1use std::{
2 collections::HashMap,
3 fmt::{Display, Formatter},
4};
5
6use crate::engine::grid::{
7 coordinate::hex::Hex,
8 piece::{Piece, PieceColor},
9};
10use serde::{Deserialize, Serialize};
11
12pub mod coordinate;
13pub mod piece;
14
15#[cfg(test)]
16#[path = "../tests/grid_tests.rs"]
17mod grid_tests;
18
19#[derive(Debug, Clone, Serialize, Deserialize)]
20pub struct Grid {
21 pub grid: HashMap<Hex, Vec<Piece>>,
22}
23
24impl Grid {
25 pub fn new() -> Grid {
26 let grid: HashMap<Hex, Vec<Piece>> = HashMap::new();
27
28 Grid { grid }
29 }
30
31 pub fn place_piece_to_hex(&mut self, piece: Piece, hex: Hex) {
32 let mut pieces: Vec<Piece> = match self.grid.get(&hex) {
33 None => Vec::new(),
34 Some(v) => v.to_vec(),
35 };
36 pieces.push(piece);
37 self.grid.insert(hex, pieces);
38 }
39
40 pub fn remove_top_piece_from_hex(&mut self, hex: Hex) -> Option<Piece> {
41 let mut pieces: Vec<Piece> = match self.grid.get(&hex) {
42 None => Vec::new(),
43 Some(v) => v.to_vec(),
44 };
45 let piece = pieces.pop();
46 self.grid.insert(hex, pieces);
47
48 piece
49 }
50
51 pub fn move_piece_from_to(&mut self, from: Hex, to: Hex) {
52 let removed_piece = self.remove_top_piece_from_hex(from);
53 if let Some(p) = removed_piece {
54 self.place_piece_to_hex(p, to)
55 };
56 }
57
58 pub fn find_top_piece(&self, hex: &Hex) -> Option<&Piece> {
59 if self.is_hex_occupied(hex) {
60 match self.grid.get(hex) {
61 Some(v) => v.last(),
62 None => None,
63 }
64 } else {
65 None
66 }
67 }
68
69 pub fn is_hex_surrounded(&self, hex: &Hex) -> bool {
70 let neighbors = hex.neighbors();
71
72 let mut is_surrended = true;
73
74 for neighbor in &neighbors {
75 let pieces = self.grid.get(neighbor);
76 is_surrended = is_surrended
77 && match pieces {
78 Some(p) => !p.is_empty(),
79 None => false,
80 }
81 }
82
83 is_surrended
84 }
85
86 pub fn is_hex_neighbor_of(&self, hex: &Hex, of: &Hex) -> bool {
87 let mut is_neighbor = false;
88
89 for neighbor in hex.neighbors() {
90 is_neighbor = is_neighbor || neighbor == *of;
91 }
92
93 is_neighbor
94 }
95
96 pub fn is_hex_occupied(&self, hex: &Hex) -> bool {
97 let pieces = self.grid.get(hex);
98
99 match pieces {
100 Some(p) => !p.is_empty(),
101 None => false,
102 }
103 }
104
105 pub fn is_hex_alone(&self, hex: &Hex) -> bool {
106 let neighbors = hex.neighbors();
107
108 let mut is_alone = true;
109
110 for neighbor in neighbors {
111 is_alone = is_alone && !self.is_hex_occupied(&neighbor);
112 }
113
114 is_alone
115 }
116
117 pub fn is_hex_of_color(&self, hex: &Hex, piece_color: &PieceColor) -> bool {
118 let piece = self.find_top_piece(hex);
119
120 match piece {
121 Some(p) => p.p_color == *piece_color,
122 None => false,
123 }
124 }
125
126 pub fn is_hex_neighbors_only_piece_color(&self, hex: &Hex, piece_color: &PieceColor) -> bool {
127 let mut is_hex_surrounded_by_piece_color = true;
128
129 if !self.is_hex_alone(hex) {
130 for neighbor in hex.neighbors() {
131 if self.is_hex_occupied(&neighbor) && !self.is_hex_of_color(&neighbor, piece_color) {
132 is_hex_surrounded_by_piece_color = false;
133 }
134 }
135 } else {
136 is_hex_surrounded_by_piece_color = false;
137 }
138
139 is_hex_surrounded_by_piece_color
140 }
141
142 pub fn number_of_pieces(&self) -> usize {
143 let mut count = 0;
144 for vec in self.grid.values() {
145 count += vec.len()
146 }
147
148 count
149 }
150}
151
152impl Default for Grid {
153 fn default() -> Self {
154 Self::new()
155 }
156}
157
158impl Display for Grid {
159 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
160 let mut initialized = false;
161 let mut min_q = 0;
162 let mut max_q = 0;
163 let mut min_r = 0;
164 let mut max_r = 0;
165
166 for key in self.grid.keys() {
167 if !initialized {
168 min_q = key.q;
169 max_q = key.q;
170 min_r = key.r;
171 max_r = key.r;
172 initialized = true;
173 } else {
174 if min_q > key.q {
175 min_q = key.q;
176 } else if max_q < key.q {
177 max_q = key.q;
178 }
179
180 if min_r > key.r {
181 min_r = key.r;
182 } else if max_r < key.r {
183 max_r = key.r;
184 }
185 }
186 }
187
188 let mut count_r = -1;
189
190 write!(f, "GRID START")?;
191 for r in min_r..=max_r {
192 for m in 1..=2 {
193 writeln!(f)?;
194
195 if m % 2 == 1 {
196 count_r += 1;
197 }
198
199 for _i in 0..count_r {
200 write!(f, " ")?;
201 }
202
203 for q in min_q..=max_q {
204 let hex = Hex::new(q, r);
205
206 let occupied = self.is_hex_occupied(&hex);
207
208 if occupied {
209 if m % 2 == 0 {
210 write!(f, "{}", hex)?;
211 } else {
212 let piece = self.find_top_piece(&hex);
213 match piece {
214 Some(p) => write!(f, " {} ", p)?,
215 None => write!(f, " NA ")?,
216 }
217 }
218 } else if m % 2 == 1 {
219 write!(f, " __ ")?;
220 } else {
221 write!(f, "{}", hex)?;
222 }
223 }
224 }
225 }
226
227 write!(f, "\nGRID END")
228 }
229}