Change tiebreaking prompt according to nature of tie
This commit is contained in:
parent
32e89312fa
commit
116ff39fa5
@ -98,7 +98,7 @@ where
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
let elected_candidate = if max_cands.len() > 1 {
|
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 {
|
} else {
|
||||||
max_cands[0]
|
max_cands[0]
|
||||||
};
|
};
|
||||||
|
@ -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 {
|
while state.num_elected < state.election.seats {
|
||||||
let max_cands = ties::multiple_max_by(&hopefuls, |c| &state.candidates[c].votes);
|
let max_cands = ties::multiple_max_by(&hopefuls, |c| &state.candidates[c].votes);
|
||||||
let candidate = if max_cands.len() > 1 {
|
let candidate = if max_cands.len() > 1 {
|
||||||
choose_highest(state, opts, max_cands)?
|
choose_highest(state, opts, max_cands, "Which candidate to elect?")?
|
||||||
} else {
|
} else {
|
||||||
max_cands[0]
|
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
|
// Declare elected in descending order of votes
|
||||||
let max_cands = ties::multiple_max_by(&cands_meeting_quota, |c| &state.candidates[c].votes);
|
let max_cands = ties::multiple_max_by(&cands_meeting_quota, |c| &state.candidates[c].votes);
|
||||||
let candidate = if max_cands.len() > 1 {
|
let candidate = if max_cands.len() > 1 {
|
||||||
choose_highest(state, opts, max_cands)?
|
choose_highest(state, opts, max_cands, "Which candidate to elect?")?
|
||||||
} else {
|
} else {
|
||||||
max_cands[0]
|
max_cands[0]
|
||||||
};
|
};
|
||||||
@ -1016,7 +1016,7 @@ fn do_bulk_elect<N: Number>(state: &mut CountState<N>, opts: &STVOptions, templa
|
|||||||
while !hopefuls.is_empty() {
|
while !hopefuls.is_empty() {
|
||||||
let max_cands = ties::multiple_max_by(&hopefuls, |c| &state.candidates[c].votes);
|
let max_cands = ties::multiple_max_by(&hopefuls, |c| &state.candidates[c].votes);
|
||||||
let candidate = if max_cands.len() > 1 {
|
let candidate = if max_cands.len() > 1 {
|
||||||
choose_highest(state, opts, max_cands)?
|
choose_highest(state, opts, max_cands, "Which candidate to elect?")?
|
||||||
} else {
|
} else {
|
||||||
max_cands[0]
|
max_cands[0]
|
||||||
};
|
};
|
||||||
@ -1077,7 +1077,7 @@ where
|
|||||||
// Exclude only the lowest-ranked doomed candidate
|
// Exclude only the lowest-ranked doomed candidate
|
||||||
let min_cands = ties::multiple_min_by(&doomed, |c| &state.candidates[c].votes);
|
let min_cands = ties::multiple_min_by(&doomed, |c| &state.candidates[c].votes);
|
||||||
excluded_candidates = if min_cands.len() > 1 {
|
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 {
|
} else {
|
||||||
vec![min_cands[0]]
|
vec![min_cands[0]]
|
||||||
};
|
};
|
||||||
@ -1179,7 +1179,7 @@ where
|
|||||||
|
|
||||||
let min_cands = ties::multiple_min_by(&hopefuls, |c| &state.candidates[c].votes);
|
let min_cands = ties::multiple_min_by(&hopefuls, |c| &state.candidates[c].votes);
|
||||||
excluded_candidates = if min_cands.len() > 1 {
|
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 {
|
} else {
|
||||||
vec![min_cands[0]]
|
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
|
/// 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
|
/// 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() {
|
for strategy in opts.ties.iter() {
|
||||||
match strategy.choose_highest(state, opts, &candidates) {
|
match strategy.choose_highest(state, opts, &candidates, prompt_text) {
|
||||||
Ok(c) => {
|
Ok(c) => {
|
||||||
return 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
|
/// 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
|
/// 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() {
|
for strategy in opts.ties.iter() {
|
||||||
match strategy.choose_lowest(state, opts, &candidates) {
|
match strategy.choose_lowest(state, opts, &candidates, prompt_text) {
|
||||||
Ok(c) => {
|
Ok(c) => {
|
||||||
return Ok(c);
|
return Ok(c);
|
||||||
}
|
}
|
||||||
|
18
src/ties.rs
18
src/ties.rs
@ -53,7 +53,7 @@ impl TieStrategy {
|
|||||||
/// Break a tie between the given candidates, selecting the highest candidate
|
/// Break a tie between the given candidates, selecting the highest candidate
|
||||||
///
|
///
|
||||||
/// The given candidates are assumed to be tied in this round
|
/// 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 {
|
match self {
|
||||||
Self::Forwards => {
|
Self::Forwards => {
|
||||||
let mut candidates = candidates.clone();
|
let mut candidates = candidates.clone();
|
||||||
@ -87,7 +87,7 @@ impl TieStrategy {
|
|||||||
return Ok(candidates[state.random.as_mut().unwrap().next(candidates.len())]);
|
return Ok(candidates[state.random.as_mut().unwrap().next(candidates.len())]);
|
||||||
}
|
}
|
||||||
Self::Prompt => {
|
Self::Prompt => {
|
||||||
match prompt(state, opts, candidates) {
|
match prompt(state, opts, candidates, prompt_text) {
|
||||||
Ok(c) => {
|
Ok(c) => {
|
||||||
state.logger.log_literal(format!("Tie between {} broken by manual intervention.", smart_join(&candidates.iter().map(|c| c.name.as_str()).collect())));
|
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);
|
return Ok(c);
|
||||||
@ -101,7 +101,7 @@ impl TieStrategy {
|
|||||||
/// Break a tie between the given candidates, selecting the lowest candidate
|
/// Break a tie between the given candidates, selecting the lowest candidate
|
||||||
///
|
///
|
||||||
/// The given candidates are assumed to be tied in this round
|
/// 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 {
|
match self {
|
||||||
Self::Forwards => {
|
Self::Forwards => {
|
||||||
let mut candidates = candidates.clone();
|
let mut candidates = candidates.clone();
|
||||||
@ -130,10 +130,10 @@ impl TieStrategy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Self::Random(_seed) => {
|
Self::Random(_seed) => {
|
||||||
return self.choose_highest(state, opts, candidates);
|
return self.choose_highest(state, opts, candidates, prompt_text);
|
||||||
}
|
}
|
||||||
Self::Prompt => {
|
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
|
/// Prompt the candidate for input, depending on CLI or WebAssembly target
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[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
|
// Show intrastage progress if required
|
||||||
if !state.logger.entries.is_empty() {
|
if !state.logger.entries.is_empty() {
|
||||||
// Print stage details
|
// Print stage details
|
||||||
@ -224,7 +224,7 @@ fn prompt<'c, N: Number>(state: &CountState<N>, opts: &STVOptions, candidates: &
|
|||||||
}
|
}
|
||||||
let mut buffer = String::new();
|
let mut buffer = String::new();
|
||||||
loop {
|
loop {
|
||||||
print!("Which candidate to select? [1-{}] ", candidates.len());
|
print!("{} [1-{}] ", prompt_text, candidates.len());
|
||||||
stdout().flush().expect("IO Error");
|
stdout().flush().expect("IO Error");
|
||||||
stdin().read_line(&mut buffer).expect("IO Error");
|
stdin().read_line(&mut buffer).expect("IO Error");
|
||||||
match buffer.trim().parse::<usize>() {
|
match buffer.trim().parse::<usize>() {
|
||||||
@ -252,7 +252,7 @@ extern "C" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_arch = "wasm32")]
|
#[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();
|
let mut message = String::new();
|
||||||
|
|
||||||
// Show intrastage progress if required
|
// 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() {
|
for (i, candidate) in candidates.iter().enumerate() {
|
||||||
message.push_str(&format!("{}. {}\n", i + 1, candidate.name));
|
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 {
|
loop {
|
||||||
let response = get_user_input(&message);
|
let response = get_user_input(&message);
|
||||||
|
Loading…
Reference in New Issue
Block a user