diff --git a/html/blt/index.html b/html/blt/index.html index 3d36fc7..f0c5a33 100644 --- a/html/blt/index.html +++ b/html/blt/index.html @@ -29,7 +29,7 @@ - + Information and instructions diff --git a/html/blt/index.js b/html/blt/index.js index 68d9493..1ad023a 100644 --- a/html/blt/index.js +++ b/html/blt/index.js @@ -145,7 +145,7 @@ async function changeInpFile() { ballots = []; for (let ballot of election.ballots) { - let js_ballot = {'value': ballot.value.impl, 'preferences': []}; + let js_ballot = {'value': ballot.value.__str__(), 'preferences': []}; for (let i = 0; i < candidates.length; i++) { js_ballot['preferences'].push(''); } @@ -183,8 +183,62 @@ function clickSaveJSON() { 'ballots': ballots, }; + // Download file let url = URL.createObjectURL(new File([JSON.stringify(result)], 'ballots.json', {type: 'application/json'})); + let elA = document.createElement('a'); + elA.href = url; + elA.download = ''; + elA.click(); +} + +function clickExportBLT() { + let election = py.pyRCV2.model.Election(); + let result = window.prompt('Enter the number of seats to elect:', '1'); + if (result !== null) { + election.seats = parseInt(result); + } else { + return; + } + + result = window.prompt('Enter the name of the election:'); + if (result !== null) { + election.name = result; + } else { + return; + } + + for (let candidate of candidates) { + let py_candidate = py.pyRCV2.model.Candidate(candidate); + election.candidates.push(py_candidate); + } + + // Process ballots + for (let ballot of ballots) { + let py_ballot = py.pyRCV2.model.Ballot(py.pyRCV2.numbers.StringNum(ballot['value']), []); + + for (let i = 1; i < candidates.length + 1; i++) { + let candidate = null; + for (let j = 0; j < candidates.length; j++) { + if (ballot.preferences[j].trim() === '' + i) { + candidate = j; + break; + } + } + + if (candidate !== null) { + py_ballot.preferences.push(election.candidates[candidate]); + } else { + // No such preference + break; + } + } + + election.ballots.push(py_ballot); + } + + // Download file + let url = URL.createObjectURL(new File([py.pyRCV2.blt.writeBLT(election)], 'election.blt', {type: 'application/json'})); let elA = document.createElement('a'); elA.href = url; elA.download = ''; diff --git a/pyRCV2/blt.py b/pyRCV2/blt.py index dcad81d..399c25c 100644 --- a/pyRCV2/blt.py +++ b/pyRCV2/blt.py @@ -68,3 +68,26 @@ def readBLT(data): election.withdrawn = [election.candidates[x] for x in withdrawn] return election + +def writeBLT(election, stringify=str): + lines = [] + + lines.append('{} {}'.format(len(election.candidates), election.seats)) + + if len(election.withdrawn) > 0: + lines.append(' '.join(['-{}'.format(election.candidates.index(candidate) + 1) for candidate in election.withdrawn])) + + for ballot in election.ballots: + if ballot.preferences: + lines.append('{} {} 0'.format(stringify(ballot.value), ' '.join(str(election.candidates.index(x) + 1) for x in ballot.preferences))) + else: + lines.append('{} 0'.format(stringify(ballot.value))) + + lines.append('0') + + for candidate in election.candidates: + lines.append('"{}"'.format(candidate.name)) + + lines.append('"{}"'.format(election.name)) + + return '\n'.join(lines) diff --git a/pyRCV2/numbers/string_js.py b/pyRCV2/numbers/string_js.py index 7fd871d..1c3c756 100644 --- a/pyRCV2/numbers/string_js.py +++ b/pyRCV2/numbers/string_js.py @@ -26,3 +26,6 @@ class StringNum(BaseNum): def _to_impl(cls, value): """Implements BaseNum._to_impl""" return value + + def __str__(self): + return self.impl