initial commit
This commit is contained in:
commit
7b597748bb
|
@ -0,0 +1 @@
|
||||||
|
target
|
|
@ -0,0 +1,11 @@
|
||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sycamore"
|
||||||
|
version = "0.1.0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sycamore-harness"
|
||||||
|
version = "0.1.0"
|
|
@ -0,0 +1,5 @@
|
||||||
|
[workspace]
|
||||||
|
members = [
|
||||||
|
"sycamore",
|
||||||
|
"sycamore-harness"
|
||||||
|
]
|
|
@ -0,0 +1,3 @@
|
||||||
|
# Sycamore: Speedrunning Minesweeper
|
||||||
|
|
||||||
|
Sycamore is a Rust minesweeper bot, intenting to solve any board permutation as quickly as possible.
|
|
@ -0,0 +1,7 @@
|
||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sycamore-harness"
|
||||||
|
version = "0.1.0"
|
|
@ -0,0 +1,8 @@
|
||||||
|
[package]
|
||||||
|
name = "sycamore-harness"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
|
@ -0,0 +1,3 @@
|
||||||
|
fn main() {
|
||||||
|
println!("Hello, world!");
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sycamore"
|
||||||
|
version = "0.1.0"
|
|
@ -0,0 +1,8 @@
|
||||||
|
[package]
|
||||||
|
name = "sycamore"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
|
@ -0,0 +1,76 @@
|
||||||
|
/*
|
||||||
|
Board representation
|
||||||
|
|
||||||
|
Sycamore uses a bytefield representation of the board, enabling arbitrary sized boards to be indexed extremely quickly.
|
||||||
|
|
||||||
|
There are 10 states a square can be in:
|
||||||
|
- 0000 empty
|
||||||
|
- 0001 revealed, 1
|
||||||
|
- 0010 revealed, 2
|
||||||
|
- 0011 revealed, 3
|
||||||
|
- 0100 revealed, 4
|
||||||
|
- 0101 revealed, 5
|
||||||
|
- 0110 revealed, 6
|
||||||
|
- 0111 revealed, 7
|
||||||
|
- 1000 revealed, 8
|
||||||
|
- 1001 flagged
|
||||||
|
- 1010 hidden
|
||||||
|
These numbers have been picked to allow easily performing calculations when solving - 0-8 adjacent mines per square can be represented by immediately doing arithmetic with this value.
|
||||||
|
|
||||||
|
To represent this, at minimum 4 bits are needed, however for fast and easy access, an entire byte is used.
|
||||||
|
|
||||||
|
This allows us to represent the entire board with a simple WIDTH*HEIGHT-length array, and easily access
|
||||||
|
the value of a specific coordinate with bytefield[WIDTH * row + col].
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
pub const SQUARESTATE_EMPTY: u8 = 0;
|
||||||
|
pub const SQUARESTATE_FLAGGED: u8 = 9;
|
||||||
|
pub const SQUARESTATE_HIDDEN: u8 = 10;
|
||||||
|
pub const SQUARESTATE_MAX_VAL: u8 = SQUARESTATE_HIDDEN;
|
||||||
|
|
||||||
|
pub struct Board {
|
||||||
|
field: Vec<u8>,
|
||||||
|
width: usize,
|
||||||
|
height: usize
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Board {
|
||||||
|
pub fn new(width: usize, height: usize, pre_allocate: bool) -> Self {
|
||||||
|
let mut vec = if pre_allocate {
|
||||||
|
Vec::with_capacity(width * height)
|
||||||
|
} else {
|
||||||
|
Vec::new()
|
||||||
|
};
|
||||||
|
for i in 0..width * height {
|
||||||
|
vec.insert(i, SQUARESTATE_HIDDEN);
|
||||||
|
}
|
||||||
|
Self {
|
||||||
|
field: vec,
|
||||||
|
width,
|
||||||
|
height
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get(&self, row: usize, col: usize) -> &u8 {
|
||||||
|
if col > self.width { panic!("board access out of bounds (width is {} but col is {})", self.width, col); }
|
||||||
|
if row > self.height { panic!("board access out of bounds (height is {} but row is {})", self.height, row); }
|
||||||
|
|
||||||
|
&self.field[row * self.width + col]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_mut(&mut self, row: usize, col: usize) -> &mut u8 {
|
||||||
|
if col > self.width { panic!("board access out of bounds (width is {} but col is {})", self.width, col); }
|
||||||
|
if row > self.height { panic!("board access out of bounds (height is {} but row is {})", self.height, row); }
|
||||||
|
|
||||||
|
&mut self.field[row * self.width + col]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set(&mut self, row: usize, col: usize, to: u8) {
|
||||||
|
if col > self.width { panic!("board access out of bounds (width is {} but col is {})", self.width, col); }
|
||||||
|
if row > self.height { panic!("board access out of bounds (height is {} but row is {})", self.height, row); }
|
||||||
|
if to > SQUARESTATE_MAX_VAL { panic!("board set to invalid state (max allowed state is {} but 'to' is {})", SQUARESTATE_MAX_VAL, to); }
|
||||||
|
|
||||||
|
self.field[row * self.width + col] = to;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
pub mod board;
|
Loading…
Reference in New Issue