Implement forwards/backwards tie-breaking in web UI

This commit is contained in:
RunasSudo 2021-06-13 00:39:49 +10:00
parent 2dc5ed963b
commit daeb706b44
Signed by: RunasSudo
GPG Key ID: 7234E476BF21C61A
5 changed files with 63 additions and 19 deletions

View File

@ -114,25 +114,25 @@
</select> </select>
</label> </label>
</div> </div>
<!--<div class="subheading"> <div class="subheading">
Tie-breaking: Tie-breaking:
</div> </div>
<div> <div>
<label> <label>
Ties: Ties:
<select id="selTies"> <select id="selTies">
<option value="backwards_random" selected>Backwards then random</option> <option value="backwards,random" selected>Backwards then random</option>
<option value="forwards_random">Forwards then random</option> <option value="forwards,random">Forwards then random</option>
<option value="random">Random</option> <option value="random">Random</option>
<option value="prompt">Prompt</option> <option value="prompt">Prompt</option>
</select> </select>
</label> </label>
<label> <!--<label>
Random seed: Random seed:
<input type="text" id="txtSeed" value=""> <input type="text" id="txtSeed" value="">
</label> </label>-->
</div> </div>
<div class="subheading"> <!--<div class="subheading">
Constraints: Constraints:
</div> </div>
<div> <div>

View File

@ -107,6 +107,7 @@ async function clickCount() {
document.getElementById('selQuota').value, document.getElementById('selQuota').value,
document.getElementById('selQuotaCriterion').value, document.getElementById('selQuotaCriterion').value,
document.getElementById('selQuotaMode').value, document.getElementById('selQuotaMode').value,
document.getElementById('selTies').value.split(','),
document.getElementById('selTransfers').value, document.getElementById('selTransfers').value,
document.getElementById('selSurplus').value, document.getElementById('selSurplus').value,
document.getElementById('selPapers').value == 'transferable', document.getElementById('selPapers').value == 'transferable',
@ -320,7 +321,7 @@ function changePreset() {
document.getElementById('selTransfers').value = 'wig'; document.getElementById('selTransfers').value = 'wig';
document.getElementById('selPapers').value = 'both'; document.getElementById('selPapers').value = 'both';
document.getElementById('selExclusion').value = 'single_stage'; document.getElementById('selExclusion').value = 'single_stage';
//document.getElementById('selTies').value = 'backwards_random'; document.getElementById('selTies').value = 'backwards,random';
} else if (document.getElementById('selPreset').value === 'scottish') { } else if (document.getElementById('selPreset').value === 'scottish') {
document.getElementById('selQuotaCriterion').value = 'geq'; document.getElementById('selQuotaCriterion').value = 'geq';
document.getElementById('selQuota').value = 'droop'; document.getElementById('selQuota').value = 'droop';
@ -343,7 +344,7 @@ function changePreset() {
document.getElementById('selTransfers').value = 'wig'; document.getElementById('selTransfers').value = 'wig';
document.getElementById('selPapers').value = 'both'; document.getElementById('selPapers').value = 'both';
document.getElementById('selExclusion').value = 'single_stage'; document.getElementById('selExclusion').value = 'single_stage';
//document.getElementById('selTies').value = 'backwards_random'; document.getElementById('selTies').value = 'backwards,random';
} else if (document.getElementById('selPreset').value === 'senate') { } else if (document.getElementById('selPreset').value === 'senate') {
document.getElementById('selQuotaCriterion').value = 'geq'; document.getElementById('selQuotaCriterion').value = 'geq';
document.getElementById('selQuota').value = 'droop'; document.getElementById('selQuota').value = 'droop';
@ -366,7 +367,7 @@ function changePreset() {
document.getElementById('selTransfers').value = 'uig'; document.getElementById('selTransfers').value = 'uig';
document.getElementById('selPapers').value = 'both'; document.getElementById('selPapers').value = 'both';
document.getElementById('selExclusion').value = 'by_value'; document.getElementById('selExclusion').value = 'by_value';
//document.getElementById('selTies').value = 'backwards_random'; document.getElementById('selTies').value = 'backwards,random';
} else if (document.getElementById('selPreset').value === 'prsa77') { } else if (document.getElementById('selPreset').value === 'prsa77') {
document.getElementById('selQuotaCriterion').value = 'geq'; document.getElementById('selQuotaCriterion').value = 'geq';
document.getElementById('selQuota').value = 'droop'; document.getElementById('selQuota').value = 'droop';
@ -391,7 +392,7 @@ function changePreset() {
document.getElementById('selTransfers').value = 'eg'; document.getElementById('selTransfers').value = 'eg';
document.getElementById('selPapers').value = 'transferable'; document.getElementById('selPapers').value = 'transferable';
document.getElementById('selExclusion').value = 'parcels_by_order'; document.getElementById('selExclusion').value = 'parcels_by_order';
//document.getElementById('selTies').value = 'backwards_random'; document.getElementById('selTies').value = 'backwards,random';
} else if (document.getElementById('selPreset').value === 'ers97') { } else if (document.getElementById('selPreset').value === 'ers97') {
document.getElementById('selQuotaCriterion').value = 'geq'; document.getElementById('selQuotaCriterion').value = 'geq';
document.getElementById('selQuota').value = 'droop_exact'; document.getElementById('selQuota').value = 'droop_exact';
@ -416,6 +417,6 @@ function changePreset() {
document.getElementById('selTransfers').value = 'eg'; document.getElementById('selTransfers').value = 'eg';
document.getElementById('selPapers').value = 'transferable'; document.getElementById('selPapers').value = 'transferable';
document.getElementById('selExclusion').value = 'by_value'; document.getElementById('selExclusion').value = 'by_value';
//document.getElementById('selTies').value = 'forwards_random'; document.getElementById('selTies').value = 'forwards,random';
} }
} }

View File

@ -103,7 +103,7 @@ impl<'o> STVOptions<'o> {
ties: ties.into_iter().map(|t| match t.as_str() { ties: ties.into_iter().map(|t| match t.as_str() {
"forwards" => TieStrategy::Forwards, "forwards" => TieStrategy::Forwards,
"backwards" => TieStrategy::Backwards, "backwards" => TieStrategy::Backwards,
"random" => todo!(), "random" => TieStrategy::Random(&"TODO"),
"prompt" => TieStrategy::Prompt, "prompt" => TieStrategy::Prompt,
_ => panic!("Invalid --ties"), _ => panic!("Invalid --ties"),
}).collect(), }).collect(),

View File

@ -55,13 +55,13 @@ macro_rules! impl_type {
#[wasm_bindgen] #[wasm_bindgen]
#[allow(non_snake_case)] #[allow(non_snake_case)]
pub fn [<count_init_$type>](state: &mut [<CountState$type>], opts: &STVOptionsWrapper) { pub fn [<count_init_$type>](state: &mut [<CountState$type>], opts: &STVOptions) {
stv::count_init(&mut state.0, &opts.0); stv::count_init(&mut state.0, &opts.0);
} }
#[wasm_bindgen] #[wasm_bindgen]
#[allow(non_snake_case)] #[allow(non_snake_case)]
pub fn [<count_one_stage_$type>](state: &mut [<CountState$type>], opts: &STVOptionsWrapper) -> Result<bool, JsValue> { pub fn [<count_one_stage_$type>](state: &mut [<CountState$type>], opts: &STVOptions) -> Result<bool, JsValue> {
match stv::count_one_stage(&mut state.0, &opts.0) { match stv::count_one_stage(&mut state.0, &opts.0) {
Ok(v) => Ok(v), Ok(v) => Ok(v),
Err(stv::STVError::RequireInput) => Err("RequireInput".into()), Err(stv::STVError::RequireInput) => Err("RequireInput".into()),
@ -73,19 +73,19 @@ macro_rules! impl_type {
#[wasm_bindgen] #[wasm_bindgen]
#[allow(non_snake_case)] #[allow(non_snake_case)]
pub fn [<init_results_table_$type>](election: &[<Election$type>], opts: &STVOptionsWrapper) -> String { pub fn [<init_results_table_$type>](election: &[<Election$type>], opts: &STVOptions) -> String {
return init_results_table(&election.0, &opts.0); return init_results_table(&election.0, &opts.0);
} }
#[wasm_bindgen] #[wasm_bindgen]
#[allow(non_snake_case)] #[allow(non_snake_case)]
pub fn [<describe_count_$type>](filename: String, election: &[<Election$type>], opts: &STVOptionsWrapper) -> String { pub fn [<describe_count_$type>](filename: String, election: &[<Election$type>], opts: &STVOptions) -> String {
return describe_count(filename, &election.0, &opts.0); return describe_count(filename, &election.0, &opts.0);
} }
#[wasm_bindgen] #[wasm_bindgen]
#[allow(non_snake_case)] #[allow(non_snake_case)]
pub fn [<update_results_table_$type>](stage_num: usize, state: &[<CountState$type>], opts: &STVOptionsWrapper) -> Array { pub fn [<update_results_table_$type>](stage_num: usize, state: &[<CountState$type>], opts: &STVOptions) -> Array {
return update_results_table(stage_num, &state.0, &opts.0); return update_results_table(stage_num, &state.0, &opts.0);
} }
@ -141,7 +141,50 @@ impl_type!(NativeFloat64);
impl_type!(Rational); impl_type!(Rational);
#[wasm_bindgen] #[wasm_bindgen]
pub struct STVOptionsWrapper(stv::STVOptions<'static>); pub struct STVOptions(stv::STVOptions<'static>);
#[wasm_bindgen]
impl STVOptions {
pub fn new(
round_tvs: Option<usize>,
round_weights: Option<usize>,
round_votes: Option<usize>,
round_quota: Option<usize>,
sum_surplus_transfers: &str,
normalise_ballots: bool,
quota: &str,
quota_criterion: &str,
quota_mode: &str,
ties: Array,
surplus: &str,
surplus_order: &str,
transferable_only: bool,
exclusion: &str,
bulk_exclude: bool,
defer_surpluses: bool,
pp_decimals: usize,
) -> Self {
Self(stv::STVOptions::new(
round_tvs,
round_weights,
round_votes,
round_quota,
sum_surplus_transfers,
normalise_ballots,
quota,
quota_criterion,
quota_mode,
&ties.iter().map(|v| v.as_string().unwrap()).collect(),
surplus,
surplus_order,
transferable_only,
exclusion,
bulk_exclude,
defer_surpluses,
pp_decimals,
))
}
}
// Reporting // Reporting

View File

@ -38,7 +38,7 @@ impl<'s> TieStrategy<'s> {
match self { match self {
Self::Forwards => "forwards", Self::Forwards => "forwards",
Self::Backwards => "backwards", Self::Backwards => "backwards",
Self::Random(_) => todo!(), Self::Random(_) => "random",
Self::Prompt => "prompt", Self::Prompt => "prompt",
}.to_string() }.to_string()
} }