This commit is contained in:
Robot 2024-05-03 14:55:00 -05:00
parent fc2d7822d4
commit 312f971e5d
1 changed files with 211 additions and 2 deletions

View File

@ -1,3 +1,212 @@
fn main() { use std::fmt::Display;
println!("Hello, world!"); 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<Point> for Board {
type Output = Status;
fn index(&self, index: Point) -> &Self::Output {
&self.board[index.0][8-index.1]
}
}
impl IndexMut<Point> 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<Item = Point> {
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);
} }