1use serde;
21
22
23use crate::land::Land;
24use std::collections::HashMap;
25use std::ops::{Index, IndexMut};
26use std::slice;
27
28#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
30pub struct Pos {
31 pub x: usize,
33 pub y: usize,
35}
36
37#[allow(clippy::trivially_copy_pass_by_ref)]
41impl Pos {
42 #[inline]
45 pub fn move_cost(&self, other: &Pos) -> usize {
46 use std::cmp::{max, min};
47 let dx = max(self.x, other.x) - min(self.x, other.x);
48 let dy = max(self.y, other.y) - min(self.y, other.y);
49 dx + dy
50 }
51}
52
53#[derive(Debug, PartialEq)]
56pub struct Board<'a> {
57 width: usize,
58 height: usize,
59 cells: Vec<Land<'a>>,
60}
61
62impl<'a> Board<'a> {
63 pub fn build<F>(width: usize, height: usize, mut builder: F) -> Board<'a>
67 where
68 F: FnMut(usize, usize) -> Land<'a>,
69 {
70 let mut cells = Vec::with_capacity(width * height);
71 for y in 0..height {
72 for x in 0..width {
73 cells.push(builder(x, y));
74 }
75 }
76 Board {
77 cells,
78 width,
79 height,
80 }
81 }
82
83 #[inline]
85 pub fn width(&self) -> usize {
86 self.width
87 }
88
89 #[inline]
91 pub fn height(&self) -> usize {
92 self.height
93 }
94
95 #[inline]
96 fn index_at(&self, x: usize, y: usize) -> usize {
97 y * self.width + x
98 }
99
100 #[inline]
102 pub fn at(&self, x: usize, y: usize) -> &Land<'_> {
103 &self.cells[self.index_at(x, y)]
104 }
105
106 #[inline]
108 pub fn at_mut(&mut self, x: usize, y: usize) -> &'a mut Land<'_> {
109 let idx = self.index_at(x, y);
110 &mut self.cells[idx]
111 }
112
113 #[inline]
115 pub fn iter<'b>(&'b self) -> slice::Iter<'b, Land<'a>> {
116 self.cells.iter()
117 }
118
119 #[inline]
122 pub fn iter_mut<'b>(&'b mut self) -> slice::IterMut<'b, Land<'a>> {
123 self.cells.iter_mut()
124 }
125
126 #[inline]
128 pub fn rows<'b>(&'b self) -> slice::Chunks<'b, Land<'a>> {
129 self.cells.chunks(self.width)
130 }
131
132 #[inline]
134 pub fn rows_mut<'b>(&'b mut self) -> slice::ChunksMut<'b, Land<'a>> {
135 self.cells.chunks_mut(self.width)
136 }
137}
138
139impl<'a> Index<Pos> for Board<'a> {
140 type Output = Land<'a>;
141
142 #[inline]
144 fn index(&self, p: Pos) -> &Land<'a> {
145 &self.cells[self.index_at(p.x, p.y)]
146 }
147}
148
149impl<'a> IndexMut<Pos> for Board<'a> {
150 #[inline]
152 fn index_mut(&mut self, p: Pos) -> &mut Land<'a> {
153 let idx = self.index_at(p.x, p.y);
154 &mut self.cells[idx]
155 }
156}
157
158impl<'a> serde::Serialize for Board<'a> {
159 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
162 use serde::ser::SerializeMap;
163
164 struct Cells<'a, 'b: 'a> {
165 w: usize,
166 h: usize,
167 vec: &'a Vec<Land<'b>>,
168 }
169 impl<'a, 'b> serde::Serialize for Cells<'a, 'b> {
170 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
171 use serde::ser::SerializeSeq;
172 let mut seq = serializer.serialize_seq(Some(self.h))?;
173 for row in self.vec.chunks(self.w) {
174 seq.serialize_element(row)?;
175 }
176 seq.end()
177 }
178 }
179
180 let mut map = serializer.serialize_map(Some(4))?;
181 map.serialize_entry("width", &self.width)?;
182 map.serialize_entry("height", &self.height)?;
183 map.serialize_entry(
184 "cells",
185 &Cells {
186 w: self.width,
187 h: self.height,
188 vec: &self.cells,
189 },
190 )?;
191
192 let legends = self
194 .iter()
195 .map(|cell| (cell.kind, cell.kind.legend()))
196 .collect::<HashMap<_, _>>();
197 map.serialize_entry("legends", &legends)?;
198
199 map.end()
200 }
201}
202
203#[cfg(test)]
204mod tests {
205 use super::*;
206 use crate::land::LandKind;
207 use termcolor::ColorSpec;
208
209 #[test]
210 fn build_board() {
211 let board = Board::build(2, 3, |x, y| Land {
212 kind: LandKind::Town,
213 char: "hi",
214 color: ColorSpec::default(),
215 altitude: (x + 2 * y) as u8,
216 });
217 assert_eq!(board.width, 2);
218 assert_eq!(board.height, 3);
219 for y in 0..board.height {
220 for x in 0..board.width {
221 let land = &board[Pos { x, y }];
222 assert_eq!(land.kind, LandKind::Town);
223 assert_eq!(land.altitude, (x + 2 * y) as u8);
224 let land2 = board.at(x, y);
225 assert_eq!(land, land2);
226 }
227 }
228 }
229
230 #[test]
231 fn iter_board() {
232 let mut idx = 0;
233 let board = Board::build(2, 3, |_, _| {
234 idx += 1;
235 Land {
236 kind: LandKind::Town,
237 char: "hi",
238 color: ColorSpec::default(),
239 altitude: idx,
240 }
241 });
242 for (idx, land) in board.iter().enumerate() {
243 assert_eq!(land.kind, LandKind::Town);
244 assert_eq!(land.altitude, (idx as u8) + 1);
245 }
246 }
247
248 #[test]
249 fn iter_empty_board() {
250 let board = Board::build(0, 0, |_, _| Land::default());
251 for _ in board.iter() {
252 assert!(false);
253 }
254 }
255
256 #[test]
257 fn iter_rows() {
258 let board = Board::build(2, 3, |x, y| Land {
259 kind: LandKind::Town,
260 char: "hi",
261 color: ColorSpec::default(),
262 altitude: (x + 2 * y) as u8,
263 });
264 for row in board.rows() {
265 assert_eq!(row.len(), 2);
266 }
267 assert_eq!(board.rows().count(), 3);
268
269 let mut board = Board::build(2, 3, |x, y| Land {
270 kind: LandKind::Town,
271 char: "hi",
272 color: ColorSpec::default(),
273 altitude: (x + 2 * y) as u8,
274 });
275 for row in board.rows_mut() {
276 assert_eq!(row.len(), 2);
277 }
278 assert_eq!(board.rows_mut().count(), 3);
279 }
280}