summaryrefslogtreecommitdiff
path: root/src/main.rs
diff options
context:
space:
mode:
authorJustin Worthe <justin@worthe-it.co.za>2019-04-22 21:50:00 +0200
committerJustin Worthe <justin@worthe-it.co.za>2019-04-22 21:50:00 +0200
commit88430f31c73f469086b68f2b77d1e1ba5f9178e7 (patch)
tree292a0aceba92e4d0c38679ed919b9b463c82152b /src/main.rs
parent3e54b01003aa9d27de8f4ca13c9240fe785ec0e1 (diff)
More minimal game state
I'd prefer to start with just the state that I need, and progressively readd the bits that I've skipped as I find I need them, or as the competition evolves.
Diffstat (limited to 'src/main.rs')
-rw-r--r--src/main.rs284
1 files changed, 9 insertions, 275 deletions
diff --git a/src/main.rs b/src/main.rs
index cba96f5..216915c 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -7,16 +7,21 @@ mod command;
mod json;
mod geometry;
mod game;
+mod strategy;
-use command::*;
-use json::*;
+use command::Command;
+use strategy::choose_move;
fn main() {
for line in stdin().lock().lines() {
let round_number = line.expect("Failed to read line from stdin: {}");
+
let command =
- match read_state_from_json_file(&format!("./rounds/{}/state.json", round_number)) {
- Ok(state) => choose_command(state),
+ match json::read_state_from_json_file(&format!("./rounds/{}/state.json", round_number)) {
+ Ok(json_state) => {
+ let game_board = game::GameBoard::new(json_state);
+ choose_move(&game_board)
+ },
Err(e) => {
eprintln!("WARN: State file could not be parsed: {}", e);
Command::DoNothing
@@ -25,274 +30,3 @@ fn main() {
println!("C;{};{}", round_number, command);
}
}
-
-fn choose_command(state: State) -> Command {
- match state.active_worm() {
- Some(worm) => {
- if let Some(direction) = find_worm_in_firing_distance(&state, worm) {
- Command::Shoot(direction)
- } else {
- let choices = valid_adjacent_positions(&state, &worm.position);
- let choice = choices
- .choose(&mut rand::thread_rng())
- .expect("No valid directions to move in");
- let chosen_cell = state.cell_at(&choice);
-
- match chosen_cell.map(|c| &c.cell_type) {
- Some(CellType::Air) => Command::Move(choice.x, choice.y),
- Some(CellType::Dirt) => Command::Dig(choice.x, choice.y),
- Some(CellType::DeepSpace) | None => Command::DoNothing,
- }
- }
- }
- None => {
- eprintln!("WARN: The active worm did not appear in the state file");
- Command::DoNothing
- }
- }
-}
-
-fn find_worm_in_firing_distance(state: &State, worm: &PlayerWorm) -> Option<Direction> {
- let directions: [(Direction, Box<dyn Fn(&Position, u32) -> Option<Position>>); 8] = [
- (Direction::West, Box::new(|p, d| p.west(d))),
- (Direction::NorthWest, Box::new(|p, d| p.north(d).and_then(|p| p.west(d)))),
- (Direction::North, Box::new(|p, d| p.north(d))),
- (Direction::NorthEast, Box::new(|p, d| p.north(d).and_then(|p| p.east(d, state.map_size)))),
- (Direction::East, Box::new(|p, d| p.east(d, state.map_size))),
- (Direction::SouthEast, Box::new(|p, d| p.south(d, state.map_size).and_then(|p| p.east(d, state.map_size)))),
- (Direction::South, Box::new(|p, d| p.south(d, state.map_size))),
- (Direction::SouthWest, Box::new(|p, d| p.south(d, state.map_size).and_then(|p| p.west(d)))),
- ];
-
- for (dir, dir_fn) in &directions {
- let range = adjust_range_for_diagonals(dir, worm.weapon.range);
-
- for distance in 1..=range {
- let target = dir_fn(&worm.position, distance);
- match target.and_then(|t| state.cell_at(&t)) {
- Some(Cell {
- occupier: Some(CellWorm::OpponentWorm { .. }),
- ..
- }) => return Some(*dir),
- Some(Cell {
- cell_type: CellType::Air,
- ..
- }) => continue,
- _ => break,
- }
- }
- }
- None
-}
-
-fn adjust_range_for_diagonals(dir: &Direction, straight_range: u32) -> u32 {
- if dir.is_diagonal() {
- ((straight_range as f32 + 1.) / 2f32.sqrt()).floor() as u32
- } else {
- straight_range
- }
-}
-
-fn valid_adjacent_positions(state: &State, pos: &Position) -> Vec<Position> {
- let choices = [
- pos.west(1),
- pos.west(1).and_then(|p| p.north(1)),
- pos.north(1),
- pos.north(1).and_then(|p| p.east(1, state.map_size)),
- pos.east(1, state.map_size),
- pos.east(1, state.map_size)
- .and_then(|p| p.south(1, state.map_size)),
- pos.south(1, state.map_size),
- pos.south(1, state.map_size).and_then(|p| p.west(1)),
- ];
- choices.iter().flatten().cloned().collect()
-}
-
-#[cfg(test)]
-mod test {
- use super::*;
-
- #[test]
- fn adjacent_positions_give_valid_positions() {
- let dummy_state = State {
- current_round: 0,
- max_rounds: 0,
- map_size: 3,
- current_worm_id: 0,
- consecutive_do_nothing_count: 0,
- my_player: Player {
- id: 0,
- score: 0,
- health: 0,
- worms: Vec::new(),
- },
- opponents: Vec::new(),
- map: Vec::new(),
- };
-
- assert_eq!(
- 3,
- valid_adjacent_positions(&dummy_state, &Position { x: 0, y: 0 }).len()
- );
- assert_eq!(
- 5,
- valid_adjacent_positions(&dummy_state, &Position { x: 1, y: 0 }).len()
- );
- assert_eq!(
- 3,
- valid_adjacent_positions(&dummy_state, &Position { x: 2, y: 0 }).len()
- );
- assert_eq!(
- 5,
- valid_adjacent_positions(&dummy_state, &Position { x: 0, y: 1 }).len()
- );
- assert_eq!(
- 8,
- valid_adjacent_positions(&dummy_state, &Position { x: 1, y: 1 }).len()
- );
- assert_eq!(
- 5,
- valid_adjacent_positions(&dummy_state, &Position { x: 2, y: 1 }).len()
- );
- assert_eq!(
- 3,
- valid_adjacent_positions(&dummy_state, &Position { x: 0, y: 2 }).len()
- );
- assert_eq!(
- 5,
- valid_adjacent_positions(&dummy_state, &Position { x: 1, y: 2 }).len()
- );
- assert_eq!(
- 3,
- valid_adjacent_positions(&dummy_state, &Position { x: 2, y: 2 }).len()
- );
- }
-
- #[test]
- fn range_adjustment_matches_examples() {
- assert_eq!(1, adjust_range_for_diagonals(&Direction::East, 1));
- assert_eq!(2, adjust_range_for_diagonals(&Direction::East, 2));
- assert_eq!(3, adjust_range_for_diagonals(&Direction::East, 3));
- assert_eq!(4, adjust_range_for_diagonals(&Direction::East, 4));
-
- assert_eq!(1, adjust_range_for_diagonals(&Direction::SouthEast, 1));
- assert_eq!(2, adjust_range_for_diagonals(&Direction::SouthEast, 2));
- assert_eq!(2, adjust_range_for_diagonals(&Direction::SouthEast, 3));
- assert_eq!(3, adjust_range_for_diagonals(&Direction::SouthEast, 4));
- }
-
- mod find_worm_in_firing_distance {
- use super::super::*;
-
- fn worm_shooting_dummy_state() -> (State, PlayerWorm) {
- let dummy_state = State {
- current_round: 0,
- max_rounds: 0,
- map_size: 5,
- current_worm_id: 0,
- consecutive_do_nothing_count: 0,
- my_player: Player {
- id: 0,
- score: 0,
- health: 0,
- worms: Vec::new(),
- },
- opponents: Vec::new(),
- map: vec![Vec::new()],
- };
- let active_worm = PlayerWorm {
- id: 0,
- health: 100,
- position: Position { x: 2, y: 2 },
- digging_range: 1,
- movement_range: 1,
- weapon: Weapon {
- range: 3,
- damage: 1,
- },
- };
-
- (dummy_state, active_worm)
- }
-
- #[test]
- fn finds_a_worm_that_can_be_shot() {
- let (mut dummy_state, active_worm) = worm_shooting_dummy_state();
- dummy_state.map[0].push(Cell {
- x: 3,
- y: 2,
- cell_type: CellType::Air,
- occupier: None,
- powerup: None,
- });
- dummy_state.map[0].push(Cell {
- x: 4,
- y: 2,
- cell_type: CellType::Air,
- occupier: Some(CellWorm::OpponentWorm {
- id: 0,
- player_id: 1,
- health: 0,
- position: Position { x: 4, y: 2 },
- digging_range: 1,
- movement_range: 1,
- }),
- powerup: None,
- });
-
- let firing_dir = find_worm_in_firing_distance(&dummy_state, &active_worm);
- assert_eq!(Some(Direction::East), firing_dir);
- }
-
- #[test]
- fn worm_cant_shoot_through_dirt() {
- let (mut dummy_state, active_worm) = worm_shooting_dummy_state();
- dummy_state.map[0].push(Cell {
- x: 3,
- y: 2,
- cell_type: CellType::Dirt,
- occupier: None,
- powerup: None,
- });
- dummy_state.map[0].push(Cell {
- x: 4,
- y: 2,
- cell_type: CellType::Air,
- occupier: Some(CellWorm::OpponentWorm {
- id: 0,
- player_id: 1,
- health: 0,
- position: Position { x: 4, y: 2 },
- digging_range: 1,
- movement_range: 1,
- }),
- powerup: None,
- });
-
- let firing_dir = find_worm_in_firing_distance(&dummy_state, &active_worm);
- assert_eq!(None, firing_dir);
- }
-
- #[test]
- fn identifies_lack_of_worms_to_shoot() {
- let (mut dummy_state, active_worm) = worm_shooting_dummy_state();
- dummy_state.map[0].push(Cell {
- x: 3,
- y: 2,
- cell_type: CellType::Air,
- occupier: None,
- powerup: None,
- });
- dummy_state.map[0].push(Cell {
- x: 4,
- y: 2,
- cell_type: CellType::Air,
- occupier: None,
- powerup: None,
- });
-
- let firing_dir = find_worm_in_firing_distance(&dummy_state, &active_worm);
- assert_eq!(None, firing_dir);
- }
- }
-}