├── README.md ├── Cargo.toml ├── .gitignore └── src └── lib.rs /README.md: -------------------------------------------------------------------------------- 1 | # LightsOut 2 | Lights Out solver 3 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "LightsOut" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | /target/ 4 | 5 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 6 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 7 | Cargo.lock 8 | 9 | # These are backup files generated by rustfmt 10 | **/*.rs.bk 11 | 12 | 13 | # Added by cargo 14 | # 15 | # already existing elements were commented out 16 | 17 | /target 18 | #Cargo.lock 19 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | use std::fmt; 2 | use std::collections::{VecDeque, HashSet}; 3 | 4 | #[derive(Debug, Hash, PartialEq, Eq, Clone)] 5 | pub struct LightsOutPuzzle { 6 | board: Vec>, 7 | rows: usize, 8 | columns: usize, 9 | } 10 | 11 | impl LightsOutPuzzle { 12 | pub fn new(rows: usize, columns: usize) -> Self { 13 | LightsOutPuzzle { 14 | board: vec![vec![false; columns]; rows], 15 | rows, 16 | columns, 17 | } 18 | } 19 | 20 | fn get_board(&'static self) -> &'static Vec> { 21 | &self.board 22 | } 23 | 24 | fn make_move(mut self, coord: &(usize, usize)) -> Result<(), LocationError> { 25 | if coord.0 >= self.rows || coord.1 >= self.columns { 26 | return Err(LocationError { 27 | coordinates: *coord, 28 | message: String::from("Bad coordinates for a move"), 29 | }) 30 | } 31 | self.board[coord.0][coord.1] ^= self.board[coord.0][coord.1]; 32 | if coord.0 > 0 { 33 | self.board[coord.0 - 1][coord.1] ^= self.board[coord.0 - 1][coord.1]; 34 | } 35 | if coord.0 < self.rows - 1 { 36 | self.board[coord.0 + 1][coord.1] ^= self.board[coord.0 + 1][coord.1]; 37 | } 38 | if coord.1 > 0 { 39 | self.board[coord.0][coord.1 - 1] ^= self.board[coord.0][coord.1 - 1]; 40 | } 41 | if coord.1 < self.columns - 1 { 42 | self.board[coord.0][coord.1 + 1] ^= self.board[coord.0][coord.1 + 1]; 43 | } 44 | Ok(()) 45 | } 46 | 47 | fn solved(&self) -> bool { 48 | self.board.iter() 49 | .flatten() 50 | .all(|x| *x) 51 | } 52 | 53 | fn successors(&self) -> Vec<(usize, usize)> { 54 | (0..self.rows).flat_map(|x| (0..self.columns) 55 | .map(move |y| (x, y))) 56 | .collect() 57 | } 58 | 59 | pub fn solve(&self) -> Option> { 60 | let mut steps = vec![]; 61 | if self.solved() { return Some(steps) } 62 | 63 | let mut frontier: VecDeque = VecDeque::new(); 64 | let mut visited: HashSet = HashSet::new(); 65 | while !frontier.is_empty() { 66 | let current = frontier.pop_back().unwrap(); 67 | for mv in current.successors() { 68 | let child = current.copy(); 69 | child.make_move(&mv); 70 | if !visited.contains(&child) { 71 | 72 | } 73 | } 74 | } 75 | Some(vec![]) 76 | } 77 | } 78 | 79 | impl fmt::Display for LightsOutPuzzle { 80 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 81 | let mut res = String::from("\n"); 82 | for i in 0..self.rows { 83 | for _ in 0..self.columns - 1 { res.push('-'); } 84 | res.push('\n'); 85 | for j in 0..self.columns - 1 { 86 | if self.board[i][j] { res.push_str("💡│"); } 87 | else { res.push_str("🛑│"); } 88 | } 89 | res.push('\n'); 90 | } 91 | for _ in 0..self.columns - 1 { res.push('-'); } 92 | Ok(()) 93 | } 94 | } 95 | 96 | #[derive(Debug)] 97 | struct LocationError { 98 | coordinates: (usize, usize), 99 | message: String, 100 | } 101 | 102 | 103 | #[cfg(test)] 104 | mod tests { 105 | #[test] 106 | fn it_works() { 107 | let result = 2 + 2; 108 | assert_eq!(result, 4); 109 | } 110 | } 111 | --------------------------------------------------------------------------------