pub mod register;
pub mod testing;
use crate::register::{Register, Identify};
use std::{error::Error, fmt};
use std::collections::HashMap;
pub struct Competitor {
pub id: u32,
pub _stats: Vec<f32>,
}
impl Competitor {
pub fn new(v: Vec<f32>) -> Self { Self { id: 0, _stats: v } }
}
impl Identify for Competitor {
fn get_id(&self) -> u32 { return self.id; }
fn set_id(&mut self, i: u32) { self.id = i; }
}
#[derive(Clone)]
pub enum MatchOutcome {
Match(u32, u32),
Position(u32),
Discard,
}
#[derive(Clone)]
pub struct Match<const N: usize> {
pub id: u32,
pub stage: Option<u32>,
pub done: bool,
pub competitors: [Option<u32>; N],
pub outcomes: [MatchOutcome; N],
}
impl<const N: usize> Identify for Match<N> {
fn get_id(&self) -> u32 { self.id }
fn set_id(&mut self, i: u32) { self.id = i; }
}
#[derive(Debug, Clone)]
pub enum StructureError {
MatchOutcomeInvalid([u32; 6]),
PositionOutcomeInvalid([u32; 4]),
InputMatchingInvalid([u32; 2]),
}
impl Error for StructureError {}
impl fmt::Display for StructureError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
StructureError::MatchOutcomeInvalid(n) => {
write!(f, "StructureError: Match Outcome was invalid: Match index {} Outcome index {} led to Match index {} Player index {} (Total Matches: {}, Total Players: {})", n[0], n[1], n[2], n[3], n[4], n[5])
},
StructureError::PositionOutcomeInvalid(n) => {
write!(f, "StructureError: Position Outcome was invalid: Match index {} Outcome index {} led to Final Position index {} (Total Positions: {})", n[0], n[1], n[2], n[3])
}
StructureError::InputMatchingInvalid(n) => {
write!(f, "StructureError: Number of Competitors and Inputs didn't match: {} Competitors, {} Inputs", n[0], n[1])
}
}
}
}
#[derive(Clone)]
pub struct Tourney<const NP: usize, const NW: usize> {
pub matches: Register<Match<NP>>,
pub positions: [Option<u32>; NW],
}
impl<const NP: usize, const NW: usize> Tourney<NP, NW>{
pub fn new() -> Self {
let matches = Register::new();
let positions = [None; NW];
Self { matches, positions }
}
pub fn add_match(&mut self, outcomes: [MatchOutcome; NP], stage: Option<u32>) -> u32 {
self.matches.insert(Match { id: 0, stage, done: false, competitors: [None; NP], outcomes })
}
pub fn get_inputs(&self) -> Result<Vec<(u32, u32)>, StructureError> {
let mut v = Vec::new();
let mut r = Vec::new();
for m in &self.matches.data {
for i in 0..NP {
v.push((m.id.clone(), i as u32));
}
for o in &m.outcomes {
match o {
MatchOutcome::Match(i, j) => { r.push((i.clone(), j.clone())); },
_ => {},
}
}
}
let v0 = v.iter().filter(|x| { !r.contains(x) }).map(|x| { *x }).collect::<Vec<_>>();
match self.validate_structure() {
Ok(()) => Ok(v0),
Err(e) => Err(e),
}
}
pub fn validate_structure(&self) -> Result<(), StructureError> {
let mut match_check = vec![false; NP*self.matches.data.len()];
let mut position_check = vec![false; NW];
for m in &self.matches.data {
let mut no = 0;
for o in &m.outcomes {
match o {
MatchOutcome::Match(i, j) => {
if *j as usize >= NP {
return Err(StructureError::MatchOutcomeInvalid(
[m.id.clone(), no, i.clone(), j.clone(), self.matches.data.len() as u32, NP as u32]
));
}
match self.matches.index.get(i) {
None => {
return Err(StructureError::MatchOutcomeInvalid(
[m.id.clone(), no, i.clone(), j.clone(), self.matches.data.len() as u32, NP as u32]
))
}
Some(_) => {
match match_check[(*i as usize)*NP + (*j as usize)] {
true => {
return Err(StructureError::MatchOutcomeInvalid(
[m.id.clone(), no, i.clone(), j.clone(), self.matches.data.len() as u32, NP as u32]
))
},
false => { match_check[(*i as usize)*NP + (*j as usize)] = true; },
}
},
}
},
MatchOutcome::Position(i) => {
match position_check.get(*i as usize) {
None => {
return Err(StructureError::PositionOutcomeInvalid(
[m.id.clone(), no, i.clone(), NW as u32]
))
},
Some(check) => {
match check {
true => {
return Err(StructureError::PositionOutcomeInvalid(
[m.id.clone(), no, i.clone(), NW as u32]
))
}
false => { position_check[*i as usize] = true; }
}
},
}
},
MatchOutcome::Discard => {},
}
no += 1;
}
}
Ok(())
}
}
pub struct TourneyInstance<'a, const NP: usize, const NW: usize> {
pub tourney: Tourney<NP, NW>,
pub competitors: &'a mut Register<Competitor>,
pub initialised: bool,
pub stages: HashMap<u32, bool>,
}
impl<'a, const NP: usize, const NW: usize> TourneyInstance<'a, NP, NW> {
pub fn new(t: &Tourney<NP, NW>, c: &'a mut Register<Competitor>) -> Self {
let tourney = t.clone();
let competitors = c;
Self { tourney, competitors, initialised: false, stages: HashMap::new() }
}
pub fn initialise(&mut self, ids: Vec<u32>) -> Result<(), StructureError> {
for m in &self.tourney.matches.data {
match m.stage {
Some(s) => { self.stages.insert(s, false); },
None => {},
}
}
let competitors = ids.iter().filter(|x| { self.competitors.get(*x).is_some() }).collect::<Vec<_>>();
match self.tourney.get_inputs() {
Err(e) => Err(e),
Ok(inp) => {
if competitors.len() != inp.len() { return Err(StructureError::InputMatchingInvalid([competitors.len() as u32, inp.len() as u32])); }
for i in 0..inp.len() {
let c = *competitors.get(i).unwrap();
let slot = *inp.get(i).unwrap();
let m = self.tourney.matches.get_mut(&slot.0).unwrap();
m.competitors[slot.1 as usize] = Some(c.clone());
}
Ok(())
}
}
}
pub fn num_spots(&self) -> usize { match self.tourney.get_inputs() { Ok(inputs) => inputs.len(), Err(e) => { eprintln!("{}", e); 0 } } }
pub fn get_active(&self) -> Vec<u32> {
let mut active = Vec::new();
for m in &self.tourney.matches.data {
if m.competitors.iter().filter(|x| { x.is_none() })
.collect::<Vec<_>>().len() == 0 && !m.done {
active.push(m.id.clone());
}
}
active
}
pub fn get_stage(&self, s: u32) -> Vec<u32> {
let mut stage = Vec::new();
for m in &self.tourney.matches.data {
match m.stage {
Some(s0) => { if s0 == s { stage.push(m.id.clone()); } }
None => {},
}
}
stage
}
pub fn stage_complete(&self, s: u32) -> bool {
let mut complete = true;
for m in &self.tourney.matches.data {
match m.stage {
Some(s0) => { if s0 == s { if !m.done { complete = false; } } },
None => {},
}
}
complete
}
pub fn step<T: TourneyRunner>(&mut self, runner: &mut T) -> bool {
let mut assignments: Vec<(u32, u32, u32)> = Vec::new();
let mut num_active = 0;
let mut completed = Vec::new();
for s in self.stages.keys() {
if self.stage_complete(s.clone()) { completed.push(s.clone()); }
}
for s in completed { self.stages.insert(s, true); }
for m in &mut self.tourney.matches.data {
let mut stage_active = true;
match m.stage {
Some(s) => { stage_active = match self.stages.get(&(s - 1)) {
Some(complete) => { if *complete { true } else { false }}
None => { true }
} },
None => {},
}
if m.competitors.iter().filter(|x| { x.is_none() })
.collect::<Vec<_>>().len() == 0 && !m.done && stage_active {
num_active += 1;
let result = runner.step::<NP>(
&m.competitors.iter().map(|x| { x.unwrap() }).collect::<Vec<_>>(),
&mut self.competitors,
);
for i in 0..NP {
let c = result[i];
let outcome = &m.outcomes[i as usize];
match outcome {
MatchOutcome::Match(m0, j) => {
assignments.push((c.clone() as u32, m0.clone(), j.clone()));
},
MatchOutcome::Position(p) => {
self.tourney.positions[*p as usize] = Some(c as u32);
},
MatchOutcome::Discard => {},
}
}
for i in 0..NP { m.competitors[i] = Some(result[i]); }
m.done = true;
}
}
for a in assignments {
self.tourney.matches.get_mut(&a.1).unwrap().competitors[a.2 as usize] = Some(a.0);
}
if num_active > 0 { return true; } else { return false; }
}
}
pub trait TourneyRunner {
fn step<const NP: usize>(&mut self, indices: &[u32], competitors: &mut Register<Competitor>) -> [u32; NP];
}