win condition and colors
This commit is contained in:
117
src/main.rs
117
src/main.rs
@@ -11,7 +11,7 @@ use std::io;
|
|||||||
|
|
||||||
const WIDTH: usize = 20;
|
const WIDTH: usize = 20;
|
||||||
const HEIGHT: usize = 20;
|
const HEIGHT: usize = 20;
|
||||||
const MINE_COUNT: u32 = 35;
|
const MINE_COUNT: usize = 50;
|
||||||
const TEST_POS: [(i8, i8); 8] = [
|
const TEST_POS: [(i8, i8); 8] = [
|
||||||
(-1, 1),
|
(-1, 1),
|
||||||
(0, 1),
|
(0, 1),
|
||||||
@@ -22,22 +22,52 @@ const TEST_POS: [(i8, i8); 8] = [
|
|||||||
(0, -1),
|
(0, -1),
|
||||||
(1, -1),
|
(1, -1),
|
||||||
];
|
];
|
||||||
|
const MINE: &str = "\x1b[48;2;0;0;0m \x1b[0m";
|
||||||
|
const FLAG: &str = "\x1b[48;2;255;0;0m \x1b[0m";
|
||||||
|
const EMPTY: &str = "\x1b[48;2;255;255;255m \x1b[0m";
|
||||||
|
const HIDDEN: &str = "\x1b[48;2;100;100;100m \x1b[0m";
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
print!("\x1b[2J\x1b[H");
|
print!("\x1b[2J\x1b[H");
|
||||||
let mut board = Board::new(MINE_COUNT);
|
let mut board = Board::new(MINE_COUNT);
|
||||||
board.calculate();
|
|
||||||
let mut stdout = io::stdout();
|
let mut stdout = io::stdout();
|
||||||
|
let mut rng = rand::thread_rng();
|
||||||
|
|
||||||
|
board.render();
|
||||||
|
board.calculate();
|
||||||
|
|
||||||
|
if MINE_COUNT != WIDTH * HEIGHT {
|
||||||
|
loop {
|
||||||
|
let input = input(&mut stdout);
|
||||||
|
if input.button != MouseButton::Left
|
||||||
|
|| !validate_pos(input.pos.x as i8, input.pos.y as i8)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let cell = &mut board.0[input.pos.y][input.pos.x];
|
||||||
|
if cell.kind != CellKind::Mine {
|
||||||
|
handle_input(&input, &mut board);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Since mine placement is updated, recalculation is needed.
|
||||||
|
board.spawn_mine(&mut rng, 0..WIDTH * HEIGHT - MINE_COUNT);
|
||||||
|
board.0[input.pos.y][input.pos.x].kind = CellKind::MineCount(0);
|
||||||
|
board.calculate();
|
||||||
|
handle_input(&input, &mut board);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
board.calculate();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
board.render();
|
board.render();
|
||||||
stdout.execute(EnableMouseCapture).unwrap();
|
let input = input(&mut stdout);
|
||||||
let input = input();
|
|
||||||
stdout.execute(DisableMouseCapture).unwrap();
|
|
||||||
handle_input(&input, &mut board);
|
handle_input(&input, &mut board);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Board([[Cell; 20]; 20]);
|
struct Board([[Cell; WIDTH]; HEIGHT]);
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
struct Cell {
|
struct Cell {
|
||||||
@@ -70,20 +100,26 @@ struct Position {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Board {
|
impl Board {
|
||||||
fn new(mine_count: u32) -> Self {
|
fn new(mine_count: usize) -> Self {
|
||||||
let mut rng = rand::thread_rng();
|
let mut rng = rand::thread_rng();
|
||||||
let mut board = Board(
|
let mut board = Board(
|
||||||
[[Cell {
|
[[Cell {
|
||||||
kind: CellKind::MineCount(0),
|
kind: CellKind::MineCount(0),
|
||||||
visibility: Visibility::Hidden,
|
visibility: Visibility::Hidden,
|
||||||
}; 20]; 20],
|
}; WIDTH]; HEIGHT],
|
||||||
);
|
);
|
||||||
for i in 0..mine_count {
|
for i in 0..mine_count {
|
||||||
let c = rng.gen_range(0..20 * 20 - i);
|
board.spawn_mine(&mut rng, 0..WIDTH * HEIGHT - i);
|
||||||
|
}
|
||||||
|
board
|
||||||
|
}
|
||||||
|
|
||||||
|
fn spawn_mine(&mut self, rng: &mut ThreadRng, range: std::ops::Range<usize>) {
|
||||||
|
let c = rng.gen_range(range);
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
for line in board.0.iter_mut() {
|
for line in self.0.iter_mut() {
|
||||||
for cell in line.iter_mut() {
|
for cell in line.iter_mut() {
|
||||||
if let CellKind::MineCount(_) = cell.kind {
|
if cell.kind != CellKind::Mine {
|
||||||
if i == c {
|
if i == c {
|
||||||
cell.kind = CellKind::Mine;
|
cell.kind = CellKind::Mine;
|
||||||
}
|
}
|
||||||
@@ -92,8 +128,6 @@ impl Board {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
board
|
|
||||||
}
|
|
||||||
|
|
||||||
fn calculate(&mut self) {
|
fn calculate(&mut self) {
|
||||||
let mut changes = vec![];
|
let mut changes = vec![];
|
||||||
@@ -122,11 +156,7 @@ impl Board {
|
|||||||
fn inside(&self, x: i8, y: i8) -> bool {
|
fn inside(&self, x: i8, y: i8) -> bool {
|
||||||
if validate_pos(x, y) {
|
if validate_pos(x, y) {
|
||||||
let cell = self.0[y as usize][x as usize];
|
let cell = self.0[y as usize][x as usize];
|
||||||
if let CellKind::MineCount(n) = cell.kind {
|
return cell.visibility == Visibility::Hidden && cell.kind == CellKind::MineCount(0);
|
||||||
if cell.visibility == Visibility::Hidden && n == 0 {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
@@ -187,6 +217,33 @@ impl Board {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn game_over(&mut self) {
|
||||||
|
self.0
|
||||||
|
.iter_mut()
|
||||||
|
.flatten()
|
||||||
|
.for_each(|c| c.visibility = Visibility::Visible);
|
||||||
|
self.render();
|
||||||
|
disable_raw_mode().unwrap();
|
||||||
|
println!("Game Over!");
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn win_condition(&mut self) {
|
||||||
|
for c in self.0.iter().flatten() {
|
||||||
|
if c.kind != CellKind::Mine && c.visibility == Visibility::Hidden {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.0
|
||||||
|
.iter_mut()
|
||||||
|
.flatten()
|
||||||
|
.for_each(|c| c.visibility = Visibility::Visible);
|
||||||
|
self.render();
|
||||||
|
disable_raw_mode().unwrap();
|
||||||
|
println!("Game Won!");
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
fn render(&self) {
|
fn render(&self) {
|
||||||
let mut s = String::new();
|
let mut s = String::new();
|
||||||
s.push_str("\x1b[2J\x1b[H");
|
s.push_str("\x1b[2J\x1b[H");
|
||||||
@@ -194,11 +251,14 @@ impl Board {
|
|||||||
for cell in line {
|
for cell in line {
|
||||||
match cell.visibility {
|
match cell.visibility {
|
||||||
Visibility::Visible => match cell.kind {
|
Visibility::Visible => match cell.kind {
|
||||||
CellKind::Mine => s.push('*'),
|
CellKind::Mine => s.push_str(MINE),
|
||||||
CellKind::MineCount(n) => s.push((n + b'0') as char),
|
CellKind::MineCount(0) => s.push_str(EMPTY),
|
||||||
|
CellKind::MineCount(n) => s.push_str(&format!(
|
||||||
|
"\x1b[48;2;255;255;255m\x1b[38;2;0;0;0m{n} \x1b[0m"
|
||||||
|
)),
|
||||||
},
|
},
|
||||||
Visibility::Hidden => s.push('#'),
|
Visibility::Hidden => s.push_str(HIDDEN),
|
||||||
Visibility::Flag => s.push('F'),
|
Visibility::Flag => s.push_str(FLAG),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
s.push('\n');
|
s.push('\n');
|
||||||
@@ -209,14 +269,17 @@ impl Board {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn input() -> Input {
|
fn input(stdout: &mut io::Stdout) -> Input {
|
||||||
|
stdout.execute(EnableMouseCapture).unwrap();
|
||||||
loop {
|
loop {
|
||||||
if poll(std::time::Duration::from_secs(5)).unwrap() {
|
if poll(std::time::Duration::from_secs(5)).unwrap() {
|
||||||
while let Ok(r) = read() {
|
while let Ok(r) = read() {
|
||||||
if let Event::Mouse(event) = r {
|
if let Event::Mouse(event) = r {
|
||||||
if let MouseEventKind::Down(button) = event.kind {
|
if let MouseEventKind::Down(button) = event.kind {
|
||||||
if button == MouseButton::Left || button == MouseButton::Right {
|
if button == MouseButton::Left || button == MouseButton::Right {
|
||||||
let (y, x) = (HEIGHT - event.row as usize - 1, event.column as usize);
|
let (y, x) =
|
||||||
|
(HEIGHT - event.row as usize - 1, (event.column / 2) as usize);
|
||||||
|
stdout.execute(DisableMouseCapture).unwrap();
|
||||||
return Input {
|
return Input {
|
||||||
button,
|
button,
|
||||||
pos: Position { x, y },
|
pos: Position { x, y },
|
||||||
@@ -234,7 +297,7 @@ fn input() -> Input {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn handle_input(input: &Input, board: &mut Board) {
|
fn handle_input(input: &Input, board: &mut Board) {
|
||||||
if (input.pos.x) < WIDTH && (input.pos.y) < HEIGHT {
|
if validate_pos(input.pos.x as i8, input.pos.y as i8) {
|
||||||
if input.button == MouseButton::Left {
|
if input.button == MouseButton::Left {
|
||||||
board.fill(input.pos.x as i8, input.pos.y as i8);
|
board.fill(input.pos.x as i8, input.pos.y as i8);
|
||||||
board.pad_fill();
|
board.pad_fill();
|
||||||
@@ -242,6 +305,10 @@ fn handle_input(input: &Input, board: &mut Board) {
|
|||||||
if cell.visibility == Visibility::Hidden {
|
if cell.visibility == Visibility::Hidden {
|
||||||
cell.visibility = Visibility::Visible;
|
cell.visibility = Visibility::Visible;
|
||||||
}
|
}
|
||||||
|
if cell.kind == CellKind::Mine {
|
||||||
|
board.game_over();
|
||||||
|
}
|
||||||
|
board.win_condition();
|
||||||
} else if input.button == MouseButton::Right {
|
} else if input.button == MouseButton::Right {
|
||||||
let cell = &mut board.0[input.pos.y][input.pos.x];
|
let cell = &mut board.0[input.pos.y][input.pos.x];
|
||||||
if cell.visibility == Visibility::Hidden {
|
if cell.visibility == Visibility::Hidden {
|
||||||
|
Reference in New Issue
Block a user