1use rand::Rng;
2use std::time::{SystemTime, UNIX_EPOCH};
3
4const DIRECTION_DIST: phf::Map<char, [i32; 2]> = phf::phf_map! {
5 'U' => [-1, 0],
6 'D' => [1, 0],
7 'L' => [0, -1],
8 'R' => [0, 1]
9};
10
11const DIRECTION_LIST: [char; 4] = ['U', 'D', 'L', 'R'];
12
13
14pub struct Puzzle {
15 pub cmds_str: String,
16 pub mode: usize,
17 pub puzzle: Vec<Vec<i32>>,
18 correct_puzzle: Vec<Vec<i32>>,
19 pub start_time: u128,
20 pub end_time: u128,
21}
22
23impl Puzzle {
24 pub fn new(mode: usize) -> Self {
25 let mut puzzle = vec![vec![0; mode]; mode];
26 let mut correct_puzzle = vec![vec![0; mode]; mode];
27 let mut num = 1;
28
29 for i in 0..mode {
30 for j in 0..mode {
31 puzzle[i][j] = num;
32 correct_puzzle[i][j] = num;
33 num += 1;
34 }
35 }
36
37 puzzle[mode - 1][mode - 1] = 0;
38 correct_puzzle[mode - 1][mode - 1] = 0;
39
40 let start_time = SystemTime::now()
41 .duration_since(UNIX_EPOCH)
42 .expect("Time went backwards")
43 .as_millis();
44
45 let mut instance = Puzzle {
46 cmds_str: String::new(),
47 mode,
48 puzzle,
49 correct_puzzle,
50 start_time,
51 end_time: 0,
52 };
53
54 instance.shuffle();
55 instance
56 }
57
58 fn find_0(&self) -> Option<(usize, usize)> {
59 for (i, row) in self.puzzle.iter().enumerate() {
60 for (j, &value) in row.iter().enumerate() {
61 if value == 0 {
62 return Some((i, j));
63 }
64 }
65 }
66 None
67 }
68
69 pub fn move_tile(&mut self, direction: char) -> Option<char> {
70 self.cmds_str.push(direction);
71 if let Some((r, c)) = self.find_0() {
72 if (r == 0 && direction == 'U')
73 || (r == self.mode - 1 && direction == 'D')
74 || (c == 0 && direction == 'L')
75 || (c == self.mode - 1 && direction == 'R')
76 {
77 return None
78 }
79
80 if let Some(&[dr, dc]) = DIRECTION_DIST.get(&direction) {
81 let rr = (r as i32 + dr) as usize;
82 let cc = (c as i32 + dc) as usize;
83
84 let num1 = self.puzzle[rr][cc];
85 self.puzzle[r][c] = num1;
86 self.puzzle[rr][cc] = 0;
87 return Some(direction)
88 }
89 }
90 return None
91 }
92
93 pub fn check(&mut self) -> bool {
94 for i in 0..self.mode {
95 for j in 0..self.mode {
96 if self.puzzle[i][j] != self.correct_puzzle[i][j] {
97 return false;
98 }
99 }
100 }
101 self.end_time = SystemTime::now()
102 .duration_since(UNIX_EPOCH)
103 .expect("Time went backwards")
104 .as_millis();
105 true
106 }
107
108 pub fn move_sequence(&mut self, sequence: &str) -> bool {
109 let uppercase = sequence.to_uppercase();
110 self.cmds_str.clear();
111 for command in uppercase.chars() {
112 self.move_tile(command);
113 if self.check() {
114 return true;
115 }
116 }
117 false
118 }
119
120 pub fn shuffle(&mut self) {
121 let mut rng = rand::thread_rng();
122 for _ in 0..1000 {
123 let random_direction = DIRECTION_LIST[rng.gen_range(0..4)];
124 self.move_tile(random_direction);
125 }
126 }
127
128 pub fn duration(&self) -> String {
129 let time_now = SystemTime::now()
130 .duration_since(UNIX_EPOCH)
131 .expect("Time went backwards")
132 .as_millis();
133 let duration = time_now - self.start_time;
134 self.format_duration(duration)
135 }
136
137 fn format_duration(&self, duration: u128) -> String {
138 let hours = duration / 3600000;
139 let minutes = (duration % 3600000) / 60000;
140 let seconds = (duration % 60000) / 1000;
141 format!("{}:{}:{}", hours, minutes, seconds)
142 }
143}
144
145#[cfg(test)]
146mod tests {
147 use super::*;
148
149 #[test]
150 fn it_works() {
151 let puzzle = Puzzle::new(4);
152 for i in 0..4{
153 println!("{:?}", puzzle.puzzle[i]);
154 }
155 println!();
156 assert_eq!(puzzle.puzzle.len(), 4);
157 }
158
159 #[test]
160 fn it_works_mode3() {
161 let mut puzzle = Puzzle::new(3);
162 for i in 0..3{
163 println!("{:?}", puzzle.puzzle[i]);
164 }
165 println!();
166 puzzle.move_tile('U');
167 for i in 0..3{
168 println!("{:?}", puzzle.puzzle[i]);
169 }
170 println!();
171 assert_eq!(puzzle.puzzle.len(), 3);
172 }
173}