125 lines
3.4 KiB
Rust
125 lines
3.4 KiB
Rust
|
/* OpenTally: Open-source election vote counting
|
||
|
* Copyright © 2021 Lee Yingtong Li (RunasSudo)
|
||
|
*
|
||
|
* This program is free software: you can redistribute it and/or modify
|
||
|
* it under the terms of the GNU Affero General Public License as published by
|
||
|
* the Free Software Foundation, either version 3 of the License, or
|
||
|
* (at your option) any later version.
|
||
|
*
|
||
|
* This program is distributed in the hope that it will be useful,
|
||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
* GNU Affero General Public License for more details.
|
||
|
*
|
||
|
* You should have received a copy of the GNU Affero General Public License
|
||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||
|
*/
|
||
|
|
||
|
use crate::election::Candidate;
|
||
|
use crate::stv::STVError;
|
||
|
|
||
|
#[allow(unused_imports)]
|
||
|
use wasm_bindgen::prelude::wasm_bindgen;
|
||
|
|
||
|
#[allow(unused_imports)]
|
||
|
use std::io::{stdin, stdout, Write};
|
||
|
|
||
|
pub enum TieStrategy<'s> {
|
||
|
Forwards,
|
||
|
Backwards,
|
||
|
Random(&'s str),
|
||
|
Prompt,
|
||
|
}
|
||
|
|
||
|
impl<'s> TieStrategy<'s> {
|
||
|
pub fn choose_highest<'c>(&self, candidates: Vec<&'c Candidate>) -> Result<&'c Candidate, STVError> {
|
||
|
match self {
|
||
|
Self::Forwards => { todo!() }
|
||
|
Self::Backwards => { todo!() }
|
||
|
Self::Random(_seed) => { todo!() }
|
||
|
Self::Prompt => {
|
||
|
return prompt(candidates);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pub fn choose_lowest<'c>(&self, candidates: Vec<&'c Candidate>) -> Result<&'c Candidate, STVError> {
|
||
|
match self {
|
||
|
Self::Forwards => { todo!() }
|
||
|
Self::Backwards => { todo!() }
|
||
|
Self::Random(_seed) => {
|
||
|
return self.choose_highest(candidates);
|
||
|
}
|
||
|
Self::Prompt => {
|
||
|
return self.choose_highest(candidates);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#[cfg(not(target_arch = "wasm32"))]
|
||
|
fn prompt<'c>(candidates: Vec<&'c Candidate>) -> Result<&'c Candidate, STVError> {
|
||
|
println!("Multiple tied candidates:");
|
||
|
for (i, candidate) in candidates.iter().enumerate() {
|
||
|
println!("{}. {}", i + 1, candidate.name);
|
||
|
}
|
||
|
let mut buffer = String::new();
|
||
|
loop {
|
||
|
print!("Which candidate to select? [1-{}] ", candidates.len());
|
||
|
stdout().flush().expect("IO Error");
|
||
|
stdin().read_line(&mut buffer).expect("IO Error");
|
||
|
match buffer.trim().parse::<usize>() {
|
||
|
Ok(val) => {
|
||
|
if val >= 1 && val <= candidates.len() {
|
||
|
println!();
|
||
|
return Ok(candidates[val - 1]);
|
||
|
} else {
|
||
|
println!("Invalid selection");
|
||
|
continue;
|
||
|
}
|
||
|
}
|
||
|
Err(_) => {
|
||
|
println!("Invalid selection");
|
||
|
continue;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#[cfg(target_arch = "wasm32")]
|
||
|
#[wasm_bindgen]
|
||
|
extern "C" {
|
||
|
fn read_user_input_buffer(s: &str) -> Option<String>;
|
||
|
}
|
||
|
|
||
|
#[cfg(target_arch = "wasm32")]
|
||
|
fn prompt<'c>(candidates: Vec<&'c Candidate>) -> Result<&'c Candidate, STVError> {
|
||
|
let mut message = String::from("Multiple tied candidates:\n");
|
||
|
for (i, candidate) in candidates.iter().enumerate() {
|
||
|
message.push_str(&format!("{}. {}\n", i + 1, candidate.name));
|
||
|
}
|
||
|
message.push_str(&format!("Which candidate to select? [1-{}] ", candidates.len()));
|
||
|
|
||
|
match read_user_input_buffer(&message) {
|
||
|
Some(response) => {
|
||
|
match response.trim().parse::<usize>() {
|
||
|
Ok(val) => {
|
||
|
if val >= 1 && val <= candidates.len() {
|
||
|
return Ok(candidates[val - 1]);
|
||
|
} else {
|
||
|
let _ = read_user_input_buffer(&message);
|
||
|
return Err(STVError::RequireInput);
|
||
|
}
|
||
|
}
|
||
|
Err(_) => {
|
||
|
let _ = read_user_input_buffer(&message);
|
||
|
return Err(STVError::RequireInput);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
None => {
|
||
|
return Err(STVError::RequireInput);
|
||
|
}
|
||
|
}
|
||
|
}
|