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
106
107
108
109
110
111
112
|
#[macro_use]
extern crate serde;
extern crate serde_json;
pub mod config;
pub mod protocol;
pub mod rules;
pub mod serializer;
pub use config::Config as PwConfig;
pub use protocol::CommandError;
pub use rules::{Dispatch, PwState};
use std::collections::HashMap;
pub struct PlanetWars {
/// Game state
state: rules::PwState,
/// Map planet names to their ids
planet_map: HashMap<String, usize>,
}
impl PlanetWars {
pub fn create(config: PwConfig, num_players: usize) -> Self {
let state = config.create_state(num_players);
let planet_map = state
.planets
.iter()
.map(|p| (p.name.clone(), p.id))
.collect();
PlanetWars { state, planet_map }
}
/// Proceed to next turn
pub fn step(&mut self) {
self.state.repopulate();
self.state.step();
}
pub fn is_finished(&self) -> bool {
self.state.is_finished()
}
pub fn serialize_state(&self) -> protocol::State {
serializer::serialize(&self.state)
}
pub fn serialize_player_state(&self, player_id: usize) -> protocol::State {
serializer::serialize_rotated(&self.state, player_id - 1)
}
pub fn state(&self) -> &PwState {
&self.state
}
/// Execute a command
pub fn execute_command(
&mut self,
player_num: usize,
cmd: &protocol::Command,
) -> Result<(), CommandError> {
let dispatch = self.parse_command(player_num, cmd)?;
self.state.dispatch(&dispatch);
Ok(())
}
/// Check the given command for validity.
/// If it is valid, return an internal representation of the dispatch
/// described by the command.
pub fn parse_command(
&self,
player_id: usize,
cmd: &protocol::Command,
) -> Result<Dispatch, CommandError> {
let origin_id = *self
.planet_map
.get(&cmd.origin)
.ok_or(CommandError::OriginDoesNotExist)?;
let target_id = *self
.planet_map
.get(&cmd.destination)
.ok_or(CommandError::DestinationDoesNotExist)?;
if self.state.planets[origin_id].owner() != Some(player_id - 1) {
println!("owner was {:?}", self.state.planets[origin_id].owner());
return Err(CommandError::OriginNotOwned);
}
if self.state.planets[origin_id].ship_count() < cmd.ship_count {
return Err(CommandError::NotEnoughShips);
}
if cmd.ship_count == 0 {
return Err(CommandError::ZeroShipMove);
}
Ok(Dispatch {
origin: origin_id,
target: target_id,
ship_count: cmd.ship_count,
})
}
/// Execute a dispatch.
/// This assumes the dispatch is valid. You should check this yourself
/// or use `parse_command` to obtain a valid dispatch.
pub fn execute_dispatch(&mut self, dispatch: &Dispatch) {
self.state.dispatch(dispatch);
}
}
|