gamestate
Co-authored-by: Julia Ryan <juliaryan3.14@gmail.com>
This commit is contained in:
commit
672f9e09bf
5 changed files with 230 additions and 0 deletions
211
src/gamestate.rs
Normal file
211
src/gamestate.rs
Normal file
|
|
@ -0,0 +1,211 @@
|
|||
use std::fmt::Display;
|
||||
|
||||
#[derive(Clone, Copy, PartialEq)]
|
||||
struct PlayerState {
|
||||
xy: u8,
|
||||
walls_left: u8,
|
||||
}
|
||||
|
||||
impl PlayerState {
|
||||
pub const P1_START: Self = Self::new(4, 0, 9);
|
||||
pub const P2_START: Self = Self::new(4, 8, 9);
|
||||
|
||||
pub const fn new(x: u8, y: u8, walls_left: u8) -> Self {
|
||||
let mut res = Self { xy: 0, walls_left };
|
||||
|
||||
res.set_x(x);
|
||||
res.set_y(y);
|
||||
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
impl PlayerState {
|
||||
pub const fn x(&self) -> u8 {
|
||||
self.xy & 0b00001111
|
||||
}
|
||||
|
||||
pub const fn y(&self) -> u8 {
|
||||
(self.xy & 0b11110000) >> 4
|
||||
}
|
||||
|
||||
pub const fn set_x(&mut self, x: u8) {
|
||||
// zero out x
|
||||
self.xy &= 0b11110000;
|
||||
// write the x part
|
||||
self.xy |= x & 0b00001111;
|
||||
}
|
||||
|
||||
pub const fn set_y(&mut self, y: u8) {
|
||||
// zero out y
|
||||
self.xy &= 0b00001111;
|
||||
// write the y part
|
||||
self.xy |= (y & 0b00001111) << 4;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
struct WallState {
|
||||
verticals: [u8; 9],
|
||||
horizontals: [u8; 9],
|
||||
}
|
||||
|
||||
impl WallState {
|
||||
#[inline]
|
||||
pub fn block_cleaned_hori(&mut self, byte_idx: u8, bit: u8) {
|
||||
self.horizontals[byte_idx as usize] |= 1 << bit;
|
||||
}
|
||||
#[inline]
|
||||
pub fn block_cleaned_verti(&mut self, byte_idx: u8, bit: u8) {
|
||||
self.verticals[byte_idx as usize] |= 1 << bit;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn can_walk_between_cleaned_hori(&self, byte_idx: u8, bit: u8) -> bool {
|
||||
(self.horizontals[byte_idx as usize] >> bit) & 1 != 0
|
||||
}
|
||||
#[inline]
|
||||
pub fn can_walk_between_cleaned_verti(&self, byte_idx: u8, bit: u8) -> bool {
|
||||
(self.verticals[byte_idx as usize] >> bit) & 1 != 0
|
||||
}
|
||||
|
||||
pub fn block(&mut self, from_x: u8, from_y: u8, to_x: u8, to_y: u8) {
|
||||
match (from_x.wrapping_sub(to_x), from_y.wrapping_sub(to_y)) {
|
||||
(1, 0) => self.block_cleaned_verti(to_y, to_x),
|
||||
(0xff, 0) => self.block_cleaned_verti(from_y, from_x),
|
||||
|
||||
(0, 1) => self.block_cleaned_hori(to_x, to_y),
|
||||
(0, 0xff) => self.block_cleaned_hori(from_x, from_y),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn can_walk_between(&self, from_x: u8, from_y: u8, to_x: u8, to_y: u8) -> bool {
|
||||
!match (from_x.wrapping_sub(to_x), from_y.wrapping_sub(to_y)) {
|
||||
(1, 0) => self.can_walk_between_cleaned_verti(to_y, to_x),
|
||||
(0xff, 0) => self.can_walk_between_cleaned_verti(from_y, from_x),
|
||||
|
||||
(0, 1) => self.can_walk_between_cleaned_hori(to_x, to_y),
|
||||
(0, 0xff) => self.can_walk_between_cleaned_hori(from_x, from_y),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for WallState {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
verticals: Default::default(),
|
||||
horizontals: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct GameState {
|
||||
p1: PlayerState,
|
||||
p2: PlayerState,
|
||||
walls: WallState,
|
||||
}
|
||||
|
||||
impl Default for GameState {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
p1: PlayerState::P1_START,
|
||||
p2: PlayerState::P2_START,
|
||||
walls: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
what we're going for:
|
||||
-- -- --
|
||||
| | |P2|
|
||||
-- -- --
|
||||
|P1| | |
|
||||
-- -- --
|
||||
*/
|
||||
impl Display for GameState {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
writeln!(
|
||||
f,
|
||||
"P1: {}, P2: {}\n",
|
||||
self.p1.walls_left, self.p2.walls_left
|
||||
)?;
|
||||
for y in 0..9 {
|
||||
for x in 0..9 {
|
||||
if y > 0 {
|
||||
let wall = if !self.walls.can_walk_between(x, y - 1, x, y) {
|
||||
' '
|
||||
} else {
|
||||
'-'
|
||||
};
|
||||
write!(f, "{wall}{wall}")?;
|
||||
}
|
||||
if x != 8 {
|
||||
write!(f, " ")?;
|
||||
}
|
||||
}
|
||||
writeln!(f, "")?;
|
||||
for x in 0..9 {
|
||||
if x > 0 {
|
||||
let wall = if !self.walls.can_walk_between(x - 1, y, x, y) {
|
||||
' '
|
||||
} else {
|
||||
'|'
|
||||
};
|
||||
write!(f, "{wall}")?;
|
||||
}
|
||||
let player = if self.p1.x() == x && self.p1.y() == y {
|
||||
"P1"
|
||||
} else if self.p2.x() == x && self.p2.y() == y {
|
||||
"P2"
|
||||
} else {
|
||||
" "
|
||||
};
|
||||
write!(f, "{player}")?;
|
||||
}
|
||||
writeln!(f, "")?;
|
||||
}
|
||||
writeln!(f, "")?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::gamestate::{GameState, PlayerState, WallState};
|
||||
|
||||
#[test]
|
||||
fn test_blocking() {
|
||||
let mut w = WallState::default();
|
||||
|
||||
assert!(w.can_walk_between(0, 0, 1, 0));
|
||||
w.block(0, 0, 1, 0);
|
||||
assert!(!w.can_walk_between(0, 0, 1, 0));
|
||||
|
||||
w.block(8, 7, 8, 8);
|
||||
w.block(0, 8, 1, 8);
|
||||
|
||||
assert!(w.can_walk_between(0, 0, 0, 1));
|
||||
w.block(0, 0, 0, 1);
|
||||
assert!(!w.can_walk_between(0, 0, 0, 1));
|
||||
|
||||
assert!(w.can_walk_between(0, 7, 0, 8));
|
||||
w.block(0, 7, 0, 8);
|
||||
assert!(!w.can_walk_between(0, 7, 0, 8));
|
||||
|
||||
assert!(w.can_walk_between(7, 0, 8, 0));
|
||||
w.block(7, 0, 8, 0);
|
||||
assert!(!w.can_walk_between(7, 0, 8, 0));
|
||||
|
||||
println!(
|
||||
"{}",
|
||||
GameState {
|
||||
p1: PlayerState::P1_START,
|
||||
p2: PlayerState::P2_START,
|
||||
walls: w,
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue