summaryrefslogtreecommitdiff
path: root/src/game.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/game.rs')
-rw-r--r--src/game.rs139
1 files changed, 66 insertions, 73 deletions
diff --git a/src/game.rs b/src/game.rs
index a6c79a4..3c15796 100644
--- a/src/game.rs
+++ b/src/game.rs
@@ -78,21 +78,28 @@ impl fmt::Display for Direction {
pub enum Action {
Place(Player, Position, Stone),
- Move(Player, Position, Direction, Vec<u8>),
+ Move(Position, Direction, u8, Vec<u8>),
}
impl fmt::Display for Action {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Action::Place(_, pos, stone) => write!(f, "{}{}", stone, pos),
- Action::Move(_, pos, direction, drops) => write!(
- f,
- "{}{}{}",
- // drops.iter().map(|&d| d as u32).sum::<u32>(),
- pos,
- direction,
- drops.into_iter().map(|q| q.to_string()).collect::<String>()
- ),
+ Action::Move(pos, direction, picked_up, drops) => {
+ match (*picked_up > 1, drops.len() > 1) {
+ (true, true) => write!(
+ f,
+ "{}{}{}{}",
+ picked_up,
+ pos,
+ direction,
+ drops.into_iter().map(|q| q.to_string()).collect::<String>(),
+ ),
+ (true, false) => write!(f, "{}{}{}", picked_up, pos, direction),
+ // (false, true) should be impossible
+ _ => write!(f, "{}{}", pos, direction),
+ }
+ }
}
}
}
@@ -254,9 +261,8 @@ impl GameState {
pos: &Position,
stone: Stone,
) -> Result<(Vec<Position>, GameState), String> {
- if let Err(e) = self.is_legal_place(player, pos, stone) {
- return Err(e);
- }
+ self.is_legal_place(player, pos, stone)?;
+
// Place stone
let mut copy = self.copy();
let idx = self.pos_to_idx(&pos);
@@ -264,6 +270,7 @@ impl GameState {
player: player,
stone: stone,
});
+
// Decrease count
match player {
Player::Black => {
@@ -289,6 +296,7 @@ impl GameState {
player: Player,
pos: &Position,
direction: Direction,
+ picked_up: u8,
drops: &Vec<u8>,
) -> Result<(), String> {
if self.within_bounds(pos) {
@@ -297,10 +305,8 @@ impl GameState {
- Drops have been specified
- Must actually move at least one stone
- Top stone belongs to player
- - Zero or more dropped on starting square
- One or more on each subsequent square
- - Total number of stones moved does not exceed the carry capacity
- - Moved the entire stack (up to the carry capacity)
+ - Total number of stones picked up does not exceed the carry capacity
- Direction does not contain a capstone
- Wall may only appear on last spot if it's capstone alone that covers
- All stones are used up before then end of the board is met
@@ -319,7 +325,7 @@ impl GameState {
));
};
- if drops_len == 1 && drops[0] == 1 {
+ if picked_up == 0 {
return Err(String::from(
"A valid move must change the position of at least a single stone.",
));
@@ -335,34 +341,35 @@ impl GameState {
};
for i in 0..drops_len {
- if i > 0 && drops[i] == 0 {
+ if drops[i] == 0 {
return Err(String::from(
- "A move may not drop 0 stones past the first square.",
+ "A move may not drop 0 stones on subsequent squares.",
));
}
}
+ let picked_up = picked_up as usize;
let sum_dropped = drops.iter().map(|&d| d as usize).sum::<usize>();
- let carry_capacity = self.size as usize;
- if sum_dropped > carry_capacity {
+ if sum_dropped != picked_up {
return Err(format!(
- "A move may not exceed the carry capacity of {} stones.",
- self.size
+ "Move intended to pick up {} stones but drop {}.",
+ picked_up, sum_dropped
));
}
- if sum_dropped != std::cmp::min(carry_capacity, stack_len) {
- return Err(String::from(
- "A move must effect the whole stack, up to the carry limit.",
+ let carry_capacity = self.size as usize;
+ if picked_up > carry_capacity {
+ return Err(format!(
+ "A move may not pick up more than the carry capacity of {} stones.",
+ self.size
));
}
- let mut steps: usize = drops.len() - 1;
+ let mut steps: usize = drops.len();
let cap: bool = stack[0].stone == Stone::Capstone;
let mut pos_new = Position { x: pos.x, y: pos.y };
while steps > 0 {
- steps -= 1;
if {
match direction {
Direction::Up => pos_new.y + 1 >= self.size,
@@ -404,6 +411,7 @@ impl GameState {
));
}
}
+ steps -= 1;
}
return Ok(());
} else {
@@ -422,11 +430,10 @@ impl GameState {
player: Player,
pos: &Position,
direction: Direction,
+ picked_up: u8,
drops: &Vec<u8>,
) -> Result<(Vec<Position>, GameState), String> {
- if let Err(e) = self.is_legal_move(player, pos, direction, drops) {
- return Err(e);
- }
+ self.is_legal_move(player, pos, direction, picked_up, drops)?;
let mut copy = self.copy();
let mut pos_vec: Vec<Position> = vec![pos.clone()];
@@ -436,21 +443,35 @@ impl GameState {
let stack_height = copy.board[idx].len();
- let mut offset = 0;
- let carry_capacity = self.size as usize;
- if stack_height > carry_capacity {
- for _i in 0..carry_capacity {
- copy.board[idx].pop();
- }
- offset = stack_height - carry_capacity;
- } else {
- copy.board[idx].clear();
+ let mut offset = stack_height - (picked_up as usize);
+
+ for _i in offset..stack_height {
+ copy.board[idx].pop();
}
- let num_drops = drops.len();
- for drop_idx in 0..num_drops {
- let pos = pos_vec[pos_vec.len() - 1];
- let idx = copy.pos_to_idx(&pos);
+ for drop_idx in 0..drops.len() {
+ let new_pos = pos_vec[pos_vec.len() - 1];
+ pos_vec.push(match direction {
+ Direction::Up => Position {
+ x: new_pos.x,
+ y: new_pos.y + 1,
+ },
+ Direction::Down => Position {
+ x: new_pos.x,
+ y: new_pos.y - 1,
+ },
+ Direction::Left => Position {
+ x: new_pos.x - 1,
+ y: new_pos.y,
+ },
+ Direction::Right => Position {
+ x: new_pos.x + 1,
+ y: new_pos.y,
+ },
+ });
+
+ let new_pos = pos_vec[pos_vec.len() - 1];
+ let idx = copy.pos_to_idx(&new_pos);
let num = drops[drop_idx] as usize;
for i in 0..num {
@@ -466,27 +487,6 @@ impl GameState {
copy.board[idx].push(stack[offset + i]);
}
offset += num;
-
- if drop_idx + 1 < num_drops {
- pos_vec.push(match direction {
- Direction::Up => Position {
- x: pos.x,
- y: pos.y + 1,
- },
- Direction::Down => Position {
- x: pos.x,
- y: pos.y - 1,
- },
- Direction::Left => Position {
- x: pos.x - 1,
- y: pos.y,
- },
- Direction::Right => Position {
- x: pos.x + 1,
- y: pos.y,
- },
- });
- }
}
Ok((pos_vec, copy))
}
@@ -787,16 +787,9 @@ impl Game {
}
TurnOrder::Normal => state.place_stone(*player, pos, *stone),
},
- Action::Move(player, pos, direction, drops) => match self.turn_order {
+ Action::Move(pos, direction, picked_up, drops) => match self.turn_order {
TurnOrder::Normal => {
- if *player == self.current_player {
- state.move_stack(*player, pos, *direction, drops)
- } else {
- Err(format!(
- "{} may not take actions on {}'s turn.",
- player, self.current_player
- ))
- }
+ state.move_stack(self.current_player, pos, *direction, *picked_up, drops)
}
_ => Err(String::from(
"At the start of the game only placing flats is allowed.",