Created
November 15, 2015 16:11
-
-
Save mpgarate/e4c71a4f1296a49c2617 to your computer and use it in GitHub Desktop.
This file contains 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
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