extern crate vroomba; use vroomba::command::Command; use vroomba::json; use vroomba::state::{GameState, GameStateUpdateEvents}; use std::fs::File; use std::io::prelude::*; use std::path::Path; #[test] fn it_successfully_simulates_replay() { test_from_replay(&Path::new("tests/v1-normal-match/")); } fn test_from_replay(replay_folder: &Path) { let length = replay_folder.read_dir().unwrap().count() - 1; let mut state = json::read_state_from_json_file(&format!( "{}/Round 001/JsonMap.json", replay_folder.display() )) .unwrap(); println!("State 1: {:?}", state); for i in 1..=length { let player = read_player_command(&format!( "{}/Round {:03}/PlayerCommand.txt", replay_folder.display(), i )); let opponent = read_player_command(&format!( "{}/Round {:03}/OpponentCommand.txt", replay_folder.display(), i )); let expected_state = json::read_state_from_json_file(&format!( "{}/Round {:03}/JsonMap.json", replay_folder.display(), i + 1 )) .unwrap(); // We don't know how many they actually have from the state // files. state.players[1].boosts = 1; state.players[1].oils = 1; println!("Player 1: {}, Player 2: {}", player, opponent); state.update([player, opponent], &mut GameStateUpdateEvents::default()); println!("State {}: {:?}", i + 1, state); assert_eq!( state.status, expected_state.status, "\nFailed on state {}\n", i + 1 ); player_assertions(&state, &expected_state, 0, true, i + 1); // TODO: We're only reading the state for player 1, so we can't say what obstacles player 2 may be hitting. Maybe read the full map of obstacles + powerups into the game state at the beginning? There's also the case of boost_remaining ofr player 2. // player_assertions(&state, &expected_state, 1, false, i + 1); // We can do great simulations into the future, but we need to // be told where the future mud is. state = expected_state; } } fn read_player_command(filename: &str) -> Command { let mut file = File::open(filename).unwrap(); let mut content = String::new(); file.read_to_string(&mut content).unwrap(); match content.trim() { "Command: ACCELERATE" => Command::Accelerate, "Command: NOTHING" => Command::Nothing, "Command: DECELERATE" => Command::Decelerate, "Command: TURN_LEFT" => Command::TurnLeft, "Command: TURN_RIGHT" => Command::TurnRight, "Command: USE_BOOST" => Command::UseBoost, "Command: USE_OIL" => Command::UseOil, other => panic!("Unexpected command: {}", other), } } fn player_assertions( actual: &GameState, expected: &GameState, player_index: usize, compare_powerups: bool, round: usize, ) { let actual = &actual.players[player_index]; let expected = &expected.players[player_index]; assert_eq!( actual.position, expected.position, "\nFailed on state {}, player {} position\n", round, player_index + 1 ); assert_eq!( actual.speed, expected.speed, "\nFailed on state {}, player {} speed\n", round, player_index + 1 ); if compare_powerups { assert_eq!( actual.boost_remaining, expected.boost_remaining, "\nFailed on state {}, player {} position,\n", round, player_index + 1 ); assert_eq!( actual.oils, expected.oils, "\nFailed on state {}, player {} oils,\n", round, player_index + 1 ); assert_eq!( actual.boosts, expected.boosts, "\nFailed on state {}, player {} boosts,\n", round, player_index + 1 ); } }