From dab1a3940b5b490fea5a201b8ce9e41bf94bf9cb Mon Sep 17 00:00:00 2001 From: Mia Nordentoft Date: Wed, 12 Jun 2019 14:39:59 +0200 Subject: [PATCH] Backport changes from vocho-gui --- package-lock.json | 111 +++++++++++++++++++++++++++++----------------- package.json | 4 +- src/calc.js | 80 +++++++++++++++++++++++++++------ src/main-box.js | 5 ++- 4 files changed, 143 insertions(+), 57 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1a4d26b..5c48c32 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "vocho-term", - "version": "1.2.1", + "version": "1.2.2", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -40,7 +40,6 @@ "version": "6.10.0", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.0.tgz", "integrity": "sha512-nffhOpkymDECQyR0mnsUtoCE8RlX38G0rYP+wgLWFyZuUyuuojSSvi/+euOiQBIn63whYwYVIIH1TvE3tu4OEg==", - "dev": true, "requires": { "fast-deep-equal": "^2.0.1", "fast-json-stable-stringify": "^2.0.0", @@ -66,12 +65,11 @@ "dev": true }, "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.0.0.tgz", + "integrity": "sha512-8zjUtFJ3db/QoPXuuEMloS2AUf79/yeyttJ7Abr3hteopJu9HK8vsgGviGUMq+zyA6cZZO6gAyZoMTF6TgaEjA==", "requires": { - "color-convert": "^1.9.0" + "color-convert": "^2.0.0" } }, "argparse": { @@ -86,8 +84,7 @@ "astral-regex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", - "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", - "dev": true + "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==" }, "async": { "version": "1.0.0", @@ -232,6 +229,32 @@ "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", "supports-color": "^5.3.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + } } }, "chardet": { @@ -275,19 +298,17 @@ "dev": true }, "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.0.tgz", + "integrity": "sha512-hzTicsCJIHdxih9+2aLR1tNGZX5qSJGRHDPVwSY26tVrEf55XNajLOBWz2UuWSIergszA09/bqnOiHyqx9fxQg==", "requires": { - "color-name": "1.1.3" + "color-name": "~1.1.4" } }, "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "colors": { "version": "1.0.3", @@ -498,8 +519,7 @@ "emoji-regex": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", - "dev": true + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==" }, "entities": { "version": "1.1.2", @@ -823,14 +843,12 @@ "fast-deep-equal": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", - "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", - "dev": true + "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=" }, "fast-json-stable-stringify": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", - "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", - "dev": true + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" }, "fast-levenshtein": { "version": "2.0.6", @@ -1122,8 +1140,7 @@ "is-fullwidth-code-point": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" }, "is-promise": { "version": "2.1.0", @@ -1182,8 +1199,7 @@ "json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" }, "json-stable-stringify-without-jsonify": { "version": "1.0.1", @@ -1204,8 +1220,7 @@ "lodash": { "version": "4.17.11", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", - "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==", - "dev": true + "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" }, "longjohn": { "version": "0.2.12", @@ -1440,8 +1455,7 @@ "punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" }, "random-seed": { "version": "0.2.0", @@ -1643,11 +1657,33 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", - "dev": true, "requires": { "ansi-styles": "^3.2.0", "astral-regex": "^1.0.0", "is-fullwidth-code-point": "^2.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "requires": { + "color-convert": "^1.9.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + } } }, "source-map": { @@ -1739,7 +1775,6 @@ "version": "5.4.0", "resolved": "https://registry.npmjs.org/table/-/table-5.4.0.tgz", "integrity": "sha512-nHFDrxmbrkU7JAFKqKbDJXfzrX2UBsWmrieXFTGxiI5e4ncg3VqsZeI4EzNmX0ncp4XNGVeoxIWJXfCIXwrsvw==", - "dev": true, "requires": { "ajv": "^6.9.1", "lodash": "^4.17.11", @@ -1750,14 +1785,12 @@ "ansi-regex": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" }, "string-width": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, "requires": { "emoji-regex": "^7.0.1", "is-fullwidth-code-point": "^2.0.0", @@ -1768,7 +1801,6 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, "requires": { "ansi-regex": "^4.1.0" } @@ -1896,7 +1928,6 @@ "version": "4.2.2", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", - "dev": true, "requires": { "punycode": "^2.1.0" } @@ -1907,7 +1938,7 @@ "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" }, "vocho-lib": { - "version": "git+https://github.com/tejoesperanto/vocho-lib.git#11e6d2f0858ef64ee9ccd57c36da6559d26f6d2d", + "version": "git+https://github.com/tejoesperanto/vocho-lib.git#50b5beabda976a57bf5867330a2f393be2185417", "from": "git+https://github.com/tejoesperanto/vocho-lib.git" }, "which": { diff --git a/package.json b/package.json index b328ca6..f0fae60 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "vocho-term", - "version": "1.2.2", + "version": "1.3.0", "description": "", "main": "src/index.js", "scripts": { @@ -17,8 +17,10 @@ "eslint": "^5.16.0" }, "dependencies": { + "ansi-styles": "^4.0.0", "blessed": "git+https://github.com/CreativeCactus/blessed.git", "editor-widget": "^1.1.1", + "table": "^5.4.0", "vocho-lib": "git+https://github.com/tejoesperanto/vocho-lib.git" } } diff --git a/src/calc.js b/src/calc.js index 5f24db7..24e0dd2 100644 --- a/src/calc.js +++ b/src/calc.js @@ -1,4 +1,6 @@ const lib = require('vocho-lib'); +const table = require('table').table; +const style = require('ansi-styles'); const commaSeparatedRegex = /[^\s,]/g; @@ -15,7 +17,7 @@ module.exports = function performElection (electionType, candidatesStr, ballotsS const ballots = ballotsStr .trim() .split(/\r?\n/g) - .map(b => b.trim()) + .map(b => b.replace(/\s/g, '')) .filter(b => b.length) .map(b => { if (b === 'blanka') { b = ''; } @@ -24,26 +26,76 @@ module.exports = function performElection (electionType, candidatesStr, ballotsS global.disableDebug = true; try { + let results; + if (electionType === 'RP') { - const results = lib.RankedPairs([...candidates], ballots, ignoredCandidates, tieBreaker); + results = lib.RankedPairs([...candidates], ballots, ignoredCandidates, tieBreaker); + } else if (electionType === 'STV') { + results = lib.STV(places, [...candidates], ballots, ignoredCandidates, tieBreaker); + } + + let resultsText = `${results.ballots} balotiloj kalkulitaj, ${results.blankBallots} blanka(j)`; + + if (ignoredCandidates.length) { + resultsText += `\n\nIgnorataj kandidatoj: ${ignoredCandidates.join(', ')}`; + } - let resultsStr = `${results.ballots} balotiloj (${results.blankBallots} blanka(j))\n`; + if (electionType === 'RP') { if (results.disqualifiedCandidates.length) { - resultsStr += `Neelektitaj laŭ §2.6: ${results.disqualifiedCandidates.join(', ')}\n`; + resultsText += `\n\nNeelektitaj laŭ §2.6: ${results.disqualifiedCandidates.join(', ')}\n`; + } + + const comparedPairsTableData = [[]]; + for (let th of [ 'Paro', 'Gajnanto', 'Diferenco' ]) { + comparedPairsTableData[0].push(`${style.bold.open}${th}${style.bold.close}`); + } + + for (let [pairName, pair] of results.rankedPairs) { + const cand1 = pairName[0]; + const cand2 = pairName[1]; + + comparedPairsTableData.push([ + `${cand1} (${pair[cand1]}) kontraŭ ${cand2} (${pair[cand2]})`, + pair['winner'], + Math.abs(pair['diff']) + ]); } - resultsStr += `Venkinto: ${results.winner}`; - return resultsStr; + resultsText += '\n\nKomparitaj paroj:\n' + table(comparedPairsTableData); + + const graphTableData = [[]]; + for (let th of [ 'De', 'Al' ]) { + graphTableData[0].push(`${style.bold.open}${th}${style.bold.close}`); + } + + for (let [from, to] of Object.entries(results.graph)) { + graphTableData.push([ + from, to.join(', ') + ]); + } + + resultsText += '\n\nGrafeo:\n' + table(graphTableData); + + resultsText += `\n\nVenkinto: ${results.winner}`; } else if (electionType === 'STV') { - const results = lib.STV(places, [...candidates], ballots, ignoredCandidates, tieBreaker); - - const resultsStr = -`${results.ballots} balotiloj (${results.blankBallots} blanka(j)) -Venkintoj (laŭ ordo de elektiĝo): ${results.winners.join(', ')}`; - return resultsStr; - } else { - throw new Error(`Nekonata voĉdonsistemo ${electionType}`); + resultsText += `\nElektiĝkvoto: ${results.quota.toFixed(3)}`; + + for (let i = 0; i < results.rounds.length; i++) { + const round = results.rounds[i]; + + resultsText += `\n\n${style.bold.open}Vico ${i + 1}${style.bold.close}`; + + if (round.elected.length) { + resultsText += `\nElektitaj: ${round.elected.join(', ')}`; + } else if (round.eliminated) { + resultsText += '\nMalelektita: ' + round.eliminated; + } + } + + resultsText += '\n\nVenkintoj (laŭ ordo de elektiĝo):\n' + results.winners.join(', '); } + + return resultsText; } catch (e) { if (!e || !('type' in e)) { throw e; } switch (e.type) { diff --git a/src/main-box.js b/src/main-box.js index ab5d4ee..1bbb0ef 100644 --- a/src/main-box.js +++ b/src/main-box.js @@ -140,6 +140,7 @@ module.exports = function setUpMainBox (mainBox, prompt) { width: '50%', border: 'line', scrollable: true, + mouse: true, content: defaultResultsValue }); @@ -237,9 +238,9 @@ module.exports = function setUpMainBox (mainBox, prompt) { prompt.setLabel('Necesas egalecrompanto!'); let promptText = 'La egalecrompanto mem enskribu sian balotilon ĉi-sube.'; if (currentElectionType === 'RP') { - promptText += '\nEkz. A=B>C>D=E'; + promptText += '\nEkz. A>B>D>C'; } else if (currentElectionType === 'STV') { - promptText += '\nEkz. ABCDEF'; + promptText += '\nEkz. ABCD'; } promptText += '\nValidaj kandidatoj:\n' + e.candidates.join(', ') + '\n';