From 8cc694e6094e44df87224f0a9f187c68f758912f Mon Sep 17 00:00:00 2001 From: RunasSudo Date: Thu, 21 Apr 2022 21:56:21 +1000 Subject: [PATCH] Cosmetic improvements Hide transfers column in transposed report if no transfers Report "Rollback complete" at end of stage when completed --- src/constraints.rs | 63 ++++++++++++++++++++++++++++++++++++++++------ src/stv/mod.rs | 3 ++- src/stv/wasm.rs | 2 ++ 3 files changed, 60 insertions(+), 8 deletions(-) diff --git a/src/constraints.rs b/src/constraints.rs index 4232e8f..6893e6d 100644 --- a/src/constraints.rs +++ b/src/constraints.rs @@ -794,7 +794,7 @@ pub fn init_repeat_count_rollback<'a, N: Number>(state: &mut CountState<'a, N>, } /// Process one stage of rollback for [ConstraintMode::TwoStage] -pub fn rollback_one_stage(state: &mut CountState, opts: &STVOptions) -> Result +pub fn rollback_one_stage(state: &mut CountState, opts: &STVOptions) -> Result<(), STVError> where for<'r> &'r N: ops::Add<&'r N, Output=N>, for<'r> &'r N: ops::Sub<&'r N, Output=N>, @@ -854,7 +854,7 @@ where ); state.rollback_state = RollbackState::RollingBack { candidates: Some(candidates), exhausted: exhausted.take(), candidate_distributing: None, constraint: Some(constraint), group: Some(group) }; - return Ok(true); + return Ok(()); } if let RollbackState::RollingBack { candidates, exhausted, candidate_distributing, constraint, group } = &mut state.rollback_state { @@ -904,7 +904,8 @@ where } state.rollback_state = RollbackState::RollingBack { candidates: Some(candidates), exhausted: Some(exhausted), candidate_distributing, constraint: Some(constraint), group: Some(group) }; - return Ok(true); + rollback_check_complete(state); + return Ok(()); } // ---------------------------------- @@ -933,7 +934,8 @@ where exhausted.parcels.append(&mut dummy_count_card.parcels); state.rollback_state = RollbackState::RollingBack { candidates: Some(candidates), exhausted: Some(exhausted), candidate_distributing: None, constraint: Some(constraint), group: Some(group) }; - return Ok(true); + rollback_check_complete(state); + return Ok(()); } // ------------------------------------------ @@ -989,7 +991,8 @@ where stv::exclude_candidates(state, opts, vec![dummy_candidate], "Distribution")?; state.rollback_state = RollbackState::RollingBack { candidates: Some(candidates), exhausted: Some(exhausted), candidate_distributing: Some(candidate_distributing), constraint: Some(constraint), group: Some(group) }; - return Ok(true); + rollback_check_complete(state); + return Ok(()); } // -------------------------------------------- @@ -1045,7 +1048,53 @@ where stv::exclude_candidates(state, opts, vec![dummy_candidate], "Distribution")?; state.rollback_state = RollbackState::RollingBack { candidates: Some(candidates), exhausted: Some(exhausted), candidate_distributing: Some(candidate_distributing), constraint: Some(constraint), group: Some(group) }; - return Ok(true); + rollback_check_complete(state); + return Ok(()); + } + } + + unreachable!(); +} + +fn rollback_check_complete(state: &mut CountState) { + if let RollbackState::RollingBack { candidates, exhausted, candidate_distributing: _, constraint: _, group: _ } = &state.rollback_state { + let candidates = candidates.as_ref().unwrap(); + let exhausted = exhausted.as_ref().unwrap(); + + let has_surplus: Vec<&Candidate> = state.election.candidates.iter() // Present in order in case of tie + .filter(|c| { + let cc = &candidates[c]; + if !c.is_dummy && cc.state == CandidateState::Elected && !cc.finalised { + let dummy_candidate = state.election.candidates.iter().find(|x| x.name == c.name && x.is_dummy).unwrap(); + !state.candidates[dummy_candidate].finalised + } else { + false + } + }) + .collect(); + + if !has_surplus.is_empty() { + return; + } + + if exhausted.parcels.iter().any(|p| !p.votes.is_empty()) { + return; + } + + let continuing_candidates: Vec<&Candidate> = state.election.candidates.iter() + .filter(|c| { + let cc = &candidates[c]; + if !c.is_dummy && !cc.finalised { + let dummy_candidate = state.election.candidates.iter().find(|x| x.name == c.name && x.is_dummy).unwrap(); + !state.candidates[dummy_candidate].finalised + } else { + false + } + }) + .collect(); + + if !continuing_candidates.is_empty() { + return; } // --------------------------- @@ -1065,7 +1114,7 @@ where state.rollback_state = RollbackState::Normal; state.num_excluded = state.candidates.values().filter(|cc| cc.state == CandidateState::Excluded).count(); - return Ok(false); + return; } unreachable!(); diff --git a/src/stv/mod.rs b/src/stv/mod.rs index b7ab227..26df742 100644 --- a/src/stv/mod.rs +++ b/src/stv/mod.rs @@ -670,7 +670,8 @@ where } if let RollbackState::Normal = state.rollback_state { - } else if constraints::rollback_one_stage(state, opts)? { + } else { + constraints::rollback_one_stage(state, opts)?; elect_hopefuls(state, opts, true)?; update_tiebreaks(state, opts); return Ok(false); diff --git a/src/stv/wasm.rs b/src/stv/wasm.rs index 04f8e76..c170c51 100644 --- a/src/stv/wasm.rs +++ b/src/stv/wasm.rs @@ -406,6 +406,8 @@ pub fn update_results_table(stage_num: usize, state: &CountState, hide_xfers_trsp = true; } else if let StageKind::BulkElection = state.title { hide_xfers_trsp = true; + } else if state.candidates.values().all(|cc| cc.transfers.is_zero()) && state.exhausted.transfers.is_zero() && state.loss_fraction.transfers.is_zero() { + hide_xfers_trsp = true; } else { hide_xfers_trsp = false; }