diff --git a/src/stv/gregory.rs b/src/stv/gregory.rs index cf6e839..f0bbc06 100644 --- a/src/stv/gregory.rs +++ b/src/stv/gregory.rs @@ -98,7 +98,7 @@ where } }; let elected_candidate = if max_cands.len() > 1 { - super::choose_highest(state, opts, max_cands)? + super::choose_highest(state, opts, max_cands, "Which candidate's surplus to distribute?")? } else { max_cands[0] }; diff --git a/src/stv/mod.rs b/src/stv/mod.rs index 794384c..d070d1a 100644 --- a/src/stv/mod.rs +++ b/src/stv/mod.rs @@ -835,7 +835,7 @@ fn elect_sure_winners<'a, N: Number>(state: &mut CountState<'a, N>, opts: &STVOp while state.num_elected < state.election.seats { let max_cands = ties::multiple_max_by(&hopefuls, |c| &state.candidates[c].votes); let candidate = if max_cands.len() > 1 { - choose_highest(state, opts, max_cands)? + choose_highest(state, opts, max_cands, "Which candidate to elect?")? } else { max_cands[0] }; @@ -879,7 +879,7 @@ fn elect_hopefuls<'a, N: Number>(state: &mut CountState<'a, N>, opts: &STVOption // Declare elected in descending order of votes let max_cands = ties::multiple_max_by(&cands_meeting_quota, |c| &state.candidates[c].votes); let candidate = if max_cands.len() > 1 { - choose_highest(state, opts, max_cands)? + choose_highest(state, opts, max_cands, "Which candidate to elect?")? } else { max_cands[0] }; @@ -1016,7 +1016,7 @@ fn do_bulk_elect(state: &mut CountState, opts: &STVOptions, templa while !hopefuls.is_empty() { let max_cands = ties::multiple_max_by(&hopefuls, |c| &state.candidates[c].votes); let candidate = if max_cands.len() > 1 { - choose_highest(state, opts, max_cands)? + choose_highest(state, opts, max_cands, "Which candidate to elect?")? } else { max_cands[0] }; @@ -1077,7 +1077,7 @@ where // Exclude only the lowest-ranked doomed candidate let min_cands = ties::multiple_min_by(&doomed, |c| &state.candidates[c].votes); excluded_candidates = if min_cands.len() > 1 { - vec![choose_lowest(state, opts, min_cands)?] + vec![choose_lowest(state, opts, min_cands, "Which candidate to exclude?")?] } else { vec![min_cands[0]] }; @@ -1179,7 +1179,7 @@ where let min_cands = ties::multiple_min_by(&hopefuls, |c| &state.candidates[c].votes); excluded_candidates = if min_cands.len() > 1 { - vec![choose_lowest(state, opts, min_cands)?] + vec![choose_lowest(state, opts, min_cands, "Which candidate to exclude?")?] } else { vec![min_cands[0]] }; @@ -1291,9 +1291,9 @@ fn finished_before_stage(state: &CountState) -> bool { /// Break a tie between the given candidates according to [STVOptions::ties], selecting the highest candidate /// /// The given candidates are assumed to be tied in this round -fn choose_highest<'c, N: Number>(state: &mut CountState, opts: &STVOptions, candidates: Vec<&'c Candidate>) -> Result<&'c Candidate, STVError> { +fn choose_highest<'c, N: Number>(state: &mut CountState, opts: &STVOptions, candidates: Vec<&'c Candidate>, prompt_text: &str) -> Result<&'c Candidate, STVError> { for strategy in opts.ties.iter() { - match strategy.choose_highest(state, opts, &candidates) { + match strategy.choose_highest(state, opts, &candidates, prompt_text) { Ok(c) => { return Ok(c); } @@ -1312,9 +1312,9 @@ fn choose_highest<'c, N: Number>(state: &mut CountState, opts: &STVOptions, c /// Break a tie between the given candidates according to [STVOptions::ties], selecting the lowest candidate /// /// The given candidates are assumed to be tied in this round -fn choose_lowest<'c, N: Number>(state: &mut CountState, opts: &STVOptions, candidates: Vec<&'c Candidate>) -> Result<&'c Candidate, STVError> { +fn choose_lowest<'c, N: Number>(state: &mut CountState, opts: &STVOptions, candidates: Vec<&'c Candidate>, prompt_text: &str) -> Result<&'c Candidate, STVError> { for strategy in opts.ties.iter() { - match strategy.choose_lowest(state, opts, &candidates) { + match strategy.choose_lowest(state, opts, &candidates, prompt_text) { Ok(c) => { return Ok(c); } diff --git a/src/ties.rs b/src/ties.rs index 8453802..2bfe0c4 100644 --- a/src/ties.rs +++ b/src/ties.rs @@ -53,7 +53,7 @@ impl TieStrategy { /// Break a tie between the given candidates, selecting the highest candidate /// /// The given candidates are assumed to be tied in this round - pub fn choose_highest<'c, N: Number>(&self, state: &mut CountState, opts: &STVOptions, candidates: &Vec<&'c Candidate>) -> Result<&'c Candidate, STVError> { + pub fn choose_highest<'c, N: Number>(&self, state: &mut CountState, opts: &STVOptions, candidates: &Vec<&'c Candidate>, prompt_text: &str) -> Result<&'c Candidate, STVError> { match self { Self::Forwards => { let mut candidates = candidates.clone(); @@ -87,7 +87,7 @@ impl TieStrategy { return Ok(candidates[state.random.as_mut().unwrap().next(candidates.len())]); } Self::Prompt => { - match prompt(state, opts, candidates) { + match prompt(state, opts, candidates, prompt_text) { Ok(c) => { state.logger.log_literal(format!("Tie between {} broken by manual intervention.", smart_join(&candidates.iter().map(|c| c.name.as_str()).collect()))); return Ok(c); @@ -101,7 +101,7 @@ impl TieStrategy { /// Break a tie between the given candidates, selecting the lowest candidate /// /// The given candidates are assumed to be tied in this round - pub fn choose_lowest<'c, N: Number>(&self, state: &mut CountState, opts: &STVOptions, candidates: &Vec<&'c Candidate>) -> Result<&'c Candidate, STVError> { + pub fn choose_lowest<'c, N: Number>(&self, state: &mut CountState, opts: &STVOptions, candidates: &Vec<&'c Candidate>, prompt_text: &str) -> Result<&'c Candidate, STVError> { match self { Self::Forwards => { let mut candidates = candidates.clone(); @@ -130,10 +130,10 @@ impl TieStrategy { } } Self::Random(_seed) => { - return self.choose_highest(state, opts, candidates); + return self.choose_highest(state, opts, candidates, prompt_text); } Self::Prompt => { - return self.choose_highest(state, opts, candidates); + return self.choose_highest(state, opts, candidates, prompt_text); } } } @@ -199,7 +199,7 @@ where /// Prompt the candidate for input, depending on CLI or WebAssembly target #[cfg(not(target_arch = "wasm32"))] -fn prompt<'c, N: Number>(state: &CountState, opts: &STVOptions, candidates: &Vec<&'c Candidate>) -> Result<&'c Candidate, STVError> { +fn prompt<'c, N: Number>(state: &CountState, opts: &STVOptions, candidates: &Vec<&'c Candidate>, prompt_text: &str) -> Result<&'c Candidate, STVError> { // Show intrastage progress if required if !state.logger.entries.is_empty() { // Print stage details @@ -224,7 +224,7 @@ fn prompt<'c, N: Number>(state: &CountState, opts: &STVOptions, candidates: & } let mut buffer = String::new(); loop { - print!("Which candidate to select? [1-{}] ", candidates.len()); + print!("{} [1-{}] ", prompt_text, candidates.len()); stdout().flush().expect("IO Error"); stdin().read_line(&mut buffer).expect("IO Error"); match buffer.trim().parse::() { @@ -252,7 +252,7 @@ extern "C" { } #[cfg(target_arch = "wasm32")] -fn prompt<'c, N: Number>(state: &CountState, opts: &STVOptions, candidates: &Vec<&'c Candidate>) -> Result<&'c Candidate, STVError> { +fn prompt<'c, N: Number>(state: &CountState, opts: &STVOptions, candidates: &Vec<&'c Candidate>, prompt_text: &str) -> Result<&'c Candidate, STVError> { let mut message = String::new(); // Show intrastage progress if required @@ -278,7 +278,7 @@ fn prompt<'c, N: Number>(state: &CountState, opts: &STVOptions, candidates: & 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())); + message.push_str(&format!("{} [1-{}] ", prompt_text, candidates.len())); loop { let response = get_user_input(&message);