1pub mod models;
2pub use models::*;
3
4use wasm_bindgen::prelude::*;
5
6#[wasm_bindgen]
7pub fn winner(fen_w: &str, fen_b: &str, flat_moves_string_w: &str, flat_moves_string_b: &str) -> String {
8 let moves_w: Vec<&str> = flat_moves_string_w.split("-").collect();
9 let moves_b: Vec<&str> = flat_moves_string_b.split("-").collect();
10
11 let game_w = MonsGame::from_fen(&fen_w);
12 let game_b = MonsGame::from_fen(&fen_b);
13
14 if game_w.is_none() || game_b.is_none() {
15 if game_w.is_none() && game_b.is_none() {
16 return "x".to_string();
17 } else if game_w.is_none() {
18 return Color::Black.fen();
19 } else {
20 return Color::White.fen();
21 }
22 }
23
24 let winner_color_game_w = game_w.unwrap().winner_color();
25 let winner_color_game_b = game_b.unwrap().winner_color();
26
27 if winner_color_game_w.is_none() && winner_color_game_b.is_none() {
28 return "".to_string()
29 }
30
31 let mut game = MonsGame::new();
32
33 let mut w_index = 0;
34 let mut b_index = 0;
35
36 while w_index < moves_w.len() || b_index < moves_b.len() {
37 if game.active_color == Color::White {
38 if w_index >= moves_w.len() { return "x".to_string(); }
39 let inputs = Input::array_from_fen(moves_w[w_index]);
40 _ = game.process_input(inputs, false, false);
41 w_index += 1;
42 } else {
43 if b_index >= moves_b.len() { return "x".to_string(); }
44 let inputs = Input::array_from_fen(moves_b[b_index]);
45 _ = game.process_input(inputs, false, false);
46 b_index += 1;
47 }
48
49 if let Some(winner) = game.winner_color() {
50 if winner == Color::White {
51 if w_index == moves_w.len() && fen_w == game.fen() {
52 return winner.fen();
53 } else {
54 return "x".to_string();
55 }
56 } else {
57 if b_index == moves_b.len() && fen_b == game.fen() {
58 return winner.fen();
59 } else {
60 return "x".to_string();
61 }
62 }
63 }
64 }
65
66 return "x".to_string();
67}
68
69#[cfg(test)]
70mod tests {
71 use super::*;
72 use std::fs::{self, File};
73 use std::io::{self, Read};
74 use std::path::Path;
75
76 #[derive(Hash, PartialEq, Eq, Clone, Debug)]
77 struct TestCase {
78 fen_before: String,
79 input_fen: String,
80 output_fen: String,
81 fen_after: String,
82 }
83
84 #[test]
85 fn test_from_test_data() -> io::Result<()> {
86 let test_data_dir = Path::new("test-data");
87 let mut count = 0;
88 let mut oks = 0;
89 for entry in fs::read_dir(test_data_dir)? {
90 let entry = entry?;
91 let path = entry.path();
92 if path.is_file() && path.file_name().and_then(|f| f.to_str()).map_or(false, |s| !s.starts_with('.')) {
93 let mut file = File::open(&path)?;
94 let mut contents = String::new();
95 file.read_to_string(&mut contents)?;
96 let parts: Vec<&str> = contents.split("\"").collect();
97 let mut test_case = TestCase {
98 fen_before: String::new(),
99 input_fen: String::new(),
100 output_fen: String::new(),
101 fen_after: String::new(),
102 };
103
104 for i in 0..parts.len() {
105 match parts[i] {
106 "fenBefore" => test_case.fen_before = parts[i + 2].replace('\\', ""),
107 "inputFen" => test_case.input_fen = parts[i + 2].replace('\\', ""),
108 "outputFen" => test_case.output_fen = parts[i + 2].replace('\\', ""),
109 "fenAfter" => test_case.fen_after = parts[i + 2].replace('\\', ""),
110 _ => {}
111 }
112 }
113
114 let inputs = Input::array_from_fen(&test_case.input_fen);
115 let recreated_inputs_fen = Input::fen_from_array(&inputs);
116 assert!(recreated_inputs_fen == test_case.input_fen);
117
118 let game_after = MonsGame::from_fen(&test_case.fen_after);
119 let recreated_game_after_fen = game_after.unwrap().fen();
120 assert!(recreated_game_after_fen == test_case.fen_after);
121
122 let mut game_before = MonsGame::from_fen(&test_case.fen_before).unwrap();
123 let recreated_game_before_fen = game_before.fen();
124 assert!(recreated_game_before_fen == test_case.fen_before);
125
126 let output = Output::from_fen(&test_case.output_fen);
127 let recreated_output_fen = output.unwrap().fen();
128 assert!(recreated_output_fen == test_case.output_fen);
129
130 assert!(!test_case.fen_before.is_empty() && !test_case.fen_after.is_empty() && !test_case.output_fen.is_empty(), "test data must not be empty");
131
132 let actual_output = game_before.process_input(inputs, false, false);
133
134 if game_before.fen() != test_case.fen_after || actual_output.fen() != test_case.output_fen {
135 println!("expected {}", test_case.output_fen);
136 println!("received {}", actual_output.fen());
137 println!("forinput {}", test_case.input_fen);
138 println!("forboard {}", test_case.fen_before);
139 println!("expected fen after {}", test_case.fen_after);
140 println!("received fen after {}\n\n\n\n\n", game_before.fen());
141 count += 1;
142 } else {
143 oks += 1;
144 println!("ok {}", oks);
145 }
146
147 assert!(game_before.fen() == test_case.fen_after);
148 assert!(actual_output.fen() == test_case.output_fen);
149 }
150 }
151 println!("\n\n\n\n\n TOTAL ERRORS {}", count);
152 println!("TOTAL OKS {}", oks);
153 Ok(())
154 }
155}