summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authortslil clingman <>2020-01-14 16:09:27 -0500
committertslil clingman <>2020-01-14 16:09:27 -0500
commit0c3c243d60d49e1c18e5a18fc2300e7e47292938 (patch)
treeaff566581f3dec14133d87c92ee083fd67e7d7f3 /src
parent67ca3fc5f9280c8a6fa4623efc4b60ba554a2bc4 (diff)
First draft of action checking code
Diffstat (limited to 'src')
-rw-r--r--src/board.rs175
1 files changed, 134 insertions, 41 deletions
diff --git a/src/board.rs b/src/board.rs
index bd86c12..484c31a 100644
--- a/src/board.rs
+++ b/src/board.rs
@@ -97,7 +97,7 @@ impl fmt::Display for Action {
type Stack = Vec<(Player, Stone)>;
pub struct Board {
- size: u16,
+ size: u8,
black_flats: u8,
white_flats: u8,
black_capstones: u8,
@@ -110,7 +110,7 @@ pub struct Board {
// TODO: Generate all legal actions for a given player
-pub type Logger = fn(&str);
+pub type Logger = fn(String);
impl Board {
fn remaining_pieces(&self, player: &Player, stone: &Stone) -> u8 {
@@ -132,10 +132,18 @@ impl Board {
}
}
+ fn within_bounds(&self, pos: &Position) -> bool {
+ if (pos.x < self.size) && (pos.y < self.size) {
+ true
+ } else {
+ false
+ }
+ }
+
fn lookup_square(&self, pos: &Position) -> Option<&Stack> {
- let y: u16 = pos.y as u16;
- let x: u16 = pos.x as u16;
- self.board.get((x + y * self.size) as usize)
+ let y: usize = pos.y as usize;
+ let x: usize = pos.x as usize;
+ self.board.get(x + y * (self.size as usize))
}
fn is_legal_place(&self, player: &Player, pos: &Position, stone: &Stone, log: Logger) -> bool {
@@ -143,16 +151,30 @@ impl Board {
1. The desired square must be empty
2. The player must have sufficient pieces
*/
- match self.lookup_square(pos) {
- Some(stack) => {
- if (stack.len() > 0) || (self.remaining_pieces(player, stone) == 0) {
- log("Not");
+ if self.within_bounds(pos) {
+ match self.lookup_square(pos) {
+ Some(stack) => {
+ if stack.len() > 0 {
+ log(format!("{} is already occupied.", pos));
+ false
+ } else if self.remaining_pieces(player, stone) == 0 {
+ log(format!(
+ "{} has no more remaining {} pieces.",
+ player, stone
+ ));
+ false
+ } else {
+ true
+ }
+ }
+ None => {
+ log(format!("Internal error, lookup for {} failed.", pos));
false
- } else {
- true
}
}
- None => false,
+ } else {
+ log(format!("Position {} is not within bounds.", pos));
+ false
}
}
@@ -162,41 +184,112 @@ impl Board {
pos: &Position,
direction: &Direction,
drops: &Vec<u8>,
+ log: Logger,
) -> bool {
- match self.lookup_square(pos) {
- Some(stack) => {
+ if self.within_bounds(pos) {
+ match self.lookup_square(pos) {
/* Rules for moving a stack:
0. There are stones
- 1. Top stone belongs to player
- 2. Zero or One stones dropped on starting square
- 3. Total number of stones moved does not exceed the carry capacity
- 4. Direction does not contain a capstone
- 5. Wall may only appear on last spot if it's capstone alone that covers
- 6. All stones are used up before then end of the board is met
-
- We check 0,1,2, and 3 first
- */
- if (stack.len() == 0)
- || (drops.len() == 0)
- || (stack[0].0 != *player)
- || (drops[0] > 1)
- || (drops.iter().sum::<u8>() as u16 > self.size)
- {
- false
- } else {
- let steps: usize = drops.len() - 1;
- let cap: bool = stack[0].1 == Stone::Capstone;
- let (dy, dx): (i8, i8) = match direction {
- Direction::Up => (1, 0),
- Direction::Down => (-1, 0),
- Direction::Left => (0, -1),
- Direction::Right => (0, 1),
- };
-
+ 1. Top stone belongs to player
+ 2. Zero or One stones dropped on starting square
+ 3. Total number of stones moved does not exceed the carry capacity
+ 4. Direction does not contain a capstone
+ 5. Wall may only appear on last spot if it's capstone alone that covers
+ 6. All stones are used up before then end of the board is met
+ */
+ Some(stack) => {
+ if stack.len() == 0 {
+ log(format!("{} has no stones to move.", pos));
+ false
+ } else if drops.len() == 0 {
+ log(format!("A drop sequence for must be specified for a move."));
+ false
+ } else if stack[0].0 != *player {
+ log(format!(
+ "{} may not move the stack at {} as it belongs to {}.",
+ player, pos, stack[0].0
+ ));
+ false
+ } else if drops[0] > 1 {
+ log(format!(
+ "A move may only drop 0 or 1 stones at it's origin square."
+ ));
+ false
+ // Do the sum in u32 just in case ?
+ } else if drops.iter().map(|&d| d as u32).sum::<u32>() > self.size as u32 {
+ log(format!(
+ "A move may not exceed the carry limit of {} stones.",
+ self.size
+ ));
+ false
+ } else {
+ let mut steps: usize = drops.len() - 1;
+ let cap: bool = stack[0].1 == Stone::Capstone;
+ let mut pos_new = Position { x: pos.x, y: pos.y };
+ let mut result = true;
+ while steps > 0 {
+ if {
+ match direction {
+ Direction::Up => pos_new.y + 1 >= self.size,
+ Direction::Down => pos_new.y == 0,
+ Direction::Left => pos_new.x + 1 >= self.size,
+ Direction::Right => pos_new.x == 0,
+ }
+ } {
+ log(format!("A move may not extend past the board."));
+ result = false;
+ break;
+ } else {
+ match direction {
+ Direction::Up => pos_new.y += 1,
+ Direction::Down => pos_new.y -= 1,
+ Direction::Left => pos_new.x += 1,
+ Direction::Right => pos_new.x -= 1,
+ }
+ match self.lookup_square(&pos_new) {
+ Some(stack) => {
+ if stack.len() > 0 {
+ match stack[0].1 {
+ Stone::Capstone => {
+ log(format!(
+ "A move may not cover a capstone."
+ ));
+ result = false;
+ break;
+ }
+ Stone::Standing => {
+ if (steps > 1) || (!cap) {
+ log(format!(
+ "A move may not cover a standing stone."
+ ));
+ result = false;
+ break;
+ }
+ }
+ Stone::Flat => (),
+ }
+ }
+ }
+ None => {
+ log(format!("Internal error, lookup for {} failed.", pos));
+ result = false;
+ break;
+ }
+ }
+ }
+ steps -= 1;
+ }
+ result
+ }
+ }
+ None => {
+ log(format!("Internal error, lookup for {} failed.", pos));
false
}
}
- None => false,
+ } else {
+ log(format!("Position {} is not within bounds.", pos));
+ false
}
}