diff options
Diffstat (limited to 'tests/official-runner-matching.rs')
-rw-r--r-- | tests/official-runner-matching.rs | 142 |
1 files changed, 134 insertions, 8 deletions
diff --git a/tests/official-runner-matching.rs b/tests/official-runner-matching.rs index 7ef12b8..12b6010 100644 --- a/tests/official-runner-matching.rs +++ b/tests/official-runner-matching.rs @@ -1,13 +1,139 @@ +use steam_powered_wyrm::json; +use steam_powered_wyrm::game::*; +use steam_powered_wyrm::command::Command; +use std::path::Path; +use std::fs::File; +use std::io::prelude::*; #[test] fn simulates_the_same_match() { - //TODO - //iterate over list of replays (FS?) - - //read initial state.json - //iterate over moves - //simulate move (both sides) - //assert state is as expected - //repeat with players swapped? + let replays = Path::new("tests/replays/"); + for replay in replays.read_dir().expect("read_dir failed") { + let replay = replay.expect("error on replay").path(); + + let mut game_board = GameBoard::new( + json::read_state_from_json_file(&replay.join(Path::new("A-init.json"))).expect("Failed to read initial state") + ); + let player_csv = read_file_lines(&replay.join(Path::new("A-log.csv")), 1); + let opponent_csv = read_file_lines(&replay.join(Path::new("B-log.csv")), 1); + + for round in 0..player_csv.len() { + println!("Testing round {}", round); + + let player = split_csv(&player_csv[round]); + let opponent = split_csv(&opponent_csv[round]); + + assert_eq!(round + 1, player[0].parse::<usize>().expect(&format!("Invalid player input on round {}", round))); + assert_eq!(round + 1, opponent[0].parse::<usize>().expect(&format!("Invalid opponent input on round {}", round))); + + // active worm id field in CSV refers to the worm of the + // move. The rest of the state refers to after the move + // has happened. + assert_eq!(player[3].parse::<i32>().unwrap(), game_board.players[0].worms[game_board.players[0].active_worm].id, "Active worm is incorrect for player 0"); + assert_eq!(opponent[3].parse::<i32>().unwrap(), game_board.players[1].worms[game_board.players[1].active_worm].id, "Active worm is incorrect for player 1"); + + if round != 0 { + let player_move = read_move(&player); + let opponent_move = read_move(&opponent); + let _ = game_board.simulate([player_move, opponent_move]); + } + + for player_index in 0..2 { + let csv_row = match player_index { + 0 => &player, + _ => &opponent + }; + for worm_index in 0..3 { + let worm_id = worm_index as i32 + 1; + + match game_board.players[player_index].find_worm(worm_id) { + Some(worm) => { + assert_eq!(csv_row[6 + worm_index * 3].parse::<i32>().unwrap(), worm.health, "Worm health is incorrect for worm {} on player {}, Row: {:?}", worm_id, player_index, csv_row); + assert_eq!(csv_row[7 + worm_index * 3].parse::<i8>().unwrap(), worm.position.x, "Worm x is incorrect for worm {} on player {}, Row: {:?}", worm_id, player_index, csv_row); + assert_eq!(csv_row[8 + worm_index * 3].parse::<i8>().unwrap(), worm.position.y, "Worm y is incorrect for worm {} on player {}, Row: {:?}", worm_id, player_index, csv_row); + }, + None => { + // If the worms don't appear in my state, they should be dead + assert!(csv_row[6 + worm_index * 3].parse::<i32>().unwrap() <= 0, "Worm is not actually dead"); + } + } + } + } + } + } +} + + +fn read_file_lines(path: &Path, skip: usize) -> Vec<String> { + let mut file = File::open(path).unwrap(); + let mut contents = String::new(); + file.read_to_string(&mut contents).unwrap(); + contents.split("\n").skip(skip).map(String::from).filter(|s| !s.is_empty()).collect() +} + +fn split_csv(input: &str) -> Vec<String> { + let mut result = Vec::new(); + let mut next = Vec::new(); + let mut quoted = false; + + for c in input.chars() { + match c { + '"' => { + quoted = !quoted; + }, + ',' if !quoted => { + result.push(next.iter().collect()); + next = Vec::new(); + }, + c => { + next.push(c); + } + } + } + result.push(next.iter().collect()); + result +} + +fn read_move(csv_line: &[String]) -> Command { + match csv_line[1].as_ref() { + "move" => { + let (x, y) = read_xy_pair(&csv_line[2]); + Command::Move(x, y) + }, + "dig" => { + let (x, y) = read_xy_pair(&csv_line[2]); + Command::Dig(x, y) + }, + "nothing" => { + Command::DoNothing + }, + "shoot" => { + use steam_powered_wyrm::geometry::Direction::*; + + let dir = match csv_line[2].as_ref() { + "shoot N" => North, + "shoot NE" => NorthEast, + "shoot E" => East, + "shoot SE" => SouthEast, + "shoot S" => South, + "shoot SW" => SouthWest, + "shoot W" => West, + "shoot NW" => NorthWest, + _ => panic!("Unknown shoot direction: {}", csv_line[2]) + }; + Command::Shoot(dir) + }, + x => { + panic!("Unknown command {}", x); + } + } +} + +fn read_xy_pair(input: &str) -> (i8, i8) { + let mut char_iter = input.chars(); + let _ = char_iter.by_ref().take_while(|c| *c != '(').collect::<String>(); + let x = char_iter.by_ref().take_while(|c| *c != ',').collect::<String>().trim().parse::<i8>().unwrap(); + let y = char_iter.by_ref().take_while(|c| *c != ')').collect::<String>().trim().parse::<i8>().unwrap(); + (x, y) } |