Change tiebreaking prompt according to nature of tie

This commit is contained in:
RunasSudo 2021-07-31 17:51:09 +10:00
parent 32e89312fa
commit 116ff39fa5
Signed by: RunasSudo
GPG Key ID: 7234E476BF21C61A
3 changed files with 19 additions and 19 deletions

View File

@ -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]
};

View File

@ -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<N: Number>(state: &mut CountState<N>, 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<N: Number>(state: &CountState<N>) -> 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<N>, opts: &STVOptions, candidates: Vec<&'c Candidate>) -> Result<&'c Candidate, STVError> {
fn choose_highest<'c, N: Number>(state: &mut CountState<N>, 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<N>, 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<N>, opts: &STVOptions, candidates: Vec<&'c Candidate>) -> Result<&'c Candidate, STVError> {
fn choose_lowest<'c, N: Number>(state: &mut CountState<N>, 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);
}

View File

@ -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<N>, opts: &STVOptions, candidates: &Vec<&'c Candidate>) -> Result<&'c Candidate, STVError> {
pub fn choose_highest<'c, N: Number>(&self, state: &mut CountState<N>, 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<N>, opts: &STVOptions, candidates: &Vec<&'c Candidate>) -> Result<&'c Candidate, STVError> {
pub fn choose_lowest<'c, N: Number>(&self, state: &mut CountState<N>, 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<N>, opts: &STVOptions, candidates: &Vec<&'c Candidate>) -> Result<&'c Candidate, STVError> {
fn prompt<'c, N: Number>(state: &CountState<N>, 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<N>, 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::<usize>() {
@ -252,7 +252,7 @@ extern "C" {
}
#[cfg(target_arch = "wasm32")]
fn prompt<'c, N: Number>(state: &CountState<N>, opts: &STVOptions, candidates: &Vec<&'c Candidate>) -> Result<&'c Candidate, STVError> {
fn prompt<'c, N: Number>(state: &CountState<N>, 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<N>, 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);