use std::{fs::File, io::{Seek, Write, stdout}};
use bulletformat::ChessBoard;
use color_print::cprintln;
mod position;
use std::path::Path;
use filesize::file_real_size_fast;
mod reader;
#[cfg(feature = "hll")]
mod hyperloglog;
#[cfg(feature = "hll")]
#[macro_use] extern crate cfor;
use reader::{
SydGame
};
mod filter;
#[cfg(any(feature = "positionstats", feature = "readerstats"))]
mod stats;
use filter::Filter;
use std::env;
fn main() -> std::io::Result<()>{
let args: Vec<String> = env::args().collect();
let mut filenames: Vec<String> = Vec::<String>::new();
let mut outfile: String = "data.syd".to_string();
let mut filter: Filter = Filter::default();
for arg in &args[1..] {
if arg.starts_with("--") {
let mut flag = arg[2..].to_string();
let mut res: bool = true;
if flag.starts_with("no-filter") {
filter = Filter::nofilter();
}else {
if flag.starts_with("no-"){
flag = flag[3..].to_string();
res = false;
}
if flag.starts_with("onlyexact") {
filter.require_exact = res;
}else if flag.starts_with("min_depth") {
filter.min_depth = flag.split("=").last().expect("should be").parse::<u8>().unwrap();
}else if flag.starts_with("min_pieces") {
filter.min_pieces = flag.split("=").last().expect("should be").parse::<u32>().unwrap();
}else if flag.starts_with("max_eval") {
filter.max_eval = flag.split("=").last().expect("should be").parse::<u16>().unwrap();
}else if flag.starts_with("require_bm") {
filter.require_bm = res;
}else if flag.starts_with("filter_check") {
filter.filter_check = res;
}else if flag.starts_with("filter_tactical") {
filter.filter_tactical = res;
}else if flag.starts_with("filter_castling") {
filter.filter_castling = res;
}else if flag.starts_with("out=") {
outfile = flag[4..].to_string();
}else {
cprintln!("<red>argument {} unknow</>\n", arg);
}
}
} else {
filenames.push(arg.to_string());
}
}
cprintln!("<cyan>min_depth</> = <red>{}</>", filter.min_depth);
cprintln!("<cyan>min_pieces</> = <red>{}</>", filter.min_pieces);
cprintln!("<cyan>max_eval</> = <red>{}</>", filter.max_eval);
cprintln!("<cyan>require_exact</> = <green>{}</>", filter.require_exact);
cprintln!("<cyan>require_bm</> = <green>{}</>", filter.require_bm);
cprintln!("<cyan>filter_check</> = <green>{}</>", filter.filter_check);
cprintln!("<cyan>filter_tactical</> = <green>{}</>", filter.filter_tactical);
cprintln!("<cyan>filter_castling</> = <green>{}</>", filter.filter_castling);
cprintln!("writing to: <cyan>{}</>", outfile);
let mut nb_positions = 0;
let mut nb_batch = 0;
let mut nb_bytes: usize = 0;
let mut parser = SydGame::new();
for filename in filenames {
cprintln!("parsing file <cyan>{}</>", filename);
let mut f = File::open(&filename).expect("file not found");
let filesize = {
let path = Path::new(&filename);
let metadata = path.symlink_metadata()?;
file_real_size_fast(path, &metadata)?
};
loop {
let mut pos = Vec::<ChessBoard>::new();
match parser.parse_syd(&mut f, &mut pos, &filter) {
Ok(()) => {}
Err(e) if e.kind() == std::io::ErrorKind::UnexpectedEof => break,
Err(e) => return Err(e)
}
nb_positions += pos.len();
nb_batch += 1;
if nb_batch % 1024 == 0 {
print!("\rProgress: {:.2}", f.stream_position().unwrap() as f64 * 100.0 / filesize as f64);
stdout().flush().unwrap();
}
}
println!("");
nb_bytes += f.stream_position().unwrap() as usize;
}
println!("numpos = {} num_batch = {} => {:.2} pos/batch", nb_positions, nb_batch, nb_positions as f64 / nb_batch as f64);
println!("{:.2} B/pos", nb_bytes as f64 / nb_positions as f64);
#[cfg(feature = "positionstats")]
parser.posstats.print();
#[cfg(feature = "readerstats")]
parser.readerstat.print();
Ok(())
}