summaryrefslogtreecommitdiff
path: root/src/bin/depth-first-search.rs
blob: c04061da92438289ff13b4aeb41efb2ab42b5b28 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
extern crate zombot;
extern crate time;
use time::PreciseTime;

use zombot::*;
use zombot::engine::*;
use zombot::engine::settings::*;
use zombot::engine::command::*;

const STATE_PATH: &str = "tests/state0.json";

use std::process;

fn main() {
    println!("Performing an exhaustive depth-first walk of the game states");
    let start_time = PreciseTime::now();
    let (settings, state) = match input::json::read_bitwise_state_from_file(STATE_PATH) {
        Ok(ok) => ok,
        Err(error) => {
            println!("Error while parsing JSON file: {}", error);
            process::exit(1);
        }
    };

    walk_states(&settings, &state, 0);

    println!("Total running time: {}", start_time.to(PreciseTime::now()));
}

fn walk_states<GS: GameState>(settings: &GameSettings, state: &GS, depth: u32) {
    if depth >= 200 {
        return;
    }

    let player_buildings = valid_buildings(settings, &state.player(), state.player_has_max_teslas());
    let opponent_buildings = valid_buildings(settings, &state.opponent(), state.opponent_has_max_teslas());

    for &player_building in &player_buildings {
        for player_i in 0..state.unoccupied_player_cell_count() {
            for &opponent_building in &opponent_buildings {
                for opponent_i in 0..state.unoccupied_opponent_cell_count() {
                    let player_point = state.location_of_unoccupied_player_cell(player_i);
                    let player_move = Command::Build(player_point, player_building);
                    let opponent_point = state.location_of_unoccupied_player_cell(opponent_i);
                    let opponent_move = Command::Build(opponent_point, opponent_building);

                    let mut after_move = state.clone();
                    let status = after_move.simulate(settings, player_move, opponent_move);
                    if status == GameStatus::Continue {
                        walk_states(settings, &after_move, depth+1);
                    }
                }
            }
        }
    }
    for player_building in player_buildings {
        for player_i in 0..state.unoccupied_player_cell_count() {
            let player_point = state.location_of_unoccupied_player_cell(player_i);
            let player_move = Command::Build(player_point, player_building);
            let opponent_move = Command::Nothing;

            let mut after_move = state.clone();
            let status = after_move.simulate(settings, player_move, opponent_move);
            if status == GameStatus::Continue {
                walk_states(settings, &after_move, depth+1);
            }
        }
    }
    for opponent_building in opponent_buildings {
        for opponent_i in 0..state.unoccupied_opponent_cell_count() {
            let player_move = Command::Nothing;
            let opponent_point = state.location_of_unoccupied_player_cell(opponent_i);
            let opponent_move = Command::Build(opponent_point, opponent_building);

            let mut after_move = state.clone();
            let status = after_move.simulate(settings, player_move, opponent_move);
            if status == GameStatus::Continue {
                walk_states(settings, &after_move, depth+1);
            }
        }
    }
    let player_move = Command::Nothing;
    let opponent_move = Command::Nothing;
    let mut after_move = state.clone();
    let status = after_move.simulate(settings, player_move, opponent_move);
    if status == GameStatus::Continue {
        walk_states(settings, &after_move, depth+1);
    }
    if depth < 10 {
        print!(".");
    }
}

fn valid_buildings(settings: &GameSettings, player: &Player, has_max_teslas: bool) -> Vec<BuildingType> {
    let mut result = Vec::with_capacity(4);
    for b in BuildingType::all().iter() {
        let building_setting = settings.building_settings(*b);
        let affordable = building_setting.price <= player.energy;
        let is_tesla = *b == BuildingType::Tesla;
        if affordable && (!is_tesla || !has_max_teslas) {
            result.push(*b);
        }
    }
    result
}