1use std::cell::RefCell;
2use std::rc::Rc;
3
4pub mod cell;
5pub mod group;
6pub mod remove_answer;
7pub mod setting;
8pub mod shuffle;
9pub mod solve;
10
11pub struct NormalGame {
12 setting: setting::GameSetting,
13 cells: Vec<Rc<RefCell<cell::Cell>>>,
14 groups: Vec<Rc<RefCell<group::Group>>>,
15 answered_count: u32,
16}
17
18impl NormalGame {
19 pub fn new(setting: setting::GameSetting) -> NormalGame {
20 let cells = cell::create_cells(&setting);
21 let groups = group::create_groups(&cells, &setting);
22 NormalGame {
23 setting,
24 cells,
25 groups,
26 answered_count: 0,
27 }
28 }
29
30 pub fn setting(&self) -> &setting::GameSetting {
31 &self.setting
32 }
33 pub fn cells(&self) -> &Vec<Rc<RefCell<cell::Cell>>> {
34 &self.cells
35 }
36 pub fn groups(&self) -> &Vec<Rc<RefCell<group::Group>>> {
37 &self.groups
38 }
39 pub fn answered_count(&self) -> u32 {
40 self.answered_count
41 }
42 pub fn load(&mut self, issue: &str) {
44 let answer_columns: Vec<&str> = issue.split("|").collect();
45 for (y, horizontal_line) in answer_columns.iter().enumerate() {
46 let horizontal_line = horizontal_line.to_string();
47 let answers: Vec<String> = if horizontal_line.contains(',') {
48 horizontal_line.split(',').map(|s| s.to_string()).collect()
49 } else {
50 horizontal_line.chars().map(|c| format!("{}", c)).collect()
51 };
52 for (x, answer) in answers.iter().enumerate() {
53 if *answer == " " || *answer == "" {
54 continue;
55 }
56 let answer: u8 = answer.parse().expect("issue is wrong.");
57 self.set_answer(cell::Position::new(x as u8, y as u8), answer);
58 }
59 }
60 }
61
62 pub fn set_answer(&mut self, pos: cell::Position, answer: u8) {
63 let cell = self.find_cell(pos).unwrap();
64 if cell.borrow().answer().is_some() {
65 return;
66 }
67 cell.borrow_mut().set_answer(answer);
68 self.groups()
69 .iter()
70 .filter(|g| g.borrow().cells().iter().any(|c| c.borrow().pos() == pos))
71 .for_each(|g| g.borrow_mut().remove_answer_candidate(answer));
72 self.answered_count += 1;
73 }
74
75 pub fn check_status(&mut self) -> GameState {
76 if self
77 .cells()
78 .iter()
79 .filter(|c| c.borrow().answer() == None)
80 .any(|c| c.borrow().answer_candidate_count() == 0)
81 {
82 return GameState::Failure;
83 }
84
85 if self
86 .groups()
87 .iter()
88 .any(|g| g.borrow().is_duplicate_answer())
89 {
90 return GameState::Failure;
91 }
92
93 if (self.setting.side_size() as u32 * self.setting.side_size() as u32)
94 == self.answered_count
95 {
96 return if self.is_all_clear_groups_answer_candidate() {
97 GameState::Complete
98 } else {
99 GameState::Failure
100 };
101 }
102 return GameState::Solving;
103 }
104
105 fn is_all_clear_groups_answer_candidate(&self) -> bool {
106 self.groups()
107 .iter()
108 .all(|g| g.borrow().is_all_clear_answer_candidate())
109 }
110
111 pub fn find_cell(&self, pos: cell::Position) -> Option<&Rc<RefCell<cell::Cell>>> {
112 self.cells.iter().find(|c| c.borrow().pos() == pos)
113 }
114
115 pub fn to_string(&self) -> String {
116 let mut str = String::new();
117 for y in 0..self.setting.side_size() {
118 for x in 0..self.setting.side_size() {
119 let str2 = match self
120 .find_cell(cell::Position::new(x, y))
121 .unwrap()
122 .borrow()
123 .answer()
124 {
125 Some(a) => a.to_string(),
126 None => " ".to_string(),
127 };
128 str = format!("{}{}", str, str2);
129 }
130 str = format!("{}{}", str, '|');
131 }
132 str.pop();
133 return str;
134 }
135 pub fn to_string_with_comma(&self) -> String {
136 let mut str = String::new();
137 for y in 0..self.setting.side_size() {
138 for x in 0..self.setting.side_size() {
139 let str2 = match self
140 .find_cell(cell::Position::new(x, y))
141 .unwrap()
142 .borrow()
143 .answer()
144 {
145 Some(a) => a.to_string(),
146 None => " ".to_string(),
147 };
148 str = format!("{}{}{}", str, if x == 0 { "" } else { "," }, str2);
149 }
150 str = format!("{}{}", str, '|');
151 }
152 str.pop();
153 return str;
154 }
155 pub fn to_string_with_newline(&self) -> String {
156 let mut str = String::new();
157 for y in 0..self.setting.side_size() {
158 for x in 0..self.setting.side_size() {
159 let str2 = match self
160 .find_cell(cell::Position::new(x, y))
161 .unwrap()
162 .borrow()
163 .answer()
164 {
165 Some(a) => a.to_string(),
166 None => " ".to_string(),
167 };
168 str = format!("{}{}{}", str, if x == 0 { "" } else { "," }, str2);
169 }
170 str = format!("{}{}", str, '\n');
171 }
172 str.pop();
173 return str;
174 }
175}
176
177impl PartialEq for NormalGame {
178 fn eq(&self, other: &Self) -> bool {
179 self.setting().block_size() == other.setting().block_size()
180 && self.to_string_with_comma() == other.to_string_with_comma()
181 }
182}
183
184impl Clone for NormalGame {
185 fn clone(&self) -> Self {
186 let mut new_game = NormalGame::new(self.setting.clone());
187 self.cells()
188 .iter()
189 .filter(|c| c.borrow().answer() != None)
190 .for_each(|c| new_game.set_answer(c.borrow().pos(), c.borrow().answer().unwrap()));
191 new_game
192 }
193}
194
195#[derive(Debug, PartialEq, Copy, Clone)]
196pub enum GameState {
197 Solving,
198 Complete,
199 Failure,
200}
201
202#[cfg(test)]
203mod tests {
204 use super::*;
205 use crate::normal_game::setting::BlockSize;
206 use crate::normal_game::setting::GameSetting;
207 fn setting() -> GameSetting {
208 GameSetting::new(BlockSize {
209 height: 2,
210 width: 3,
211 })
212 }
213
214 #[cfg(test)]
215 mod _2_3 {
216 use super::*;
217
218 #[test]
219 fn it_answer_candidate_is_1_to_6() {
220 assert_eq!(setting().answer_candidate(), vec![1, 2, 3, 4, 5, 6]);
221 }
222 #[test]
223 fn it_has_36_cells() {
224 let game = NormalGame::new(setting());
225 assert_eq!(game.cells.len(), 36);
226 }
227 #[test]
228 fn it_has_18_groups() {
229 let game = NormalGame::new(setting());
230 assert_eq!(game.groups.len(), 18);
231 }
232 }
233 mod _3_3 {
234 use super::*;
235 fn setting() -> GameSetting {
236 GameSetting::new(BlockSize {
237 height: 3,
238 width: 3,
239 })
240 }
241
242 #[test]
243 fn it_answer_candidate_is_1_to_9() {
244 assert_eq!(
245 setting().answer_candidate(),
246 vec![1, 2, 3, 4, 5, 6, 7, 8, 9]
247 );
248 }
249 #[test]
250 fn it_has_81_cells() {
251 let game = NormalGame::new(setting());
252 assert_eq!(game.cells.len(), 81);
253 }
254 #[test]
255 fn it_has_27_groups() {
256 let game = NormalGame::new(setting());
257 assert_eq!(game.groups.len(), 27);
258 }
259 }
260 mod test_load {
261 use super::*;
262 const GAME_STRING:&str = " 7 6 |6 1 3| 54 87 | 8 4 | 1 3 5 | 9 1 | 35 12 |7 2 8| 5 9 ";
263 fn game() -> NormalGame {
264 let mut game = NormalGame::new(setting::GameSetting::new(BlockSize {
265 height: 3,
266 width: 3,
267 }));
268 game.load(GAME_STRING);
269 game
270 }
271 mod load_9_9 {
272 use super::*;
273 #[test]
274 fn has_81_cells() {
275 assert_eq!(game().cells.len(), 81);
276 }
277
278 #[test]
279 fn none_0_0() {
280 assert_eq!(
281 game()
282 .cells
283 .iter()
284 .find(|c| c.borrow().pos() == cell::Position::new(0, 0))
285 .unwrap()
287 .borrow()
288 .answer(),
289 None
290 );
291 }
292 #[test]
293 fn some_1_0() {
294 assert_eq!(
295 game()
296 .cells
297 .iter()
298 .find(|c| c.borrow().pos() == cell::Position::new(1, 0))
299 .unwrap()
301 .borrow()
302 .answer(),
303 Some(7)
304 );
305 }
306 #[test]
307 fn some_2_0() {
308 assert_eq!(
309 game()
310 .cells
311 .iter()
312 .find(|c| c.borrow().pos() == cell::Position::new(2, 0))
313 .unwrap()
315 .borrow()
316 .answer(),
317 None
318 );
319 }
320 #[test]
321 fn some_7_0() {
322 assert_eq!(
323 game()
324 .cells
325 .iter()
326 .find(|c| c.borrow().pos() == cell::Position::new(7, 0))
327 .unwrap()
329 .borrow()
330 .answer(),
331 Some(6)
332 );
333 }
334 }
335 #[test]
336 fn test_to_string() {
337 assert_eq!(game().to_string(), GAME_STRING.to_string());
338 }
339 #[test]
340 fn test_load_9_9_2() {
341 let mut game = NormalGame::new(setting::GameSetting::new(BlockSize {
342 height: 3,
343 width: 3,
344 }));
345 game.load(
346 "4 1| 5 1 4 | 8 476 | 79| 3 7 2| 59| 681 9| 4 9 7|2 5",
347 );
348 assert_eq!(game.to_string(), "4 1| 5 1 4 | 8 476 | 79 | 3 7 2 | 59 | 681 9 | 4 9 7 |2 5")
349 }
350 #[test]
351 fn test_load_12x12() {
352 let mut game = NormalGame::new(setting::GameSetting::new(BlockSize {
353 height: 3,
354 width: 4,
355 }));
356 game.load(
357 " , , ,6, , , , ,8| , , , ,12,10,5,11| , ,10,4, ,9,7, ,1,11|10, ,3, , , , , , ,7, ,12| ,5, , , ,12,10, , , ,9| ,7,8, ,9, , ,2, ,5,10| ,1,7, ,8, , ,6, ,3,4,| ,10, , , ,5,1, , , ,2|11, ,4, , , , , , ,12, ,7| , ,9,10, ,8,4, ,3,6,| , , , ,2,1,6,9,| , , ,11, , , , ,9",
358 );
359 assert_eq!(game.to_string_with_comma(), " , , ,6, , , , ,8, , , | , , , ,12,10,5,11, , , , | , ,10,4, ,9,7, ,1,11, , |10, ,3, , , , , , ,7, ,12| ,5, , , ,12,10, , , ,9, | ,7,8, ,9, , ,2, ,5,10, | ,1,7, ,8, , ,6, ,3,4, | ,10, , , ,5,1, , , ,2, |11, ,4, , , , , , ,12, ,7| , ,9,10, ,8,4, ,3,6, , | , , , ,2,1,6,9, , , , | , , ,11, , , , ,9, , , ")
360 }
361 }
362 mod set_answer {
363 use super::*;
364 #[test]
365 fn test() {
366 let mut game = NormalGame::new(setting());
367 game.set_answer(cell::Position::new(0, 0), 2);
368 assert_eq!(game.cells()[0].borrow().answer(), Some(2));
369 }
370 #[test]
371 fn remove_unanswerd_candidate_from_groups() {
372 let mut game = NormalGame::new(setting());
373 game.set_answer(cell::Position::new(0, 0), 2);
374 assert_eq!(game.cells()[1].borrow().has_answer_candidate(2), false);
375 }
376 }
377}