Created
July 20, 2023 16:05
-
-
Save outfrost/5e0c73684bc9f739b44ec3080ba48874 to your computer and use it in GitHub Desktop.
Some garbage to test out tournament bracket ideas
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::{collections::BTreeMap, mem}; | |
use rand::prelude::*; | |
const BIT_INDEX_DEF: [((u32, u32), u32); 28] = [ | |
((0, 1), 0), | |
((0, 2), 1), | |
((0, 3), 2), | |
((0, 4), 3), | |
((0, 5), 4), | |
((0, 6), 5), | |
((0, 7), 6), | |
((1, 2), 7), | |
((1, 3), 8), | |
((1, 4), 9), | |
((1, 5), 10), | |
((1, 6), 11), | |
((1, 7), 12), | |
((2, 3), 13), | |
((2, 4), 14), | |
((2, 5), 15), | |
((2, 6), 16), | |
((2, 7), 17), | |
((3, 4), 18), | |
((3, 5), 19), | |
((3, 6), 20), | |
((3, 7), 21), | |
((4, 5), 22), | |
((4, 6), 23), | |
((4, 7), 24), | |
((5, 6), 25), | |
((5, 7), 26), | |
((6, 7), 27), | |
]; | |
struct Determiner<'a> { | |
seed: u32, | |
bit_index: &'a BTreeMap<(u32, u32), u32>, | |
} | |
impl<'a> Determiner<'a> { | |
fn new(seed: u32, bit_index: &'a BTreeMap<(u32, u32), u32>) -> Self { | |
Self { | |
seed, | |
bit_index, | |
} | |
} | |
fn wins(&self, team_a: u32, team_b: u32) -> bool { | |
let mut a = team_a - 1; | |
let mut b = team_b - 1; | |
let mut swap = false; | |
if a > b { | |
mem::swap(&mut a, &mut b); | |
swap = true; | |
} | |
//let f_a = a as f32; | |
//let bit_index = b - 1 + ((6.5 * f_a) - (0.5 * f_a * f_a)) as u32; | |
//println!("bit_index: {}", bit_index); | |
(self.seed & 1 << self.bit_index[&(a, b)] != 0) ^ swap | |
} | |
fn winner(&self, pair: (u32, u32)) -> u32 { | |
if self.wins(pair.0, pair.1) { pair.0 } else { pair.1 } | |
} | |
fn loser(&self, pair: (u32, u32)) -> u32 { | |
if self.wins(pair.0, pair.1) { pair.1 } else { pair.0 } | |
} | |
fn superiority(&self, team: u32) -> u32 { | |
let mut result = 0u32; | |
for other in 1..=8 { | |
if team == other { continue; } | |
if self.wins(team, other) { result += 1; /*println!("wins against {}", other);*/ } | |
} | |
result | |
} | |
} | |
fn main() { | |
// let det = Determiner(u32::MAX); | |
// println!("{} {} against {}", 1, if det.wins(1, 4) { "wins" } else { "loses" }, 4); | |
// println!("{} {} against {}", 3, if det.wins(3, 7) { "wins" } else { "loses" }, 7); | |
// println!("{} {} against {}", 6, if det.wins(6, 8) { "wins" } else { "loses" }, 8); | |
// println!("{} {} against {}", 5, if det.wins(5, 2) { "wins" } else { "loses" }, 2); | |
let mut samples = 0usize; | |
let mut bracket_total_diff = 0u64; | |
let mut bracket_total_rematches = 0u64; | |
let mut bracket_rematches_by_round = [0u64; 6]; | |
let bit_index = BTreeMap::from(BIT_INDEX_DEF); | |
let mut rng = thread_rng(); | |
// seed pattern to account for team 1, 2, 3 always winning against 4, 5, 6, 7, 8 | |
// XXXX XXXXXX 11 111 11111 X 11111 XX | |
for det in (0u32..0x2000u32) | |
.map(|seed| (seed & 0b11u32) | (seed & 0b100u32) << 5 | (seed & 0xFFFFFFF8u32) << 15 | 0b111111111101111100) | |
.map(|seed| Determiner::new(seed, &bit_index)) | |
{ | |
// for det in (0x0FFFFFFFu32..0x10000000u32).map(|seed| { Determiner::new(seed) }) { | |
// if rng.gen::<f32>() < 0.75 { continue; } | |
let mut ranking = [1u32, 2, 3, 4, 5, 6, 7, 8]; | |
ranking.sort_by(|a, b| { det.superiority(*b).cmp(&det.superiority(*a)) /* numerically reverse */ }); | |
let rank_lookup: BTreeMap<u32, i32> = ranking.iter().enumerate().map(|(i, team)| (*team, i as i32)).collect(); | |
let round_1 = [(1, 5), (2, 6), (3, 7), (4, 8)]; | |
let round_2 = [ | |
(det.winner(round_1[0]), det.winner(round_1[1])), | |
(det.loser(round_1[0]), det.loser(round_1[1])), | |
(det.winner(round_1[2]), det.winner(round_1[3])), | |
(det.loser(round_1[2]), det.loser(round_1[3])), | |
]; | |
let round_3 = [ | |
(det.winner(round_2[0]), det.winner(round_2[3])), | |
(det.winner(round_2[1]), det.winner(round_2[2])), | |
(det.loser(round_2[1]), det.loser(round_2[2])), | |
(det.loser(round_2[0]), det.loser(round_2[3])), | |
]; | |
let round_4 = [ | |
(det.winner(round_3[0]), det.winner(round_3[2])), | |
(det.winner(round_3[1]), det.winner(round_3[3])), | |
(det.loser(round_3[0]), det.loser(round_3[2])), | |
(det.loser(round_3[1]), det.loser(round_3[3])), | |
]; | |
let round_5 = [ | |
(det.winner(round_4[0]), det.winner(round_4[1])), | |
(det.loser(round_4[0]), det.loser(round_4[1])), | |
(det.winner(round_4[2]), det.winner(round_4[3])), | |
(det.loser(round_4[2]), det.loser(round_4[3])), | |
]; | |
let round_6 = [ | |
(det.winner(round_5[0]), det.winner(round_5[1])), | |
(det.loser(round_5[0]), det.winner(round_5[2])), | |
(det.loser(round_5[1]), det.winner(round_5[3])), | |
(det.loser(round_5[2]), det.loser(round_5[3])), | |
]; | |
let all_matches = [round_1, round_2, round_3, round_4, round_5, round_6].concat(); | |
let mut total_diff = 0u32; | |
let mut rematches = BTreeMap::<(u32, u32), u32>::new(); | |
let mut rematches_by_round = [0u32; 6]; | |
for (i, pair) in all_matches.iter().enumerate() { | |
total_diff += (rank_lookup[&pair.0] - rank_lookup[&pair.1]).abs() as u32; | |
let ord_pair = if pair.0 < pair.1 { *pair } else { (pair.1, pair.0) }; | |
if let Some(_) = rematches.get(&ord_pair) { | |
rematches_by_round[i / 4] += 1; | |
} | |
rematches.entry(ord_pair).and_modify(|count| *count += 1).or_insert(1); | |
} | |
bracket_total_diff += total_diff as u64; | |
bracket_total_rematches += rematches.values().fold(0, |acc, v| acc + std::cmp::max(v - 1, 0)) as u64; | |
for (i, tally) in bracket_rematches_by_round.iter_mut().enumerate() { | |
*tally += rematches_by_round[i] as u64; | |
} | |
samples += 1; | |
} | |
let avg_total_diff: f32 = bracket_total_diff as f32 / samples as f32; | |
let avg_rematches: f32 = bracket_total_rematches as f32 / samples as f32; | |
let avg_rematches_by_round: [f32; 6] = bracket_rematches_by_round.iter().map(|v| *v as f32 / samples as f32).collect::<Vec<f32>>().try_into().unwrap(); | |
println!("in {} samples:", samples); | |
println!("{} average accumulated rank difference", avg_total_diff); | |
println!("{} average rematches", avg_rematches); | |
println!("average rematches by round: {:?}", avg_rematches_by_round); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment