summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorstale <redkugelblitzin@gmail.com>2022-04-27 09:05:55 -0300
committerstale <redkugelblitzin@gmail.com>2022-04-27 09:05:55 -0300
commit29596951b18eca8fb5a8dd16c874e01000587847 (patch)
tree96a9e2a98c864bfd33377895bf9cee3be42a978a /src
parentcdb1e3711f919f22455385cce3587b973270066c (diff)
feature parity
Diffstat (limited to 'src')
-rw-r--r--src/main.rs126
1 files changed, 72 insertions, 54 deletions
diff --git a/src/main.rs b/src/main.rs
index 5970808..268fa58 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -27,12 +27,6 @@ mod minesweeper {
pub board: Board,
pub mine_count: usize,
}
- impl Display for Game {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- writeln!(f, "{}", self.board)
- }
- }
-
pub struct Board {
pub data: Vec<u8>,
pub width: usize,
@@ -55,36 +49,28 @@ mod minesweeper {
g
}
pub fn act(mut self, m: Move) -> Self {
- let kaboom = match m.t {
+ let lost_phase = | phase | {
+ match phase {
+ Phase::SafeFirstMove => unimplemented!(),
+ Phase::Run => Phase::Die,
+ _ => unreachable!(),
+ }
+ };
+
+ match m.t {
MoveType::Reveal => {
- if self.phase == Phase::SafeFirstMove {
- self.phase = Phase::Run;
- }
let kaboom: bool;
self.board = {
let mr = self.board.reveal(m.pos);
kaboom = mr.1;
mr.0
};
- kaboom
- },
- MoveType::ToggleFlag => {
- let kaboom: bool;
- self.board = {
- let mr = self.board.flag(m.pos);
- kaboom = mr.1;
- mr.0
- };
- kaboom
+ if kaboom { self.phase = lost_phase(self.phase) }
+ if self.phase == Phase::SafeFirstMove { self.phase = Phase::Run }
},
+ MoveType::ToggleFlag => self.board = self.board.flag(m.pos).0,
};
- if kaboom {
- self.phase = match self.phase {
- Phase::SafeFirstMove => unimplemented!(),
- Phase::Run => Phase::Die,
- _ => unreachable!(),
- }
- }
+
if self.board.hidden_tiles == self.mine_count {
self.phase = Phase::Win;
}
@@ -149,11 +135,7 @@ mod minesweeper {
let nyr = usize::try_from(pos.1 as i8 + oy);
let _ = nxr.and_then(|nx: usize| { nyr.and_then(|ny: usize| {
if nx > self.width - 1 || ny > self.height - 1 { return usize::try_from(-1) };
- let off = self.pos_to_off((nx,ny));
- let c = &mut self.data[off];
- if *c == HIDDEN_BIT {
- self.flood_reveal((nx, ny));
- }
+ self.flood_reveal((nx, ny));
Ok(0)
})
});
@@ -180,39 +162,57 @@ mod minesweeper {
self.data[off] ^= FLAGGED_BIT;
MoveResult { 0: self, 1: false }
}
- }
- impl Display for Board {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ pub fn render(&self, cursor: Option<(usize,usize)>) -> Vec<u8> {
+ const CYAN: &[u8] = &[27,b'[',b'3',b'6',b'm'];
+ const YELLOW: &[u8] = &[27,b'[',b'3',b'3',b'm'];
+ const GREEN: &[u8] = &[27,b'[',b'3',b'2',b'm'];
+ const RED: &[u8] = &[27,b'[',b'3',b'1',b'm'];
+ const FG: &[u8] = &[27,b'[',b'3',b'9',b'm'];
+ const ULINE: &[u8] = &[27,b'[',b'4',b'm'];
+ const REGULAR: &[u8] = &[27,b'[',b'0',b'm'];
+
+ let mut ret = vec![27,b'[',b'2',b'J',27,b'[',b'0',b'm',b'\r'];
+ let mut cur_clr = FG;
for y in 0..self.height {
for x in 0..self.width {
let c = &self.data[self.pos_to_off((x,y))];
+ let is_cursor = if let Some(cursor) = cursor { cursor.0 == x && cursor.1 == y } else { false };
+ if is_cursor { ret.extend_from_slice(ULINE); }
match *c {
- 0 => write!(f, " ")?,
- _ if *c <= 8 => write!(f, "{}", c.to_string())?,
- _ if (*c & FLAGGED_BIT) > 0 => write!(f, "F")?,
- _ if (*c & HIDDEN_BIT) > 0 => write!(f, "-")?,
- _ if (*c & CORRECT_BIT) > 0 => write!(f, "C")?,
- _ if *c == MINE_VAL => write!(f, "O")?,
- _ => write!(f, "?")?,
+ 0 => ret.push(b' '),
+ _ if *c <= 8 => { if cur_clr != FG { ret.extend_from_slice(FG); cur_clr = FG; } ret.push(b'0' + c); },
+ _ if (*c & CORRECT_BIT) > 0 => { if cur_clr != GREEN { ret.extend_from_slice(GREEN); cur_clr = GREEN; } ret.push(b'F') },
+ _ if (*c & FLAGGED_BIT) > 0 => { if cur_clr != YELLOW { ret.extend_from_slice(YELLOW); cur_clr = YELLOW; } ret.push(b'F'); },
+ _ if (*c & HIDDEN_BIT) > 0 => { if cur_clr != CYAN { ret.extend_from_slice(CYAN); cur_clr = CYAN; } ret.push(b'-'); },
+ _ if *c == MINE_VAL => { if cur_clr != RED { ret.extend_from_slice(RED); cur_clr = RED; } ret.push(b'O'); },
+ _ => ret.push(b'?'),
}
+ if is_cursor { ret.extend_from_slice(REGULAR); ret.extend_from_slice(cur_clr); }
}
- writeln!(f, "\r")?;
+ ret.push(b'\r');
+ ret.push(b'\n');
}
- Ok(())
+ ret
}
}
}
use minesweeper::*;
use std::convert::{ TryFrom, TryInto };
+use std::io::Write;
fn main() -> Result<(), io::Error> {
let board = Board::new(10,10);
let mut game = Game::new(board, 10);
- let mut cursor: (usize, usize) = (5,5);
+ let mut cursor: (usize, usize) = (0,0);
+ let stdout = io::stdout();
+ let mut lstdout = stdout.lock();
while game.phase == Phase::Run || game.phase == Phase::SafeFirstMove {
- println!("{}",game);
+ let screen = game.board.render(Some(cursor));
+ lstdout.write_all(&screen)?;
+ lstdout.flush()?;
+
let mm = playerctrl(
(cursor.0.try_into().unwrap(), cursor.1.try_into().unwrap()),
(game.board.width.try_into().unwrap(), game.board.height.try_into().unwrap()))?;
@@ -223,8 +223,8 @@ fn main() -> Result<(), io::Error> {
MetaMove::Noop => (),
}
}
-
- print!("{}", game);
+ game.board = game.board.grade();
+ lstdout.write_all(&game.board.render(None))?;
Ok(())
}
@@ -235,20 +235,38 @@ enum MetaMove {
Quit,
}
fn playerctrl(mut cursor: (isize, isize), bounds: (isize, isize)) -> io::Result<MetaMove> {
+ const ERR_STR: &str = "bad/no input";
+ let mut mov_dir = | dir: (isize,isize) | {
+ cursor.0 += dir.0;
+ cursor.1 += dir.1;
+ MetaMove::CursorMove(cursor_bounds(cursor, bounds))
+ };
let stdin = io::stdin();
let lstdin = stdin.lock();
let mut input = lstdin.bytes();
- Ok(match input.next().expect("bad/no input byte")? {
- b'w' => { cursor.1 -= 1; MetaMove::CursorMove(cursor_bounds(cursor, bounds)) },
- b's' => { cursor.1 += 1; MetaMove::CursorMove(cursor_bounds(cursor, bounds)) },
- b'a' => { cursor.0 -= 1; MetaMove::CursorMove(cursor_bounds(cursor, bounds)) },
- b'd' => { cursor.0 += 1; MetaMove::CursorMove(cursor_bounds(cursor, bounds)) },
- b'r' => MetaMove::Move(Move { t: MoveType::Reveal, pos: cursor_bounds(cursor, bounds) }),
+ Ok(match input.next().expect(ERR_STR)? {
+ b'w' => mov_dir((0,-1)),
+ b'a' => mov_dir((-1,0)),
+ b's' => mov_dir((0,1)),
+ b'd' => mov_dir((1,0)),
+ 13 => MetaMove::Move(Move { t: MoveType::Reveal, pos: cursor_bounds(cursor, bounds) }),
b'f' => MetaMove::Move(Move { t: MoveType::ToggleFlag, pos: cursor_bounds(cursor, bounds) }),
b'q' => MetaMove::Quit,
+ 27 => {
+ if input.next().expect(ERR_STR)? == b'[' {
+ match input.next().expect(ERR_STR)? {
+ b'A' => mov_dir((0,-1)),
+ b'B' => mov_dir((0,1)),
+ b'C' => mov_dir((1,0)),
+ b'D' => mov_dir((-1,0)),
+ _ => MetaMove::Noop,
+ }
+ } else { MetaMove::Noop }
+ }
v => { println!("{:?}", v); MetaMove::Noop },
})
}
+
fn cursor_bounds(mut c: (isize, isize), b: (isize, isize)) -> (usize, usize) {
if c.0 > b.0 - 1 {
c.0 = 0;