Last active
October 12, 2021 05:21
-
-
Save divi255/e734704e137d02b2ee0ebe92e5f52774 to your computer and use it in GitHub Desktop.
Mine field generator for Minesweeper game
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use rand::{thread_rng, Rng}; | |
use std::fmt; | |
struct MineField { | |
field: Vec<u16>, | |
x: usize, | |
y: usize, | |
} | |
impl MineField { | |
fn generate(x: usize, y: usize, mines: usize) -> Option<Self> { | |
let mut rng = thread_rng(); | |
let mine_field_square = x * y; | |
let mut cap = mine_field_square / 16; | |
if mine_field_square % 16 > 0 { | |
cap += 1; | |
} | |
let mut field: Vec<u16> = vec![0; cap]; | |
let mut coords: Vec<usize> = (0..mine_field_square).collect(); | |
for _ in 0..mines { | |
if coords.is_empty() { | |
return None; | |
} | |
let coord = coords.remove(rng.gen_range(0..coords.len())); | |
field[coord / 16] |= 1 << (coord % 16); | |
} | |
Some(Self { field, x, y }) | |
} | |
} | |
impl fmt::Display for MineField { | |
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | |
let mut result = String::new(); | |
for y in 0..self.y { | |
for x in 0..self.x { | |
let coord = x + y * self.x; | |
result += if self.field[coord / 16] & 1 << (coord % 16) > 0 { | |
"X" | |
} else { | |
"0" | |
} | |
} | |
result += "\n"; | |
} | |
write!(f, "{}", result) | |
} | |
} | |
fn main() { | |
let x = 5; | |
let y = 5; | |
let mines = 5; | |
let mine_field = MineField::generate(x, y, mines).unwrap(); | |
println!("{}", mine_field); | |
} | |
mod test { | |
#[test] | |
fn test_minefield() { | |
use super::MineField; | |
fn calculate_mines(mine_field: &MineField) -> usize { | |
let mut count = 0; | |
for f in mine_field.field.iter() { | |
for bit in 0..16 { | |
if f & 1 << bit > 0 { | |
count += 1; | |
} | |
} | |
} | |
count | |
} | |
for x in 10..100 { | |
for y in 10..100 { | |
for mines in 10..20 { | |
let mine_field = MineField::generate(x, y, mines).unwrap(); | |
assert_eq!(calculate_mines(&mine_field), mines); | |
assert_eq!(mine_field.to_string().matches('X').count(), mines); | |
assert_eq!(mine_field.to_string().matches('0').count(), x * y - mines); | |
} | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment