mahjong_cli/simulate/
mod.rs1use std::process;
2
3use mahjong_core::{
4 ai::{PlayActionResult, StandardAI},
5 Game, GamePhase,
6};
7use rustc_hash::FxHashSet;
8
9pub use self::simulate_cli::{get_simulate_command, get_simulate_opts, SimulateOpts};
10use self::stats::Stats;
11
12mod simulate_cli;
13mod stats;
14
15#[derive(Debug)]
16struct HistoryItem {
17 game: Game,
18 result: PlayActionResult,
19}
20
21pub async fn run_simulation(opts: SimulateOpts) {
22 let mut stats = Stats::new();
23
24 loop {
25 let mut game = Game::new(None);
26 let mut history: Option<Vec<HistoryItem>> =
27 if opts.debug { Some(Vec::new()) } else { None };
28
29 for player in 0..Game::get_players_num(&game.style) {
30 game.players.push(player.to_string());
31 }
32
33 let auto_stop_claim_meld = FxHashSet::default();
34 let ai_players = FxHashSet::from_iter(game.players.0.clone());
35 let mut game_ai = StandardAI::new(&mut game, ai_players, auto_stop_claim_meld);
36
37 game_ai.dealer_order_deterministic = Some(false);
38 game_ai.can_draw_round = true;
39
40 loop {
41 let result = game_ai.play_action(opts.debug);
42
43 if opts.debug {
44 let history_vect = history.as_mut().unwrap();
45 history_vect.push(HistoryItem {
46 game: game_ai.game.clone(),
47 result: result.clone(),
48 });
49 }
50
51 if !result.changed {
52 println!("Game didn't change, breaking");
53 if opts.debug {
54 let history = history
55 .as_ref()
56 .unwrap()
57 .iter()
58 .rev()
59 .take(10)
60 .rev()
61 .collect::<Vec<_>>();
62
63 println!("History:");
64 for (idx, history_item) in history.iter().enumerate() {
65 if idx > 0 {
66 println!("---");
67
68 if idx == history.len() - 1 {
69 break;
70 }
71 }
72 println!("- {:?}", history_item.result);
73 println!("{}", history_item.game.get_summary());
74 println!("\n\n\n");
75 }
76 }
77 println!(
78 "Current state:\n{}\n{:?}",
79 game_ai.game.get_summary(),
80 result
81 );
82 process::exit(1);
83 }
84
85 if game_ai.game.phase == GamePhase::End {
86 stats.complete_game(game_ai.game);
87 break;
88 }
89 }
90
91 let passed_interval = stats.print_if_interval(10);
92
93 if passed_interval && opts.once {
94 break;
95 };
96 }
97}