Skip to content

Instantly share code, notes, and snippets.

@mpgarate
Created November 15, 2015 16:14
Show Gist options
  • Save mpgarate/82a00c1ed0668b51f6cf to your computer and use it in GitHub Desktop.
Save mpgarate/82a00c1ed0668b51f6cf to your computer and use it in GitHub Desktop.
diff --git a/src/game/bitboard.rs b/src/game/bitboard.rs
index 2564a85..08ec7f7 100644
--- a/src/game/bitboard.rs
+++ b/src/game/bitboard.rs
@@ -1,4 +1,5 @@
use game::position::Position;
+use std::fmt;
#[allow(dead_code)]
const BOARD_STATE_EMPTY: u64 = 0x123456789ABCDEF0;
@@ -37,6 +38,18 @@ impl BitBoard {
((masked_data >> offset as u64) & 0xF) as u8
}
+
+ pub fn swap(&self, p1: Position, p2: Position) -> BitBoard {
+ let v1 = self.get(p1.clone());
+ self.set(p1, self.get(p2.clone()))
+ .set(p2, v1)
+ }
+}
+
+impl fmt::Display for BitBoard {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "({:X})", self.data)
+ }
}
#[cfg(test)]
@@ -92,4 +105,31 @@ mod tests {
}
}
}
+
+ #[test]
+ fn swap_two_valid_positions() {
+ let b1 = BitBoard::new();
+
+ for row1 in 0..4 {
+ for col1 in 0..4 {
+ for row2 in 0..4 {
+ for col2 in 0..4 {
+ let p1 = Position::new(row1, col1);
+ let p2 = Position::new(row2, col2);
+
+ println!("-----------------------");
+ println!("r1: {} c1: {} r2: {} c2: {}", row1, col1, row2, col2);
+
+ let b2 = b1.swap(p1, p2);
+
+ println!("b1: {}", b1);
+ println!("b2: {}", b2);
+
+ assert_eq!(b1.get(p1), b2.get(p2));
+ assert_eq!(b2.get(p1), b1.get(p2));
+ }
+ }
+ }
+ }
+ }
}
diff --git a/src/game/position.rs b/src/game/position.rs
index d40dc8e..bcf941e 100644
--- a/src/game/position.rs
+++ b/src/game/position.rs
@@ -1,9 +1,20 @@
+use std::fmt;
+
#[allow(dead_code)]
const MAX_ROW_INDEX: u8 = 3;
#[allow(dead_code)]
const MAX_COL_INDEX: u8 = 3;
#[allow(dead_code)]
+pub enum MoveDirection {
+ Left,
+ Right,
+ Up,
+ Down
+}
+
+#[allow(dead_code)]
+#[derive(Copy, Clone)]
pub struct Position {
row: u8,
col: u8,
@@ -23,6 +34,36 @@ impl Position {
let index = (self.row * 4) + self.col;
4 * (15 - index)
}
+
+ pub fn get_neighbor(&self, move_direction: MoveDirection) -> Option<Position> {
+ match move_direction {
+ MoveDirection::Left if self.col > 0 => {
+ Some(Position { row: self.row, col: self.col - 1 })
+ }
+ MoveDirection::Right if self.col < MAX_COL_INDEX => {
+ Some(Position { row: self.row, col: self.col + 1 })
+ }
+ MoveDirection::Up if self.row > 0 => {
+ Some(Position { row: self.row - 1, col: self.col })
+ }
+ MoveDirection::Down if self.row < MAX_ROW_INDEX => {
+ Some(Position { row: self.row + 1, col: self.col })
+ }
+ _ => None
+ }
+ }
+}
+
+impl PartialEq for Position {
+ fn eq(&self, other: &Position) -> bool {
+ self.col == other.col && self.row == other.row
+ }
+}
+
+impl fmt::Debug for Position {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "row: {}, col: {}", self.row, self.col)
+ }
}
#[cfg(test)]
@@ -40,4 +81,12 @@ mod tests {
fn high_row_position_should_panic() {
Position::new(141, 0);
}
+
+ #[test]
+ fn get_valid_left_move() {
+ let p: Position = Position::new(3, 3);
+ let n: Option<Position> = p.get_neighbor(MoveDirection::Left);
+
+ assert_eq!(Some(Position::new(3, 2)), n);
+ }
}
diff --git a/src/game/state.rs b/src/game/state.rs
index dadd51b..4662d1c 100644
--- a/src/game/state.rs
+++ b/src/game/state.rs
@@ -1,22 +1,49 @@
use game::bitboard::BitBoard;
+use game::position::Position;
+use game::position::MoveDirection;
+#[allow(dead_code)]
+const DEFAULT_FREE_SPACE_ROW: u8 = 3;
+#[allow(dead_code)]
+const DEFAULT_FREE_SPACE_COL: u8 = 3;
+
+#[allow(dead_code)]
pub struct GameState {
- board: BitBoard
+ board: BitBoard,
+ free_space: Position,
}
+#[allow(dead_code)]
impl GameState {
pub fn new() -> GameState {
- GameState { board: BitBoard::new() }
+ GameState {
+ board: BitBoard::new(),
+ free_space: Position::new(DEFAULT_FREE_SPACE_ROW, DEFAULT_FREE_SPACE_COL),
+ }
}
pub fn is_solved(&self) -> bool {
self.board.is_solved()
}
+
+ pub fn move_space(&self, move_direction: MoveDirection) -> Option<GameState> {
+ match self.free_space.get_neighbor(move_direction) {
+ Some(position) => {
+ Some(GameState {
+ board: self.board.swap(self.free_space, position),
+ free_space: position,
+ })
+ }
+ _ => None
+ }
+ }
}
#[cfg(test)]
mod tests {
use super::*;
+ use game::position::Position;
+ use game::position::MoveDirection;
#[test]
fn new_state_is_solved() {
@@ -24,4 +51,20 @@ mod tests {
assert!(s.is_solved());
}
+
+ #[test]
+ fn move_space_valid_direction() {
+ let s: Option<GameState> = GameState::new()
+ .move_space(MoveDirection::Left);
+
+ match s {
+ //Some(GameState { board: _, free_space: Position { row: 3, col: 2 }}) => { } // ok
+ Some(state) => {
+ if state.free_space != Position::new(3, 2) {
+ panic!()
+ }
+ }
+ _ => panic!(),
+ }
+ }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment