June 2018 Update
This commit is contained in:
parent
ba8067c3b7
commit
22f33d4004
5278 changed files with 84726 additions and 14379 deletions
316
Task/Minesweeper-game/Rust/minesweeper-game.rust
Normal file
316
Task/Minesweeper-game/Rust/minesweeper-game.rust
Normal file
|
|
@ -0,0 +1,316 @@
|
|||
extern crate rand;
|
||||
|
||||
use std::io;
|
||||
use std::io::Write;
|
||||
|
||||
fn main() {
|
||||
|
||||
use minesweeper::{MineSweeper, GameStatus};
|
||||
|
||||
let mut width = 6;
|
||||
let mut height = 4;
|
||||
let mut mine_perctg = 10;
|
||||
let mut game = MineSweeper::new(width, height, mine_perctg);
|
||||
|
||||
loop {
|
||||
let mut command = String::new();
|
||||
|
||||
println!(
|
||||
"\n\
|
||||
M I N E S W E E P E R\n\
|
||||
\n\
|
||||
Commands: \n\
|
||||
line col - reveal line,col \n\
|
||||
m line col - mark line,col \n\
|
||||
q - quit\n\
|
||||
n - new game\n\
|
||||
n width height perc - new game size and mine percentage\n"
|
||||
);
|
||||
|
||||
game.print();
|
||||
print!("> ");
|
||||
io::stdout().flush().unwrap();
|
||||
while let Ok(_) = io::stdin().read_line(&mut command) {
|
||||
let mut command_ok = false;
|
||||
{
|
||||
let values: Vec<&str> = command.trim().split(' ').collect();
|
||||
if values.len() == 1 {
|
||||
if values[0] == "q" {
|
||||
println!("Goodbye");
|
||||
return;
|
||||
} else if values[0] == "n" {
|
||||
println!("New game");
|
||||
game = MineSweeper::new(width, height, mine_perctg);
|
||||
command_ok = true;
|
||||
}
|
||||
} else if values.len() == 2 {
|
||||
if let (Ok(x), Ok(y)) = (
|
||||
values[0].parse::<usize>(),
|
||||
values[1].parse::<usize>(),
|
||||
)
|
||||
{
|
||||
game.play(x - 1, y - 1);
|
||||
|
||||
match game.game_status {
|
||||
GameStatus::Won => println!("You won!"),
|
||||
GameStatus::Lost => println!("You lost!"),
|
||||
_ => (),
|
||||
}
|
||||
command_ok = true;
|
||||
}
|
||||
} else if values.len() == 3 {
|
||||
if values[0] == "m" {
|
||||
if let (Ok(x), Ok(y)) = (
|
||||
values[1].parse::<usize>(),
|
||||
values[2].parse::<usize>(),
|
||||
)
|
||||
{
|
||||
game.mark(x - 1, y - 1);
|
||||
command_ok = true;
|
||||
}
|
||||
}
|
||||
} else if values.len() == 4 {
|
||||
if values[0] == "n" {
|
||||
if let (Ok(new_width), Ok(new_height), Ok(new_mines_perctg)) =
|
||||
(
|
||||
values[1].parse::<usize>(),
|
||||
values[2].parse::<usize>(),
|
||||
values[3].parse::<usize>(),
|
||||
)
|
||||
{
|
||||
width = new_width;
|
||||
height = new_height;
|
||||
mine_perctg = new_mines_perctg;
|
||||
game = MineSweeper::new(width, height, mine_perctg);
|
||||
command_ok = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if command_ok {
|
||||
game.print();
|
||||
} else {
|
||||
println!("Invalid command");
|
||||
}
|
||||
|
||||
print!("> ");
|
||||
io::stdout().flush().unwrap();
|
||||
command.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub mod minesweeper {
|
||||
|
||||
pub struct MineSweeper {
|
||||
cell: [[Cell; 100]; 100],
|
||||
pub game_status: GameStatus,
|
||||
mines: usize,
|
||||
width: usize,
|
||||
height: usize,
|
||||
revealed_count: usize,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
struct Cell {
|
||||
content: CellContent,
|
||||
mark: Mark,
|
||||
revealed: bool,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
enum CellContent {
|
||||
Empty,
|
||||
Mine,
|
||||
MineNeighbour { count: u8 },
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
enum Mark {
|
||||
None,
|
||||
Mine,
|
||||
}
|
||||
|
||||
pub enum GameStatus {
|
||||
InGame,
|
||||
Won,
|
||||
Lost,
|
||||
}
|
||||
|
||||
extern crate rand;
|
||||
|
||||
use std::cmp::max;
|
||||
use std::cmp::min;
|
||||
use self::rand::Rng;
|
||||
use self::CellContent::*;
|
||||
use self::GameStatus::*;
|
||||
|
||||
impl MineSweeper {
|
||||
pub fn new(width: usize, height: usize, percentage_of_mines: usize) -> MineSweeper {
|
||||
let mut game = MineSweeper {
|
||||
cell: [[Cell {
|
||||
content: Empty,
|
||||
mark: Mark::None,
|
||||
revealed: false,
|
||||
}; 100]; 100],
|
||||
game_status: InGame,
|
||||
mines: (width * height * percentage_of_mines) / 100,
|
||||
width: width,
|
||||
height: height,
|
||||
revealed_count: 0,
|
||||
};
|
||||
game.put_mines();
|
||||
game.calc_neighbours();
|
||||
game
|
||||
}
|
||||
|
||||
pub fn play(&mut self, x: usize, y: usize) {
|
||||
match self.game_status {
|
||||
InGame => {
|
||||
if !self.cell[x][y].revealed {
|
||||
match self.cell[x][y].content {
|
||||
Mine => {
|
||||
self.cell[x][y].revealed = true;
|
||||
self.revealed_count += 1;
|
||||
self.game_status = Lost;
|
||||
}
|
||||
Empty => {
|
||||
self.flood_fill_reveal(x, y);
|
||||
if self.revealed_count + self.mines == self.width * self.height {
|
||||
self.game_status = Won;
|
||||
}
|
||||
}
|
||||
MineNeighbour { .. } => {
|
||||
self.cell[x][y].revealed = true;
|
||||
self.revealed_count += 1;
|
||||
if self.revealed_count + self.mines == self.width * self.height {
|
||||
self.game_status = Won;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => println!("Game has ended"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mark(&mut self, x: usize, y: usize) {
|
||||
self.cell[x][y].mark = match self.cell[x][y].mark {
|
||||
Mark::None => Mark::Mine,
|
||||
Mark::Mine => Mark::None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn print(&self) {
|
||||
print!("┌");
|
||||
for _ in 0..self.width {
|
||||
print!("─");
|
||||
}
|
||||
println!("┐");
|
||||
for y in 0..self.height {
|
||||
print!("│");
|
||||
for x in 0..self.width {
|
||||
self.cell[x][y].print();
|
||||
}
|
||||
println!("│");
|
||||
}
|
||||
print!("└");
|
||||
for _ in 0..self.width {
|
||||
print!("─");
|
||||
}
|
||||
println!("┘");
|
||||
}
|
||||
|
||||
fn put_mines(&mut self) {
|
||||
let mut rng = rand::thread_rng();
|
||||
for _ in 0..self.mines {
|
||||
while let (x, y, true) = (
|
||||
rng.gen::<usize>() % self.width,
|
||||
rng.gen::<usize>() % self.height,
|
||||
true,
|
||||
)
|
||||
{
|
||||
match self.cell[x][y].content {
|
||||
Mine => continue,
|
||||
_ => {
|
||||
self.cell[x][y].content = Mine;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn calc_neighbours(&mut self) {
|
||||
for x in 0..self.width {
|
||||
for y in 0..self.height {
|
||||
if !self.cell[x][y].is_bomb() {
|
||||
let mut adjacent_bombs = 0;
|
||||
|
||||
for i in max(x as isize - 1, 0) as usize..min(x + 2, self.width) {
|
||||
for j in max(y as isize - 1, 0) as usize..min(y + 2, self.height) {
|
||||
adjacent_bombs += if self.cell[i][j].is_bomb() { 1 } else { 0 };
|
||||
}
|
||||
}
|
||||
|
||||
if adjacent_bombs == 0 {
|
||||
self.cell[x][y].content = Empty;
|
||||
} else {
|
||||
self.cell[x][y].content = MineNeighbour { count: adjacent_bombs };
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn flood_fill_reveal(&mut self, x: usize, y: usize) {
|
||||
let mut stack = Vec::<(usize, usize)>::new();
|
||||
stack.push((x, y));
|
||||
|
||||
while let Some((i, j)) = stack.pop() {
|
||||
if self.cell[i][j].revealed {
|
||||
continue;
|
||||
}
|
||||
self.cell[i][j].revealed = true;
|
||||
self.revealed_count += 1;
|
||||
if let Empty = self.cell[i][j].content {
|
||||
for m in max(i as isize - 1, 0) as usize..min(i + 2, self.width) {
|
||||
for n in max(j as isize - 1, 0) as usize..min(j + 2, self.height) {
|
||||
if !self.cell[m][n].is_bomb() && !self.cell[m][n].revealed {
|
||||
stack.push((m, n));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Cell {
|
||||
pub fn print(&self) {
|
||||
print!(
|
||||
"{}",
|
||||
if self.revealed {
|
||||
match self.content {
|
||||
Empty => ' ',
|
||||
Mine => '*',
|
||||
MineNeighbour { count } => char::from(count + b'0'),
|
||||
}
|
||||
} else {
|
||||
match self.mark {
|
||||
Mark::Mine => '?',
|
||||
Mark::None => '.',
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
pub fn is_bomb(&self) -> bool {
|
||||
match self.content {
|
||||
Mine => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue