aboutsummaryrefslogtreecommitdiff
path: root/planetwars-rules/src/serializer.rs
blob: 22ba52e73804824440d438278b497e35e8ec913e (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
use super::protocol as proto;
use super::rules::{Expedition, Planet, PwState};

/// Serialize given gamestate
pub fn serialize(state: &PwState) -> proto::State {
    serialize_rotated(state, 0)
}

/// Serialize given gamestate with player numbers rotated by given offset.
pub fn serialize_rotated(state: &PwState, offset: usize) -> proto::State {
    let serializer = Serializer::new(state, offset);
    serializer.serialize_state()
}

struct Serializer<'a> {
    state: &'a PwState,
    player_num_offset: usize,
}

impl<'a> Serializer<'a> {
    fn new(state: &'a PwState, offset: usize) -> Self {
        Serializer {
            state,
            player_num_offset: offset,
        }
    }

    fn serialize_state(&self) -> proto::State {
        proto::State {
            planets: self
                .state
                .planets
                .iter()
                .map(|planet| self.serialize_planet(planet))
                .collect(),
            expeditions: self
                .state
                .expeditions
                .iter()
                .map(|exp| self.serialize_expedition(exp))
                .collect(),
        }
    }

    /// Gets the player number for given player id.
    /// Player numbers are 1-based (as opposed to player ids), They will also be
    /// rotated based on the number offset for this serializer.
    fn player_num(&self, player_id: usize) -> usize {
        let num_players = self.state.players.len();
        let rotated_id = (player_id + num_players - self.player_num_offset) % num_players;
        // protocol player ids start at 1
        rotated_id + 1
    }

    fn serialize_planet(&self, planet: &Planet) -> proto::Planet {
        proto::Planet {
            name: planet.name.clone(),
            x: planet.x,
            y: planet.y,
            owner: planet.owner().map(|id| self.player_num(id)),
            ship_count: planet.ship_count(),
        }
    }

    fn serialize_expedition(&self, exp: &Expedition) -> proto::Expedition {
        proto::Expedition {
            id: exp.id,
            owner: self.player_num(exp.fleet.owner.unwrap()),
            ship_count: exp.fleet.ship_count,
            origin: self.state.planets[exp.origin as usize].name.clone(),
            destination: self.state.planets[exp.target as usize].name.clone(),
            turns_remaining: exp.turns_remaining,
        }
    }
}