use gtk::prelude::*; use clap::Parser; use csv; use rand::Rng; use text_io; const APP_ID: &str = "com.encrox.rraffle"; #[derive(Parser, Debug)] struct Cli { /// CSV file with names and number of lots #[arg(short, long)] file: Option, /// Show GUI #[arg(short, long)] gui: bool, /// Shuffle animation #[arg(short, long)] animation: Option, /// Number of draws #[arg(short, long, default_value_t = 5)] draws: u32, /// Number of wins per entry #[arg(short, long, default_value_t = 2)] wins: u32, /// Interactive when in CLI mode #[arg(short, long)] interactive: bool, } #[derive(Debug)] struct Entry { name: String, lots: u32, wins: u32, odds: f64 } fn load_csv(entries : &mut Vec, file: std::path::PathBuf) { let reader = csv::Reader::from_path(file); for record in reader.unwrap().records() { //dbg!(record.unwrap().get(0).unwrap()); let rec = record.unwrap(); entries.push(Entry { name: rec.get(0).unwrap().to_string(), lots: rec.get(1).unwrap().parse::().unwrap(), wins: 2, odds: 0.0 }); } } fn max_wins(entries : &mut Vec, wins : u32) { for entry in entries { entry.wins = wins; } } fn calc_odds(entries : &mut Vec) { let mut sum : u32 = 0; for entry in &mut *entries { sum += if entry.wins > 0 { entry.lots } else { 0 }; } for entry in entries { entry.odds = if entry.wins > 0 { entry.lots as f64 / sum as f64 } else { 0.0 }; } } fn get_winner(entries : &mut Vec) -> &Entry { let mut rng = rand::thread_rng(); let rn = rng.gen::(); let mut sum : f64 = 0.0; for entry in entries { if rn >= sum && rn < sum + entry.odds { entry.lots -= 1; entry.wins -= 1; return entry; } sum += entry.odds; } unreachable!(); } fn main() { let args = Cli::parse(); //dbg!(args); if args.gui { // Create a new application let app = gtk::Application::builder().application_id(APP_ID).build(); // Connect to "activate" signal of `app` app.connect_activate(build_ui); // Run the application app.run_with_args(&[""]); } else { if !args.file.is_none() { let mut entries = Vec::::new(); load_csv(&mut entries, args.file.unwrap()); max_wins(&mut entries, args.wins); let mut round = 1; 'outer: loop { calc_odds(&mut entries); println!("Draw round: {}", round); println!("Entries: {:?}", &entries); if args.interactive { print!("Option (s = start, a = abort) [s/a]: "); loop { let option : char = text_io::read!(); match option { 'a' => break 'outer, 's' => break, _ => println!("Unknown option: {}", option), } } } let winner = get_winner(&mut entries); println!("Winner is: {}", winner.name); if args.interactive { print!("Option (n = next, a = abort) [n/a]: "); loop { let option : char = text_io::read!(); match option { 'a' => break 'outer, 'n' => break, _ => println!("Unknown option: {}", option), } } } if round == args.draws && !args.interactive { println!("Number of draws reached."); break; } round += 1; } } } } fn build_ui(app: >k::Application) { let glade_src = include_str!("main.glade"); let builder = gtk::Builder::from_string(glade_src); let window: gtk::ApplicationWindow = builder.object("window").expect("Couldn't get window"); let tv : gtk::TreeView = builder.object("tv").expect("Couldn't get tree view"); let btn_draw_single : gtk::Button = builder.object("btn_draw_single").expect("Couldn't get button btn_draw_single"); let btn_draw_multiple : gtk::Button = builder.object("btn_draw_multiple").expect("Couldn't get button btn_draw_multiple"); let file_choose_csv : gtk::FileChooserButton = builder.object("file_choose_csv").expect("Couldn't get button file_choose_csv"); let btn_load : gtk::Button = builder.object("btn_load").expect("Couldn't get button btn_load"); let lbl_round : gtk::Label = builder.object("lbl_round").expect("Couldn't get lbl_round"); let btn_reset : gtk::Button = builder.object("btn_reset").expect("Couldn't get btn_reset"); let sp_num_draws : gtk::SpinButton = builder.object("sp_num_draws").expect("Couldn't get sp_num_draws"); let ts : gtk::TreeStore = builder.object("ts").expect("Couldn't get tree store"); window.set_application(Some(app)); btn_load.connect_clicked(glib::clone!(@weak file_choose_csv, @weak ts => move |button| { //let data = load_csv(file_choose_csv.filename().unwrap()); //for entry in data { let iter = ts.insert(None, -1); ts.set(&iter, &[(0, &glib::Value::from("Eva")), (1, &0.to_value())]); //} })); // Present window window.show_all(); }