1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
use num::rational::BigRational;
use std::collections::HashSet;
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)]
pub struct CandidateIndex(pub u8);
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
pub struct GroupIndex(pub u8);
#[derive(Debug)]
pub struct BallotState {
pub form: Vec<CandidateIndex>,
pub count: u32,
pub active_preference: usize,
}
pub struct CountResults {
elected: Vec<CandidateIndex>,
excluded: Vec<CandidateIndex>,
inactive: HashSet<CandidateIndex>,
}
impl CountResults {
pub fn new() -> CountResults {
CountResults {
elected: Vec::new(),
excluded: Vec::new(),
inactive: HashSet::new(),
}
}
pub fn number_elected(&self) -> u32 {
self.elected.len() as u32
}
pub fn get_elected(&self) -> &Vec<CandidateIndex> {
&self.elected
}
pub fn get_excluded(&self) -> &Vec<CandidateIndex> {
&self.excluded
}
pub fn candidate_elected(&mut self, candidate: CandidateIndex) {
self.elected.push(candidate);
self.inactive.insert(candidate);
}
pub fn candidate_excluded(&mut self, candidate: CandidateIndex) {
self.excluded.push(candidate);
self.inactive.insert(candidate);
}
pub fn candidate_is_inactive(&self, candidate: &CandidateIndex) -> bool {
self.inactive.contains(&candidate)
}
}
impl BallotState {
pub fn alive(&self) -> bool {
self.active_preference < self.form.len()
}
pub fn current_preference(&self) -> Option<CandidateIndex> {
if self.alive() {
Some(self.form[self.active_preference])
} else {
None
}
}
pub fn to_next_preference(&mut self, results: &CountResults) {
loop {
self.active_preference += 1;
match self.current_preference() {
Some(candidate) => {
if !results.candidate_is_inactive(&candidate) {
break;
}
}
None => {
break;
}
}
}
}
}
pub struct BundleTransaction {
pub ballot_states: Vec<BallotState>,
pub transfer_value: BigRational,
pub votes: u32,
pub papers: u32,
}
pub struct CandidateData {
pub count: usize,
pub names: Vec<String>,
pub parties: Vec<String>,
pub tickets: Vec<Vec<CandidateIndex>>,
}
impl CandidateData {
pub fn vec_names(&self, candidates: &Vec<CandidateIndex>) -> String {
let names: Vec<String> = candidates.iter().map(|c| self.get_name(*c)).collect();
names.join("; ")
}
}
impl CandidateData {
pub fn get_name(&self, idx: CandidateIndex) -> String {
return self.names[idx.0 as usize].clone();
}
pub fn get_party(&self, idx: CandidateIndex) -> String {
return self.parties[idx.0 as usize].clone();
}
}