118 lines
3.1 KiB
Rust
118 lines
3.1 KiB
Rust
use time::Date;
|
|
use trueskill_tt::{History, IndexMap};
|
|
|
|
fn main() {
|
|
let mut csv = csv::Reader::open("examples/atp.csv").unwrap();
|
|
|
|
let mut composition = Vec::new();
|
|
let mut results = Vec::new();
|
|
let mut times = Vec::new();
|
|
|
|
let time_format = time::format_description::parse("[year]-[month]-[day]").unwrap();
|
|
|
|
let mut index_map = IndexMap::new();
|
|
|
|
for row in csv.records() {
|
|
if &row["double"] == "t" {
|
|
let w1_id = index_map.get_or_create(&row["w1_id"]);
|
|
let w2_id = index_map.get_or_create(&row["w2_id"]);
|
|
|
|
let l1_id = index_map.get_or_create(&row["l1_id"]);
|
|
let l2_id = index_map.get_or_create(&row["l2_id"]);
|
|
|
|
composition.push(vec![vec![w1_id, w2_id], vec![l1_id, l2_id]]);
|
|
} else {
|
|
let w1_id = index_map.get_or_create(&row["w1_id"]);
|
|
|
|
let l1_id = index_map.get_or_create(&row["l1_id"]);
|
|
|
|
composition.push(vec![vec![w1_id], vec![l1_id]]);
|
|
}
|
|
|
|
results.push(vec![1.0, 0.0]);
|
|
|
|
let time = Date::parse(&row["time_start"], &time_format)
|
|
.unwrap()
|
|
.midnight()
|
|
.assume_utc()
|
|
.unix_timestamp();
|
|
|
|
times.push(time as u64 / (60 * 60 * 24));
|
|
}
|
|
|
|
let mut hist = History::builder().sigma(1.6).gamma(0.036).build();
|
|
|
|
hist.add_events(composition, results, times, vec![]);
|
|
hist.convergence(10, 0.01, true);
|
|
}
|
|
|
|
mod csv {
|
|
use std::fs::File;
|
|
use std::io::{self, BufRead, BufReader, Lines};
|
|
use std::ops;
|
|
use std::path::Path;
|
|
|
|
pub struct Reader {
|
|
header_map: Vec<String>,
|
|
lines: Lines<BufReader<File>>,
|
|
}
|
|
|
|
impl Reader {
|
|
pub fn open<P: AsRef<Path>>(path: P) -> Result<Self, io::Error> {
|
|
let mut lines = File::open(path).map(BufReader::new)?.lines();
|
|
|
|
let header_map = if let Some(header) = lines.next() {
|
|
let header = header?;
|
|
|
|
header.split(',').map(Into::into).collect::<Vec<_>>()
|
|
} else {
|
|
Vec::new()
|
|
};
|
|
|
|
Ok(Self { header_map, lines })
|
|
}
|
|
|
|
pub fn records(&mut self) -> Records<'_> {
|
|
Records {
|
|
header_map: &self.header_map,
|
|
lines: &mut self.lines,
|
|
}
|
|
}
|
|
}
|
|
|
|
pub struct Records<'a> {
|
|
header_map: &'a Vec<String>,
|
|
lines: &'a mut Lines<BufReader<File>>,
|
|
}
|
|
|
|
impl<'a> Iterator for Records<'a> {
|
|
type Item = Record<'a>;
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
let line = self.lines.next()?;
|
|
|
|
Some(Record {
|
|
header_map: self.header_map,
|
|
columns: line.unwrap().split(',').map(Into::into).collect::<Vec<_>>(),
|
|
})
|
|
}
|
|
}
|
|
|
|
pub struct Record<'a> {
|
|
header_map: &'a Vec<String>,
|
|
columns: Vec<String>,
|
|
}
|
|
|
|
impl<'a> ops::Index<&str> for Record<'a> {
|
|
type Output = str;
|
|
|
|
fn index(&self, index: &str) -> &Self::Output {
|
|
&self.columns[self
|
|
.header_map
|
|
.iter()
|
|
.position(|header| header == index)
|
|
.unwrap()]
|
|
}
|
|
}
|
|
}
|