rust_warrior/
floor.rs

1//! contains types that represent the topology of a level
2
3use std::collections::HashMap;
4
5use crate::unit::{Unit, UnitType};
6
7/// The `Floor::tile` method constructs a conceptual representation of the
8/// floor using the `Tile` enum.
9#[derive(Clone, Copy, Debug, PartialEq)]
10pub enum Tile {
11    Wall,
12    Empty,
13    Stairs,
14    Unit(UnitType),
15}
16
17impl Tile {
18    /// A character (`&str` for convenience) representation of the tile
19    pub fn draw(self) -> &'static str {
20        match self {
21            Tile::Wall => panic!("attempted to draw a wall"),
22            Tile::Empty => " ",
23            Tile::Stairs => ">",
24            Tile::Unit(unit_type) => unit_type.draw(),
25        }
26    }
27}
28
29/// Each level has a `Floor` with a predefined `width` and `height`,
30/// `stairs` positioned at the exit, and one or more `units`. There
31/// is a player-controlled [`Warrior`](crate::warrior::Warrior) unit
32/// for every level.
33#[derive(Clone, Debug)]
34pub struct Floor {
35    /// the east/west count of tiles
36    pub width: usize,
37    /// the north/south count of tiles
38    pub height: usize,
39    /// the position (x, y) of the exit
40    pub stairs: (i32, i32),
41    /// all of the units that the level contains
42    pub units: Vec<Unit>,
43}
44
45impl Floor {
46    /// Returns the predefined configuration for a given `level` number.
47    pub fn load(level: usize) -> Floor {
48        match Floor::get(level) {
49            Some(level) => level,
50            None => unimplemented!(),
51        }
52    }
53
54    /// Returns `true` if a configuration exists for a given `level` number.
55    pub fn exists(level: usize) -> bool {
56        Floor::get(level).is_some()
57    }
58
59    /// Returns a `Tile` representing the current state of a tile
60    /// of the floor at `position`.
61    pub fn tile(&self, position: (i32, i32)) -> Tile {
62        if position == self.stairs {
63            return Tile::Stairs;
64        }
65
66        let unit_positions: HashMap<(i32, i32), UnitType> = self
67            .units
68            .iter()
69            .map(|u| (u.position, u.unit_type))
70            .collect();
71
72        match unit_positions.get(&position) {
73            Some(unit_type) => Tile::Unit(*unit_type),
74            _ => Tile::Empty,
75        }
76    }
77
78    /// Prints a textual representation of the floor and all
79    /// of its units.
80    pub fn draw(&self) -> String {
81        let mut lines = Vec::new();
82        lines.push(format!(" {}", "-".repeat(self.width)));
83
84        let tiles: Vec<&str> = (0..self.width)
85            .map(|x| self.tile((x as i32, 0)).draw())
86            .collect();
87        lines.push(format!("|{}|", tiles.join("")));
88
89        lines.push(format!(" {}", "-".repeat(self.width)));
90        lines.join("\n")
91    }
92
93    fn get(level: usize) -> Option<Floor> {
94        match level {
95            1 => Some(Floor {
96                width: 8,
97                height: 1,
98                stairs: (7, 0),
99                units: vec![Unit::warrior((0, 0))],
100            }),
101            2 => Some(Floor {
102                width: 8,
103                height: 1,
104                stairs: (7, 0),
105                units: vec![Unit::warrior((0, 0)), Unit::sludge((4, 0))],
106            }),
107            3 => Some(Floor {
108                width: 9,
109                height: 1,
110                stairs: (8, 0),
111                units: vec![
112                    Unit::warrior((0, 0)),
113                    Unit::sludge((2, 0)),
114                    Unit::sludge((4, 0)),
115                    Unit::sludge((5, 0)),
116                    Unit::sludge((7, 0)),
117                ],
118            }),
119            4 => Some(Floor {
120                width: 8,
121                height: 1,
122                stairs: (7, 0),
123                units: vec![
124                    Unit::warrior((0, 0)),
125                    Unit::thick_sludge((2, 0)),
126                    Unit::archer((5, 0)),
127                    Unit::thick_sludge((6, 0)),
128                ],
129            }),
130            5 => Some(Floor {
131                width: 8,
132                height: 1,
133                stairs: (7, 0),
134                units: vec![
135                    Unit::warrior((0, 0)),
136                    Unit::captive((2, 0)),
137                    Unit::archer((3, 0)),
138                    Unit::archer((4, 0)),
139                    Unit::thick_sludge((5, 0)),
140                    Unit::captive((6, 0)),
141                ],
142            }),
143            6 => Some(Floor {
144                width: 9,
145                height: 1,
146                stairs: (8, 0),
147                units: vec![
148                    Unit::captive((0, 0)),
149                    Unit::warrior((2, 0)),
150                    Unit::thick_sludge((4, 0)),
151                    Unit::archer((6, 0)),
152                    Unit::archer((7, 0)),
153                ],
154            }),
155            7 => Some(Floor {
156                width: 6,
157                height: 1,
158                stairs: (0, 0),
159                units: vec![
160                    Unit::archer((1, 0)),
161                    Unit::thick_sludge((3, 0)),
162                    Unit::warrior((5, 0)),
163                ],
164            }),
165            8 => Some(Floor {
166                width: 7,
167                height: 1,
168                stairs: (6, 0),
169                units: vec![
170                    Unit::warrior((0, 0)),
171                    Unit::captive((2, 0)),
172                    Unit::wizard((3, 0)),
173                    Unit::wizard((5, 0)),
174                ],
175            }),
176            9 => Some(Floor {
177                width: 12,
178                height: 1,
179                stairs: (0, 0),
180                units: vec![
181                    Unit::captive((1, 0)),
182                    Unit::archer((2, 0)),
183                    Unit::warrior((5, 0)),
184                    Unit::thick_sludge((7, 0)),
185                    Unit::wizard((10, 0)),
186                    Unit::captive((11, 0)),
187                ],
188            }),
189            _ => None,
190        }
191    }
192}