aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/game.rs21
-rw-r--r--src/main.rs7
-rw-r--r--src/parser.rs64
3 files changed, 64 insertions, 28 deletions
diff --git a/src/game.rs b/src/game.rs
index 2922121..4cb6fdd 100644
--- a/src/game.rs
+++ b/src/game.rs
@@ -317,16 +317,16 @@ impl GameState {
}
}
- let num_dropped = drops.iter().map(|&d| d as usize).sum::<usize>();
+ let sum_dropped = drops.iter().map(|&d| d as usize).sum::<usize>();
let carry_capacity = self.size as usize;
- if num_dropped > carry_capacity {
+ if sum_dropped > carry_capacity {
return Err(format!(
"A move may not exceed the carry capacity of {} stones.",
self.size
));
}
- if num_dropped != std::cmp::max(carry_capacity, stack_len) {
+ 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.",
));
@@ -356,7 +356,7 @@ impl GameState {
}
if let Some(stack) = &self.board.get(self.pos_to_idx(&pos_new)) {
if stack.len() > 0 {
- match stack[0].stone {
+ match stack[stack.len() - 1].stone {
Stone::Capstone => {
return Err(String::from(
"A move may not cover a capstone.",
@@ -409,10 +409,19 @@ impl GameState {
let idx = copy.pos_to_idx(&pos);
let stack: &Stack = &self.board[self.pos_to_idx(pos)];
- copy.board[idx].clear();
+ let len = copy.board[idx].len();
- let num_drops = drops.len();
let mut offset = 0;
+ if len > self.size as usize {
+ for _i in 0..self.size {
+ copy.board[idx].pop();
+ }
+ offset = self.size - 1;
+ } else {
+ copy.board[idx].clear();
+ }
+
+ 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);
diff --git a/src/main.rs b/src/main.rs
index 6bbe52d..ff98d41 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -76,11 +76,12 @@ fn main() {
loop {
let inp = action_entry.read_action();
- let stone_owner = game.query_stone_owner();
- let player = game.query_current_player();
- match parse_action(stone_owner, &inp) {
+ match parse_action(&game, &inp) {
Err(err) => message_log.log_error(format!("Input \"{}\": {}", inp, err)),
Ok(act) => {
+ let stone_owner = game.query_stone_owner();
+ let player = game.query_current_player();
+
message_log.log_message(format!(
"{} performs {}{}",
player,
diff --git a/src/parser.rs b/src/parser.rs
index a1d9a32..73457f0 100644
--- a/src/parser.rs
+++ b/src/parser.rs
@@ -1,6 +1,6 @@
use crate::game::*;
-fn parse_move(player: Player, mv: &str) -> Result<Action, String> {
+fn parse_move(mv: &str, game: &Game) -> Result<Action, String> {
let mut chars = mv.chars();
let c = chars.next();
@@ -9,19 +9,28 @@ fn parse_move(player: Player, mv: &str) -> Result<Action, String> {
}
let dc = c.unwrap();
- if (dc < '1') || ('9' < dc) {
- return Err(String::from(
- "Moves must begin with a digit in 1-8 indicating the number of drops.",
- ));
- }
- let sum_drops = dc.to_digit(10).unwrap();
+ let sum_drops: u8;
+ let x;
+ if (dc >= 'a') && (dc <= 'h') {
+ // Drop number omitted, must be 1 drop.
+ sum_drops = 1;
+ x = dc;
+ } else {
+ if (dc < '1') || ('9' < dc) {
+ return Err(String::from(
+ "Moves must begin with a digit in 1-8 indicating the number of drops.",
+ ));
+ }
+ sum_drops = dc.to_digit(10).unwrap() as u8;
- let c = chars.next();
- if c.is_none() {
- return Err(String::from("Moves must specify a stack position."));
+ let c = chars.next();
+ if c.is_none() {
+ return Err(String::from("Moves must specify a stack position."));
+ }
+
+ x = c.unwrap();
}
- let x = c.unwrap();
if (x < 'a') || (x > 'h') {
return Err(String::from(
"Moves must specify a valid position on the game board.",
@@ -48,7 +57,9 @@ fn parse_move(player: Player, mv: &str) -> Result<Action, String> {
}
let c = c.unwrap();
- let dir; // This is so cool! Rust supports some very nice patterns!
+ // This is so cool! Rust supports some very nice patterns, and
+ // checks for uninitialised variables too!
+ let dir;
match c {
'+' => dir = Direction::Up,
'-' => dir = Direction::Down,
@@ -75,17 +86,28 @@ fn parse_move(player: Player, mv: &str) -> Result<Action, String> {
}
let sum = drops.iter().map(|&d| d as u32).sum::<u32>();
- if sum != sum_drops {
+ let pos = Position { x: x, y: y };
+ if sum == 0 {
+ // Omitted all the drops, it's a total stack move
+ drops.push(0);
+ if let Some(stack) = game.query_square(&pos) {
+ drops.push(std::cmp::min(stack.len() as u8, game.get_size()));
+ } else {
+ return Err(String::from(
+ "Moves must specify a valid position on the game board.",
+ ));
+ }
+ } else if sum != sum_drops as u32 {
return Err(format!(
"The move called for {} stones, but {} were dropped.",
sum_drops, sum
));
}
- Ok(Action::Move(player, Position { x: x, y: y }, dir, drops))
+ Ok(Action::Move(game.query_stone_owner(), pos, dir, drops))
}
-fn parse_place(player: Player, pl: &str) -> Result<Action, String> {
+fn parse_place(pl: &str, game: &Game) -> Result<Action, String> {
let mut chars = pl.chars();
let c = chars.next();
@@ -139,16 +161,20 @@ fn parse_place(player: Player, pl: &str) -> Result<Action, String> {
}
let y: u8 = (y.to_digit(10).unwrap() - 1) as u8;
- Ok(Action::Place(player, Position { x: x, y: y }, stone))
+ Ok(Action::Place(
+ game.query_stone_owner(),
+ Position { x: x, y: y },
+ stone,
+ ))
}
-pub fn parse_action(player: Player, act: &str) -> Result<Action, String> {
+pub fn parse_action(game: &Game, act: &str) -> Result<Action, String> {
if act
.chars()
.any(|c| c == '+' || c == '-' || c == '>' || c == '<')
{
- parse_move(player, act)
+ parse_move(act, game)
} else {
- parse_place(player, act)
+ parse_place(act, game)
}
}