diff --git a/src/main.rs b/src/main.rs index e7a11a9..3ee90a6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,212 @@ -fn main() { - println!("Hello, world!"); +use std::fmt::Display; +use std::ops::Index; +use std::ops::IndexMut; +use std::iter; +use crossterm::event::Event; +use crossterm::event::KeyEvent; +use crossterm::event::KeyCode; +use crossterm::event::KeyModifiers; +use crossterm::event; +use crossterm::cursor::*; +use std::io::stdout; + +/// board size is 8*8 with 10 bombs +#[derive(Debug, Default)] +struct Board { + board: [[Status; 8]; 8], +} +impl Index for Board { + type Output = Status; + fn index(&self, index: Point) -> &Self::Output { + &self.board[index.0][8-index.1] + } +} +impl IndexMut for Board { + fn index_mut(&mut self, index: Point) -> &mut Self::Output { + &mut self.board[index.0][8-index.1] + } +} +impl Board { + fn get(&self, idx:Point) -> Option<&Status> { + self.board.get(idx.0)?.get(7-idx.1) + } + fn get_mut(&mut self, idx:Point) -> Option<&mut Status> { + self.board.get_mut(idx.0)?.get_mut(7-idx.1) + } + fn insert_bomb(&mut self, idx:Point) { + let all = Board::all_points(); + // all.filter(|a|idx.is_adjacent(&a)).filter_map(|a|self.get_mut(a)).filter_map(|a|a.val()).for_each(|a| {*a += 1;} ); + for a in all.filter(|a|idx.is_adjacent(&a)) { + let val = self.get_mut(a).map(|a| a.val()).flatten(); + match val { + Some(a) => {*a+=1;} + _ => (), + } + } + self[idx] = Status::Bomb; + + } + fn all_points() -> impl Iterator { + const WIDTH: usize = 8; + const HIGHT: usize = 8; + let x = (0..WIDTH) + .cycle() + .take(WIDTH*HIGHT); + let y = (0..(WIDTH*HIGHT)).map(|a| a / WIDTH); + x.zip(y).map(|(x, y)| Point(x, y)) + } +} +impl Display for Board { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + /* for (i, n) in self.board.iter().enumerate() { + if i == 7 { + return write!(f, "{}{}{}{}{}{}{}{}", n[0], n[1], n[2], n[3], n[4], n[5], n[6], n[7]) + } else { + writeln!(f, "{}{}{}{}{}{}{}{}", n[0], n[1], n[2], n[3], n[4], n[5], n[6], n[7])?; + } + return Ok(()); + } */ + write!(f, "\ + \r{} {} {} {} {} {} {} {}\n\r\ + {} {} {} {} {} {} {} {}\n\r\ + {} {} {} {} {} {} {} {}\n\r\ + {} {} {} {} {} {} {} {}\n\r\ + {} {} {} {} {} {} {} {}\n\r\ + {} {} {} {} {} {} {} {}\n\r\ + {} {} {} {} {} {} {} {}\n\r\ + {} {} {} {} {} {} {} {}\n\r", + self.board[0][7], self.board[1][7], self.board[2][7], self.board[3][7], self.board[4][7], self.board[5][7], self.board[6][7], self.board[7][7], + self.board[0][6], self.board[1][6], self.board[2][6], self.board[3][6], self.board[4][6], self.board[5][6], self.board[6][6], self.board[7][6], + self.board[0][5], self.board[5][1], self.board[5][2], self.board[5][3], self.board[5][4], self.board[5][5], self.board[5][6], self.board[7][5], + self.board[4][0], self.board[4][1], self.board[4][2], self.board[4][3], self.board[4][4], self.board[4][5], self.board[4][6], self.board[7][4], + self.board[3][0], self.board[3][1], self.board[3][2], self.board[3][3], self.board[3][4], self.board[3][5], self.board[3][6], self.board[3][7], + self.board[2][0], self.board[2][1], self.board[2][2], self.board[2][3], self.board[2][4], self.board[2][5], self.board[2][6], self.board[2][7], + self.board[1][0], self.board[1][1], self.board[1][2], self.board[1][3], self.board[1][4], self.board[1][5], self.board[1][6], self.board[1][7], + self.board[0][0], self.board[0][1], self.board[0][2], self.board[0][3], self.board[0][4], self.board[0][5], self.board[0][6], self.board[0][7], + ) + } +} +#[derive(Debug, Clone)] +enum Status { + Hidden(u8), + Revealed(u8), + /// bombs are always hidden + Bomb, +} +impl Default for Status { + fn default() -> Self { + Self::Hidden(0) + } +} +impl Display for Status { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let val = match self { + Self::Hidden(_) => '*', + Self::Revealed(n) => num_to_char(*n), + Self::Bomb => '*' + }; + write!(f, "{}", val) + } +} +impl Status { + fn val(&mut self) -> Option<&mut u8> { + match self { + Self::Hidden(ref mut val) => Some(val), + Self::Revealed(_) => None, + Self::Bomb => None, + } + } +} +/// (0, 0) is bottom left +#[derive(Debug, Clone)] +pub struct Point(usize, usize); +impl Point { + fn is_adjacent(&self, rhs: &Self) -> bool { + (-1..=1).contains(&(self.0 as isize-rhs.0 as isize)) + && (-1..=1).contains(&(self.1 as isize-rhs.1 as isize)) + } +} +fn main() { + let mut board = Board::default(); + crossterm::terminal::enable_raw_mode(); + print!("\n"); + print!("{}", board); + board.insert_bomb(Point(5, 5)); + let test = board.get_mut(Point(0, 0)).unwrap(); + *test = Status::Revealed(0); + loop { + if let Ok(Event::Key(KeyEvent { code, modifiers, kind:_, state: _ })) = event::read() { + let cursor = cursor(); + match (code, modifiers == KeyModifiers::CONTROL) { + (KeyCode::Enter, false) => { + let selected = board.get_mut(cursor.clone()); + match selected.as_deref().cloned() { + Some(Status::Hidden(a)) => { + let selected = selected.unwrap(); + *selected = Status::Revealed(a); + // print!("hidden"); + } + Some(Status::Bomb) => { + crossterm::execute!(stdout(), MoveDown(8)); + // print!("KABOOM"); + break + } + None | Some(Status::Revealed(_)) => { + print!("do_nothing:{:?}\n\r", cursor); + }, + } + clear(10, &board); + } + (KeyCode::Enter, true) => {} + (KeyCode::Left, _) => { + crossterm::execute!(stdout(), MoveLeft(1)); + } + (KeyCode::Down, _) => { + crossterm::execute!(stdout(), MoveDown(1)); + } + (KeyCode::Right, _) => { + crossterm::execute!(stdout(), MoveRight(1)); + } + (KeyCode::Up, _) => { + crossterm::execute!(stdout(), MoveUp(1)); + } + (KeyCode::Char('c'), _) => { + crossterm::execute!(stdout(), MoveDown(8)); + break + } + _ => {} + } + } + } +} +fn num_to_char(num:u8) ->char { + match num { + 0 => '0', + 1 => '1', + 2 => '2', + 3 => '3', + 4 => '4', + 5 => '5', + 6 => '6', + 7 => '7', + 8 => '8', + 9 => '9', + _ => ' ', + } +} +fn cursor() -> Point { + let (_, row) = crossterm::terminal::size().unwrap(); + let (col, crow) = crossterm::cursor::position().unwrap(); + let out = Point(( col ) as usize / 2, ( row-crow ) as usize); + out +} +/// row is rows from bottom +fn clear(row: u16, board: &Board) { + let (_, total) = crossterm::terminal::size().unwrap(); + let row = total-row; + crossterm::execute!(stdout(), SavePosition, MoveToRow(row)); + print!("\u{1b}[J"); // clear from cursor to end of screen + crossterm::execute!(stdout(), MoveDown(1)); + print!("{}", board); // clear from cursor to end of screen + crossterm::execute!(stdout(), RestorePosition); }