c2b82de9aa7fbda15e480783692909f360de09b6
[entelect-challenge-tower-defence.git] / src / bin / depth-first-search.rs
1 extern crate zombot;
2 extern crate time;
3 use time::PreciseTime;
4
5 use zombot::*;
6 use zombot::engine::*;
7 use zombot::engine::settings::*;
8 use zombot::engine::constants::*;
9 use zombot::engine::command::*;
10
11 const STATE_PATH: &str = "tests/state0.json";
12
13 use std::process;
14
15 fn main() {
16     println!("Performing an exhaustive depth-first walk of the game states");
17     let start_time = PreciseTime::now();
18     let (settings, state) = match input::json::read_bitwise_state_from_file(STATE_PATH) {
19         Ok(ok) => ok,
20         Err(error) => {
21             println!("Error while parsing JSON file: {}", error);
22             process::exit(1);
23         }
24     };
25
26     walk_states(&settings, &state, 0);
27
28     println!("Total running time: {}", start_time.to(PreciseTime::now()));
29 }
30
31 fn walk_states<GS: GameState>(settings: &GameSettings, state: &GS, depth: u32) {
32     if depth >= 200 {
33         return;
34     }
35
36     let player_buildings = valid_buildings(settings, &state.player(), state.player_has_max_teslas());
37     let opponent_buildings = valid_buildings(settings, &state.opponent(), state.opponent_has_max_teslas());
38
39     for &player_building in &player_buildings {
40         for player_i in 0..state.unoccupied_player_cell_count() {
41             for &opponent_building in &opponent_buildings {
42                 for opponent_i in 0..state.unoccupied_opponent_cell_count() {
43                     let player_point = state.location_of_unoccupied_player_cell(player_i);
44                     let player_move = Command::Build(player_point, player_building);
45                     let opponent_point = state.location_of_unoccupied_player_cell(opponent_i);
46                     let opponent_move = Command::Build(opponent_point, opponent_building);
47
48                     let mut after_move = state.clone();
49                     let status = after_move.simulate(settings, player_move, opponent_move);
50                     if status == GameStatus::Continue {
51                         walk_states(settings, &after_move, depth+1);
52                     }
53                 }
54             }
55         }
56     }
57     for player_building in player_buildings {
58         for player_i in 0..state.unoccupied_player_cell_count() {
59             let player_point = state.location_of_unoccupied_player_cell(player_i);
60             let player_move = Command::Build(player_point, player_building);
61             let opponent_move = Command::Nothing;
62
63             let mut after_move = state.clone();
64             let status = after_move.simulate(settings, player_move, opponent_move);
65             if status == GameStatus::Continue {
66                 walk_states(settings, &after_move, depth+1);
67             }
68         }
69     }
70     for opponent_building in opponent_buildings {
71         for opponent_i in 0..state.unoccupied_opponent_cell_count() {
72             let player_move = Command::Nothing;
73             let opponent_point = state.location_of_unoccupied_player_cell(opponent_i);
74             let opponent_move = Command::Build(opponent_point, opponent_building);
75
76             let mut after_move = state.clone();
77             let status = after_move.simulate(settings, player_move, opponent_move);
78             if status == GameStatus::Continue {
79                 walk_states(settings, &after_move, depth+1);
80             }
81         }
82     }
83     let player_move = Command::Nothing;
84     let opponent_move = Command::Nothing;
85     let mut after_move = state.clone();
86     let status = after_move.simulate(settings, player_move, opponent_move);
87     if status == GameStatus::Continue {
88         walk_states(settings, &after_move, depth+1);
89     }
90 }
91
92 fn valid_buildings(settings: &GameSettings, player: &Player, has_max_teslas: bool) -> Vec<BuildingType> {
93     let mut result = Vec::with_capacity(4);
94     for b in BuildingType::all().iter() {
95         let building_setting = settings.building_settings(*b);
96         let affordable = building_setting.price <= player.energy;
97         let is_tesla = *b == BuildingType::Tesla;
98         if affordable && (!is_tesla || !has_max_teslas) {
99             result.push(*b);
100         }
101     }
102     result
103 }