Implement randomisation of choices
This commit is contained in:
parent
db1955d628
commit
d264159237
@ -15,6 +15,7 @@
|
|||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
from eos.core.objects import *
|
from eos.core.objects import *
|
||||||
|
from eos.core.bigint import *
|
||||||
from eos.base.workflow import *
|
from eos.base.workflow import *
|
||||||
|
|
||||||
class Answer(EmbeddedObject):
|
class Answer(EmbeddedObject):
|
||||||
@ -110,11 +111,12 @@ class Result(EmbeddedObject):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
class ListChoiceQuestion(Question):
|
class ListChoiceQuestion(Question):
|
||||||
_ver = StringField(default='0.4')
|
_ver = StringField(default='0.5')
|
||||||
|
|
||||||
choices = EmbeddedObjectListField()
|
choices = EmbeddedObjectListField()
|
||||||
min_choices = IntField()
|
min_choices = IntField()
|
||||||
max_choices = IntField()
|
max_choices = IntField()
|
||||||
|
randomise_choices = BooleanField(default=False)
|
||||||
|
|
||||||
def pretty_answer(self, answer):
|
def pretty_answer(self, answer):
|
||||||
if len(answer.choices) == 0:
|
if len(answer.choices) == 0:
|
||||||
@ -137,6 +139,21 @@ class ListChoiceQuestion(Question):
|
|||||||
flat_choices.append(choice)
|
flat_choices.append(choice)
|
||||||
return flat_choices
|
return flat_choices
|
||||||
|
|
||||||
|
def randomised_choices(self):
|
||||||
|
if not self.randomise_choices:
|
||||||
|
return self.choices
|
||||||
|
else:
|
||||||
|
# Clone list
|
||||||
|
output = EosList([x for x in self.choices])
|
||||||
|
# Fisher-Yates shuffle
|
||||||
|
i = len(output)
|
||||||
|
while i != 0:
|
||||||
|
rnd = BigInt.noncrypto_random(0, i - 1)
|
||||||
|
rnd = rnd.__int__()
|
||||||
|
i -= 1
|
||||||
|
output[rnd], output[i] = output[i], output[rnd]
|
||||||
|
return output
|
||||||
|
|
||||||
class ApprovalAnswer(Answer):
|
class ApprovalAnswer(Answer):
|
||||||
choices = ListField(IntField())
|
choices = ListField(IntField())
|
||||||
|
|
||||||
|
@ -83,6 +83,7 @@ class PrimitiveField(Field):
|
|||||||
DictField = PrimitiveField
|
DictField = PrimitiveField
|
||||||
IntField = PrimitiveField
|
IntField = PrimitiveField
|
||||||
StringField = PrimitiveField
|
StringField = PrimitiveField
|
||||||
|
BooleanField = PrimitiveField
|
||||||
|
|
||||||
class EmbeddedObjectField(Field):
|
class EmbeddedObjectField(Field):
|
||||||
def __init__(self, object_type=None, *args, **kwargs):
|
def __init__(self, object_type=None, *args, **kwargs):
|
||||||
|
@ -129,7 +129,7 @@ def setup_test_election():
|
|||||||
Choice(name='Joe Bloggs', party='Independent ACME')
|
Choice(name='Joe Bloggs', party='Independent ACME')
|
||||||
]),
|
]),
|
||||||
Choice(name='John Q. Public')
|
Choice(name='John Q. Public')
|
||||||
], min_choices=0, max_choices=3)
|
], min_choices=0, max_choices=3, randomise_choices=True)
|
||||||
election.questions.append(question)
|
election.questions.append(question)
|
||||||
|
|
||||||
question = ApprovalQuestion(prompt='Chairman', choices=[Choice(name='John Doe'), Choice(name='Andrew Citizen')], min_choices=0, max_choices=1)
|
question = ApprovalQuestion(prompt='Chairman', choices=[Choice(name='John Doe'), Choice(name='Andrew Citizen')], min_choices=0, max_choices=1)
|
||||||
|
@ -22,11 +22,11 @@
|
|||||||
|
|
||||||
<div id="question-choices" class="ui form" style="margin-bottom: 1em;">
|
<div id="question-choices" class="ui form" style="margin-bottom: 1em;">
|
||||||
<div class="grouped fields">
|
<div class="grouped fields">
|
||||||
{% for choice in election.questions.__getitem__(questionNum).choices.impl %}
|
{% for choice in election.questions.__getitem__(questionNum).randomised_choices().impl %}
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<div class="ui checkbox">
|
<div class="ui checkbox">
|
||||||
<input type="checkbox" id="question-choice-{{ loop.index0 }}" onchange="choicesChanged();">
|
<input type="checkbox" id="question-choice-{{ election.questions.__getitem__(questionNum).choices.impl.indexOf(choice) }}" onchange="choicesChanged();">
|
||||||
<label for="question-choice-{{ loop.index0 }}">{{ choice.name }}{% if choice.party %} – {{ choice.party }}{% endif %}</label>
|
<label for="question-choice-{{ election.questions.__getitem__(questionNum).choices.impl.indexOf(choice) }}">{{ choice.name }}{% if choice.party %} – {{ choice.party }}{% endif %}</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
@ -58,10 +58,10 @@
|
|||||||
<div>Options not yet voted for:</div>
|
<div>Options not yet voted for:</div>
|
||||||
<div class="dragarea">
|
<div class="dragarea">
|
||||||
<div class="dragarea-hint"></div>
|
<div class="dragarea-hint"></div>
|
||||||
{% for choice in election.questions.__getitem__(questionNum).choices.impl %}
|
{% for choice in election.questions.__getitem__(questionNum).randomised_choices().impl %}
|
||||||
{% if choice.choices %}
|
{% if choice.choices %}
|
||||||
{# Ticket #}
|
{# Ticket #}
|
||||||
<div class="preferential-choice ticket" data-ticketno="{{ loop.index0 }}">
|
<div class="preferential-choice ticket">
|
||||||
<div class="number"></div>
|
<div class="number"></div>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<div class="party-name">{{ choice.name }}</div>
|
<div class="party-name">{{ choice.name }}</div>
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#}
|
#}
|
||||||
|
|
||||||
<p><small>Approval voting. Vote for between {{ question.min_choices }} and {{ question.max_choices }} choices.</small></p>
|
<p><small>Approval voting. Vote for between {{ question.min_choices }} and {{ question.max_choices }} choices.{% if question.randomise_choices %} Order of choices is randomised.{% endif %}</small></p>
|
||||||
|
|
||||||
<ul class="ui list">
|
<ul class="ui list">
|
||||||
{% for choice in question.choices %}
|
{% for choice in question.choices %}
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#}
|
#}
|
||||||
|
|
||||||
<p><small>Preferential voting. Vote for between {{ question.min_choices }} and {{ question.max_choices }} choices.</small></p>
|
<p><small>Preferential voting. Vote for between {{ question.min_choices }} and {{ question.max_choices }} choices.{% if question.randomise_choices %} Order of choices is randomised.{% endif %}</small></p>
|
||||||
|
|
||||||
<ul class="ui list">
|
<ul class="ui list">
|
||||||
{% for choice in question.choices %}
|
{% for choice in question.choices %}
|
||||||
|
Loading…
Reference in New Issue
Block a user