use crate::Error;
use crate::rules::{Dice, Player, Roll};
use crate::stats::Stats;
use std::fmt;
#[derive(Debug, Clone, PartialEq, Default)]
pub struct Board {
raw_board: (PlayerBoard, PlayerBoard),
dice: Dice,
}
#[derive(Debug, PartialEq)]
pub struct BoardDisplay {
pub board: [i8; 24],
pub bar: (u8, u8),
pub off: (u8, u8),
pub dice: (u8, u8),
}
impl fmt::Display for BoardDisplay {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"Board: {:?}, Bar: {:?}, Off: {:?}, Dice: {:?}",
self.board, self.bar, self.off, self.dice
)
}
}
#[derive(Clone, Copy, PartialEq)]
pub enum Position {
Board(usize),
Bar,
Off,
}
impl fmt::Debug for Position {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Position::Board(field) => write!(f, "{}", field),
Position::Bar => write!(f, "Bar"),
Position::Off => write!(f, "Off"),
}
}
}
impl fmt::Display for Position {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Position::Board(field) => write!(f, "{}", field),
Position::Bar => write!(f, "Bar"),
Position::Off => write!(f, "Off"),
}
}
}
impl Board {
pub fn new() -> Self {
Board::default()
}
pub fn get_bar(&self, player: Player) -> Result<u8, Error> {
match player {
Player::Player0 => Ok(self.raw_board.0.bar),
Player::Player1 => Ok(self.raw_board.1.bar),
Player::Nobody => Err(Error::PlayerInvalid),
}
}
pub fn get_off(&self, player: Player) -> Result<u8, Error> {
match player {
Player::Player0 => Ok(self.raw_board.0.off),
Player::Player1 => Ok(self.raw_board.1.off),
Player::Nobody => Err(Error::PlayerInvalid),
}
}
pub fn is_blocked(&self, player: Player, position: Position) -> Result<bool, Error> {
if player == Player::Nobody {
return Err(Error::PlayerInvalid);
}
let field = match position {
Position::Board(f) => f,
Position::Off => return Ok(false),
Position::Bar => return Ok(false),
};
if !(1..=24).contains(&field) {
return Err(Error::FieldInvalid);
}
match player {
Player::Player0 => {
if self.raw_board.1.board[24 - field] > 1 {
Ok(true)
} else {
Ok(false)
}
}
Player::Player1 => {
if self.raw_board.0.board[24 - field] > 1 {
Ok(true)
} else {
Ok(false)
}
}
Player::Nobody => unreachable!("handled above"),
}
}
pub fn is_available(&self, player: Player, position: Position) -> Result<bool, Error> {
Ok(!self.is_blocked(player, position)?)
}
pub fn is_bar_empty(&self, player: Player) -> Result<bool, Error> {
Ok(!self.has_checker_at(player, Position::Bar)?)
}
pub fn ready_for_off_play(&self, player: Player) -> Result<bool, Error> {
let player_board = match player {
Player::Player0 => &self.raw_board.0,
Player::Player1 => &self.raw_board.1,
Player::Nobody => return Err(Error::PlayerInvalid),
};
let sum_board: u8 = player_board.board[6..24].iter().copied().sum();
Ok(sum_board == 0 && player_board.bar == 0)
}
pub fn backgammon_loss_position(&self, player: Player) -> Result<bool, Error> {
let player_board = match player {
Player::Player0 => &self.raw_board.0,
Player::Player1 => &self.raw_board.1,
Player::Nobody => return Err(Error::PlayerInvalid),
};
let sum_board: u8 = player_board.board[18..24].iter().copied().sum();
Ok((sum_board != 0 || player_board.bar != 0) && player_board.off == 0)
}
pub fn all_checkers_off(&self, player: Player) -> Result<bool, Error> {
Ok(self.get_off(player)? == 15)
}
pub fn has_checker_at(&self, player: Player, source: Position) -> Result<bool, Error> {
if player == Player::Nobody {
return Err(Error::PlayerInvalid);
}
let has_checker = match (player, source) {
(Player::Player0, Position::Board(field)) => {
if !(1..=24).contains(&field) {
return Err(Error::FieldInvalid);
}
self.raw_board.0.board[field - 1] > 0
}
(Player::Player1, Position::Board(field)) => {
if !(1..=24).contains(&field) {
return Err(Error::FieldInvalid);
}
self.raw_board.1.board[field - 1] > 0
}
(Player::Player0, Position::Bar) => self.raw_board.0.bar > 0,
(Player::Player1, Position::Bar) => self.raw_board.1.bar > 0,
(Player::Player0, Position::Off) => self.raw_board.0.off > 0,
(Player::Player1, Position::Off) => self.raw_board.1.off > 0,
(Player::Nobody, _) => unreachable!("handled above"),
};
Ok(has_checker)
}
fn move_by_dice(&mut self, player: Player, dice: u8, from: Position) -> Result<(), Error> {
if !(1..=6).contains(&dice) {
return Err(Error::DiceInvalid);
}
if player == Player::Nobody {
return Err(Error::PlayerInvalid);
}
match from {
Position::Bar => {
if self.is_blocked(player, Position::Board(25 - dice as usize))? {
return Err(Error::FieldBlocked);
}
self.set_checkers(player, Position::Bar, -1)?;
self.set_checkers(player, Position::Board(25 - dice as usize), 1)
}
Position::Board(field) => {
if !(1..=24).contains(&field) {
return Err(Error::FieldInvalid);
}
if !self.is_bar_empty(player)? {
return Err(Error::MoveInvalidBar);
}
match field.checked_sub(dice as usize) {
Some(target_field) => {
if target_field > 0 {
if self.is_blocked(player, Position::Board(target_field))? {
return Err(Error::FieldBlocked);
}
self.set_checkers(player, Position::Board(field), -1)?;
self.set_checkers(player, Position::Board(target_field), 1)
} else {
if !self.ready_for_off_play(player)? {
return Err(Error::MoveInvalidOff);
}
self.set_checkers(player, Position::Board(field), -1)?;
self.set_checkers(player, Position::Off, 1)
}
}
None => {
if !self.ready_for_off_play(player)? {
return Err(Error::MoveInvalidOff);
}
let has_higher_checkers = (field + 1..5).any(|f| {
self.has_checker_at(player, Position::Board(f))
.unwrap_or(true)
});
if has_higher_checkers {
return Err(Error::MoveInvalidOff);
}
self.set_checkers(player, Position::Board(field), -1)?;
self.set_checkers(player, Position::Off, 1)
}
}
}
Position::Off => Err(Error::MoveInvalid),
}
}
fn available_moves_by_dice(
&self,
player: Player,
dice: u8,
) -> Result<Vec<(Position, Position)>, Error> {
if !(1..=6).contains(&dice) {
return Err(Error::DiceInvalid);
}
let mut available = Vec::new();
if !self.is_bar_empty(player)? {
let target = 25 - dice as usize;
if self.is_available(player, Position::Board(target))? {
available.push((Position::Bar, Position::Board(target)));
}
return Ok(available);
}
let board_iter = match player {
Player::Player0 => self.raw_board.0.board.iter().enumerate(),
Player::Player1 => self.raw_board.1.board.iter().enumerate(),
Player::Nobody => unreachable!("handled above"),
};
for (raw_field, &checkers) in board_iter {
if checkers == 0 {
continue;
}
match raw_field.checked_sub(dice as usize) {
Some(target_field) => {
if !self.is_blocked(player, Position::Board(target_field + 1))? {
available.push((
Position::Board(raw_field + 1),
Position::Board(target_field + 1),
));
}
}
None => {
if !self.ready_for_off_play(player)? {
continue;
}
if raw_field + 1 == dice as usize {
available.push((Position::Board(raw_field + 1), Position::Off));
}
else {
let has_higher_checkers = (raw_field + 1..5).any(|f| {
self.has_checker_at(player, Position::Board(f + 1))
.unwrap_or(true)
});
if !has_higher_checkers {
available.push((Position::Board(raw_field + 1), Position::Off));
}
}
}
}
}
Ok(available)
}
}
#[derive(Debug, Clone, PartialEq)]
struct PlayerBoard {
board: [u8; 24],
bar: u8,
off: u8,
}
impl Default for PlayerBoard {
fn default() -> Self {
PlayerBoard {
board: [
0, 0, 0, 0, 0, 5, 0, 3, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,
],
bar: 0,
off: 0,
}
}
}
pub trait Move {
fn get_board(&self) -> BoardDisplay;
fn move_checkers(
&mut self,
player: Player,
moves: Vec<(Position, Position)>,
) -> Result<(), Error>;
fn available_moves(&self, player: Player) -> Result<Vec<Vec<(Position, Position)>>, Error>;
fn set_checkers(&mut self, player: Player, to: Position, amount: i8) -> Result<(), Error>;
fn empty_board(&mut self) -> Result<(), Error>;
}
impl Move for Board {
fn get_board(&self) -> BoardDisplay {
let mut board: [i8; 24] = [0; 24];
for (i, val) in board.iter_mut().enumerate() {
*val = self.raw_board.0.board[i] as i8 - self.raw_board.1.board[23 - i] as i8;
}
BoardDisplay {
board,
bar: (
self.get_bar(Player::Player0).unwrap(),
self.get_bar(Player::Player1).unwrap(),
),
off: (
self.get_off(Player::Player0).unwrap(),
self.get_off(Player::Player1).unwrap(),
),
dice: self.get_dice(),
}
}
fn move_checkers(
&mut self,
player: Player,
moves: Vec<(Position, Position)>,
) -> Result<(), Error> {
if player == Player::Nobody {
return Err(Error::PlayerInvalid);
}
for (from, to) in moves {
if !self.has_checker_at(player, from)? {
return Err(Error::MoveInvalid);
}
match from {
Position::Bar => match to {
Position::Off => {
return Err(Error::MoveInvalidOff);
}
Position::Board(target_field) => {
if !(19..=24).contains(&target_field) {
return Err(Error::FieldInvalid);
}
if self.is_blocked(player, Position::Board(target_field))? {
return Err(Error::FieldBlocked);
}
let dice_to_consume = 25 - target_field as u8;
if !self.dice_available().contains(&dice_to_consume) {
return Err(Error::DiceInvalid);
}
self.set_checkers(player, Position::Bar, -1)?;
self.set_checkers(player, Position::Board(target_field), 1)?;
self.dice.consume(dice_to_consume)?;
}
Position::Bar => {
return Err(Error::MoveInvalid);
}
},
Position::Board(source_field) => {
match to {
Position::Off => {
if !self.ready_for_off_play(player)? {
return Err(Error::MoveInvalidOff);
}
if self.dice_available().contains(&(source_field as u8)) {
self.set_checkers(player, Position::Board(source_field), -1)?;
self.set_checkers(player, Position::Off, 1)?;
self.dice.consume(source_field as u8)?;
}
else {
if (source_field + 1..5).any(|f| {
self.has_checker_at(player, Position::Board(f))
.unwrap_or(true)
}) {
return Err(Error::MoveInvalidOff);
}
for x in source_field + 1..5 {
if self.dice_available().contains(&(x as u8)) {
self.set_checkers(
player,
Position::Board(source_field),
-1,
)?;
self.set_checkers(player, Position::Off, 1)?;
self.dice.consume(x as u8)?;
}
}
}
}
Position::Board(target_field) => {
if !(1..=24).contains(&target_field) {
return Err(Error::FieldInvalid);
}
if source_field < target_field {
return Err(Error::MoveInvalid);
}
if self.is_blocked(player, Position::Board(target_field))? {
return Err(Error::FieldBlocked);
}
let dice_to_consume = (source_field - target_field) as u8;
if !self.dice_available().contains(&dice_to_consume) {
return Err(Error::DiceInvalid);
}
self.set_checkers(player, Position::Board(source_field), -1)?;
self.set_checkers(player, Position::Board(target_field), 1)?;
self.dice.consume(dice_to_consume)?;
}
Position::Bar => {
return Err(Error::MoveInvalid);
}
}
}
Position::Off => {
return Err(Error::MoveInvalid);
}
}
}
Ok(())
}
fn set_checkers(&mut self, player: Player, to: Position, amount: i8) -> Result<(), Error> {
if player == Player::Nobody {
return Err(Error::PlayerInvalid);
}
if amount == 0 {
return Ok(());
}
if self.is_blocked(player, to)? {
return Err(Error::FieldBlocked);
}
let (player_board, opponent_board) = match player {
Player::Player0 => (&mut self.raw_board.0, &mut self.raw_board.1),
Player::Player1 => (&mut self.raw_board.1, &mut self.raw_board.0),
Player::Nobody => unreachable!("handled above"),
};
match to {
Position::Board(field) => {
let new = player_board.board[field - 1] as i8 + amount;
if new < 0 {
return Err(Error::MoveInvalid);
}
player_board.board[field - 1] = new as u8;
opponent_board.bar += opponent_board.board[24 - field];
opponent_board.board[24 - field] = 0;
Ok(())
}
Position::Off => {
if amount < 0 {
return Err(Error::MoveInvalid);
}
player_board.off += amount as u8;
Ok(())
}
Position::Bar => {
let new = player_board.bar as i8 + amount;
if new < 0 {
return Err(Error::MoveInvalid);
}
player_board.bar = new as u8;
Ok(())
}
}
}
fn empty_board(&mut self) -> Result<(), Error> {
self.raw_board.0 = PlayerBoard {
board: [0; 24],
bar: 0,
off: 0,
};
self.raw_board.1 = PlayerBoard {
board: [0; 24],
bar: 0,
off: 0,
};
Ok(())
}
fn available_moves(&self, player: Player) -> Result<Vec<Vec<(Position, Position)>>, Error> {
let available_dice = self.dice_available();
if available_dice.is_empty() {
return Ok(vec![]);
}
let max_die_value = *available_dice.iter().max().unwrap_or(&0);
let permutations_with_info: Vec<(Vec<u8>, u8)> = if available_dice.len() == 2 {
vec![
(
vec![available_dice[0], available_dice[1]],
available_dice[0],
),
(
vec![available_dice[1], available_dice[0]],
available_dice[1],
),
]
} else {
vec![(available_dice.clone(), available_dice[0])]
};
fn backtrack(
board: &Board,
player: Player,
dice_sequence: &[u8],
start_die_value: u8, current_sequence: &mut Vec<(Position, Position)>,
all_sequences: &mut Vec<(Vec<(Position, Position)>, u8)>,
) -> Result<(), Error> {
if dice_sequence.is_empty() {
if !current_sequence.is_empty() {
all_sequences.push((current_sequence.clone(), start_die_value));
}
return Ok(());
}
let current_die = dice_sequence[0];
let moves = board.available_moves_by_dice(player, current_die)?;
if moves.is_empty() {
if !current_sequence.is_empty() {
all_sequences.push((current_sequence.clone(), start_die_value));
}
return Ok(());
}
for (from, to) in moves {
let mut new_board = board.clone();
new_board.move_by_dice(player, current_die, from)?;
current_sequence.push((from, to));
backtrack(
&new_board,
player,
&dice_sequence[1..],
start_die_value,
current_sequence,
all_sequences,
)?;
let _ = current_sequence.pop();
}
Ok(())
}
let mut raw_results: Vec<(Vec<(Position, Position)>, u8)> = Vec::new();
for (seq, start_die) in permutations_with_info {
let mut current_sequence = Vec::new();
backtrack(
self,
player,
&seq,
start_die,
&mut current_sequence,
&mut raw_results,
)?;
}
if raw_results.is_empty() {
return Ok(vec![]);
}
let max_len = raw_results.iter().map(|(seq, _)| seq.len()).max().unwrap();
if max_len == 1 && available_dice.len() == 2 && available_dice[0] != available_dice[1] {
let can_play_max_die = raw_results
.iter()
.any(|(_, die_val)| *die_val == max_die_value);
if can_play_max_die {
raw_results.retain(|(_, die_val)| *die_val == max_die_value);
}
}
let final_moves = raw_results.into_iter().map(|(seq, _)| seq).collect();
Ok(final_moves)
}
}
impl Roll for Board {
fn roll(&mut self, player: Player) -> Result<(), Error> {
self.dice.roll(player)
}
fn get_dice(&self) -> (u8, u8) {
self.dice.get_dice()
}
fn set_dice(&mut self, player: Player, v: (u8, u8)) -> Result<(), Error> {
self.dice.set_dice(player, v)
}
fn dice_available(&self) -> &Vec<u8> {
self.dice.dice_available()
}
fn dice_consumed(&self) -> bool {
self.dice.dice_consumed()
}
}
impl Stats for Board {
fn pip(&self, player: Player) -> Result<u8, Error> {
let player_board = match player {
Player::Player0 => &self.raw_board.0,
Player::Player1 => &self.raw_board.1,
Player::Nobody => {
return Err(Error::PlayerInvalid);
}
};
let pip: u8 = player_board
.board
.iter()
.enumerate()
.map(|(index, &value)| (index + 1) as u8 * value)
.sum();
Ok(pip)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn default_board() {
assert_eq!(Board::new(), Board::default());
}
#[test]
fn default_player_board() {
assert_eq!(
PlayerBoard::default(),
PlayerBoard {
board: [
0, 0, 0, 0, 0, 5, 0, 3, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,
],
bar: 0,
off: 0,
}
);
}
#[test]
fn get_board() {
let board = Board::new();
assert_eq!(
board.get_board(),
BoardDisplay {
board: [
-2, 0, 0, 0, 0, 5, 0, 3, 0, 0, 0, -5, 5, 0, 0, 0, -3, 0, -5, 0, 0, 0, 0, 2,
],
bar: (0, 0),
off: (0, 0),
dice: (0, 0),
}
);
}
#[test]
fn get_bar() {
let board = Board::new();
assert_eq!(board.get_bar(Player::Player0).unwrap(), 0);
assert_eq!(board.get_bar(Player::Player1).unwrap(), 0);
}
#[test]
fn get_off() {
let board = Board::new();
assert_eq!(board.get_off(Player::Player0).unwrap(), 0);
assert_eq!(board.get_off(Player::Player1).unwrap(), 0);
}
#[test]
fn board_display_fmt() {
let board_display = BoardDisplay {
board: [
1, -1, 2, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
],
bar: (3, 2),
off: (5, 7),
dice: (0, 0),
};
assert_eq!(
format!("{}", board_display),
"Board: [1, -1, 2, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], Bar: (3, 2), Off: (5, 7), Dice: (0, 0)"
);
}
#[test]
fn empty_board() -> Result<(), Error> {
let mut board = Board::new();
board.empty_board()?;
assert_eq!(
board.get_board(),
BoardDisplay {
board: [0; 24],
bar: (0, 0),
off: (0, 0),
dice: (0, 0),
}
);
Ok(())
}
#[test]
fn set() -> Result<(), Error> {
let mut board = Board::new();
board.set_checkers(Player::Player0, Position::Board(2), 1)?;
board.set_checkers(Player::Player0, Position::Board(24), 100)?;
board.set_checkers(Player::Player1, Position::Board(2), 1)?;
board.set_checkers(Player::Player1, Position::Board(24), 100)?;
assert_eq!(board.get_board().board[1], 1);
assert_eq!(board.get_board().board[23], 102);
assert_eq!(board.get_board().board[0], -102);
assert_eq!(board.get_board().board[22], -1);
Ok(())
}
#[test]
fn set_for_nobody() -> Result<(), Error> {
let mut board = Board::new();
let result = board.set_checkers(Player::Nobody, Position::Board(2), 1);
assert_eq!(result, Err(Error::PlayerInvalid));
Ok(())
}
#[test]
fn set_bar() -> Result<(), Error> {
let mut board = Board::new();
board.set_checkers(Player::Player0, Position::Bar, 1)?;
board.set_checkers(Player::Player1, Position::Bar, 100)?;
assert_eq!(board.get_board().bar, (1, 100));
Ok(())
}
#[test]
fn set_bar_invalid() -> Result<(), Error> {
let mut board = Board::new();
let result = board.set_checkers(Player::Player1, Position::Bar, -1);
assert!(result.is_err());
assert_eq!(result.unwrap_err(), Error::MoveInvalid);
let result = board.set_checkers(Player::Player0, Position::Bar, -1);
assert!(result.is_err());
assert_eq!(result.unwrap_err(), Error::MoveInvalid);
Ok(())
}
#[test]
fn set_off() -> Result<(), Error> {
let mut board = Board::new();
board.set_checkers(Player::Player0, Position::Off, 1)?;
board.set_checkers(Player::Player1, Position::Off, 1)?;
assert_eq!(board.get_board().off, (1, 1));
Ok(())
}
#[test]
fn set_off1() -> Result<(), Error> {
let mut board = Board::new();
board.set_checkers(Player::Player0, Position::Off, 1)?;
board.set_checkers(Player::Player0, Position::Off, 1)?;
board.set_checkers(Player::Player1, Position::Off, 1)?;
board.set_checkers(Player::Player1, Position::Off, 1)?;
assert_eq!(board.get_board().off, (2, 2));
Ok(())
}
#[test]
fn set_player_nobody() {
let mut board = Board::new();
assert!(
board
.set_checkers(Player::Nobody, Position::Board(0), 1)
.is_err()
);
assert_eq!(
board.set_checkers(Player::Nobody, Position::Board(0), 1),
Err(Error::PlayerInvalid)
);
assert!(
board
.set_checkers(Player::Nobody, Position::Bar, 1)
.is_err()
);
assert_eq!(
board.set_checkers(Player::Nobody, Position::Bar, 0),
Err(Error::PlayerInvalid)
);
assert!(
board
.set_checkers(Player::Nobody, Position::Off, 1)
.is_err()
);
assert_eq!(
board.set_checkers(Player::Nobody, Position::Off, 1),
Err(Error::PlayerInvalid)
);
}
#[test]
fn set_hit_checker() -> Result<(), Error> {
let mut board = Board::new();
board.set_checkers(Player::Player0, Position::Board(2), 1)?;
board.set_checkers(Player::Player1, Position::Board(23), 1)?;
assert_eq!(board.get_board().board[1], -1);
assert_eq!(board.get_board().bar.0, 1);
board.set_checkers(Player::Player1, Position::Bar, 5)?;
board.set_checkers(Player::Player1, Position::Board(2), 1)?;
board.set_checkers(Player::Player0, Position::Board(23), 1)?;
assert_eq!(board.get_board().board[22], 1);
assert_eq!(board.get_board().bar.1, 6);
Ok(())
}
#[test]
fn set_field_with_2_checkers() -> Result<(), Error> {
let mut board = Board::new();
board.set_checkers(Player::Player0, Position::Board(24), 2)?;
assert_eq!(board.get_board().board[23], 4);
board.set_checkers(Player::Player1, Position::Board(24), 2)?;
assert_eq!(board.get_board().board[0], -4);
Ok(())
}
#[test]
fn set_field_remove_checkers() -> Result<(), Error> {
let mut board = Board::new();
board.set_checkers(Player::Player0, Position::Board(24), -1)?;
assert_eq!(board.get_board().board[23], 1);
board.set_checkers(Player::Player1, Position::Board(24), -1)?;
assert_eq!(board.get_board().board[0], -1);
Ok(())
}
#[test]
fn set_field_blocked() {
let mut board = Board::new();
assert_eq!(
board
.set_checkers(Player::Player0, Position::Board(1), 2)
.unwrap_err(),
Error::FieldBlocked
);
assert_eq!(
board
.set_checkers(Player::Player1, Position::Board(1), 2)
.unwrap_err(),
Error::FieldBlocked
);
}
#[test]
fn set_wrong_field1() {
let mut board = Board::new();
assert_eq!(
board
.set_checkers(Player::Player0, Position::Board(50), 2)
.unwrap_err(),
Error::FieldInvalid
);
assert!(
board
.set_checkers(Player::Player1, Position::Board(1000), 2)
.is_err()
);
}
#[test]
fn set_wrong_amount() {
let mut board = Board::new();
assert_eq!(
board
.set_checkers(Player::Player0, Position::Board(23), -3)
.unwrap_err(),
Error::MoveInvalid
);
assert_eq!(
board
.set_checkers(Player::Player1, Position::Board(23), -3)
.unwrap_err(),
Error::MoveInvalid
);
}
#[test]
fn set_multiple() -> Result<(), Error> {
let mut board = Board::new();
board.set_checkers(Player::Player0, Position::Board(6), 2)?; board.set_checkers(Player::Player0, Position::Board(6), -3)?; assert_eq!(board.get_board().board[5], 4);
Ok(())
}
#[test]
fn set_player0_hitting_clears_opponent_field() -> Result<(), Error> {
let mut board = Board::new();
board.empty_board()?;
board.set_checkers(Player::Player0, Position::Board(11), 1)?;
board.set_checkers(Player::Player1, Position::Board(17), 1)?;
board.move_by_dice(Player::Player0, 3, Position::Board(11))?;
assert_eq!(board.get_board().board[10], 0, "Original field is empty.");
assert_eq!(
board.get_board().board[7],
1,
"Destination has a Player0 checker."
);
assert_eq!(
board.get_board().bar.1,
1,
"Player1 checker should be on the bar."
);
Ok(())
}
#[test]
fn set_player0_zero_amount_no_change() -> Result<(), Error> {
let mut board = Board::new();
let before = board.get_board().board[5];
board.set_checkers(Player::Player0, Position::Board(5), 0)?;
assert_eq!(board.get_board().board[5], before);
Ok(())
}
#[test]
fn set_player1_zero_amount_no_change() -> Result<(), Error> {
let mut board = Board::new();
let before = board.get_board().board[5];
board.set_checkers(Player::Player1, Position::Board(18), 0)?;
assert_eq!(board.get_board().board[5], before);
Ok(())
}
#[test]
fn set_off_invalid_player() {
let mut board = Board::new();
let result = board.set_checkers(Player::Nobody, Position::Off, 1);
assert_eq!(result, Err(Error::PlayerInvalid));
}
#[test]
fn set_for_invalid_player() {
let mut board = Board::new();
let result = board.set_checkers(Player::Nobody, Position::Board(0), 1);
assert_eq!(result, Err(Error::PlayerInvalid));
}
#[test]
fn is_bar_empty_invalid_player() {
let board = Board::new();
let result = board.is_bar_empty(Player::Nobody);
assert_eq!(result, Err(Error::PlayerInvalid));
}
#[test]
fn is_bar_empty() -> Result<(), Error> {
let mut board = Board::new();
board.set_checkers(Player::Player0, Position::Bar, 1)?;
let result = board.is_bar_empty(Player::Player0);
assert_eq!(result, Ok(false));
Ok(())
}
#[test]
fn move_checker_player0_from_board() -> Result<(), Error> {
let mut board = Board::new();
board.move_by_dice(Player::Player0, 3, Position::Board(24))?;
assert_eq!(board.get_board().board[23], 1); assert_eq!(board.get_board().board[20], 1); Ok(())
}
#[test]
fn move_checker_player1_from_board() -> Result<(), Error> {
let mut board = Board::new();
board.move_by_dice(Player::Player1, 3, Position::Board(24))?;
assert_eq!(board.get_board().board[0], -1);
Ok(())
}
#[test]
fn move_checker_off_when_not_ready_returns_error() -> Result<(), Error> {
let mut board = Board::new();
let result = board.move_by_dice(Player::Player0, 3, Position::Board(2));
assert_eq!(result, Err(Error::MoveInvalidOff));
Ok(())
}
#[test]
fn move_checker_off() -> Result<(), Error> {
let mut board = Board::new();
board.empty_board()?;
board.set_checkers(Player::Player0, Position::Board(2), 2)?;
board.set_checkers(Player::Player0, Position::Board(1), 2)?;
let result = board.move_by_dice(Player::Player0, 1, Position::Board(2));
assert_eq!(result, Ok(()));
assert_eq!(board.get_board().off, (0, 0));
let result = board.move_by_dice(Player::Player0, 1, Position::Board(1));
assert_eq!(result, Ok(()));
assert_eq!(board.get_board().off, (1, 0));
let result = board.move_by_dice(Player::Player0, 2, Position::Board(2));
assert_eq!(result, Ok(()));
assert_eq!(board.get_board().off, (2, 0));
Ok(())
}
#[test]
fn ready_for_off_play_player1_when_ready() -> Result<(), Error> {
let mut board = Board::new();
board.empty_board()?;
board.set_checkers(Player::Player1, Position::Board(3), 5)?;
board.set_checkers(Player::Player1, Position::Board(6), 10)?;
assert!(board.ready_for_off_play(Player::Player1)?);
board.set_checkers(Player::Player1, Position::Board(7), 10)?;
assert!(!board.ready_for_off_play(Player::Player1)?);
Ok(())
}
#[test]
fn blocked() -> Result<(), Error> {
let board = Board::new();
assert!(board.is_blocked(Player::Player0, Position::Board(1))?);
assert!(board.is_blocked(Player::Player1, Position::Board(1))?);
Ok(())
}
#[test]
fn blocked_player() -> Result<(), Error> {
let mut board = Board::new();
board.set_checkers(Player::Player1, Position::Board(2), 2)?;
assert!(board.is_blocked(Player::Player0, Position::Board(23))?);
board.set_checkers(Player::Player0, Position::Board(2), 2)?;
assert!(board.is_blocked(Player::Player1, Position::Board(23))?);
Ok(())
}
#[test]
fn blocked_invalid_player() {
let board = Board::new();
assert_eq!(
board
.is_blocked(Player::Nobody, Position::Board(0))
.unwrap_err(),
Error::PlayerInvalid
);
}
#[test]
fn blocked_invalid_field() {
let board = Board::new();
assert!(
board
.is_blocked(Player::Player0, Position::Board(25))
.is_err()
);
assert_eq!(
board.is_blocked(Player::Player0, Position::Board(25)),
Err(Error::FieldInvalid)
);
assert!(
board
.is_blocked(Player::Player1, Position::Board(25))
.is_err()
);
assert_eq!(
board.is_blocked(Player::Player1, Position::Board(25)),
Err(Error::FieldInvalid)
);
assert!(
board
.is_blocked(Player::Player0, Position::Board(0))
.is_err()
);
assert_eq!(
board.is_blocked(Player::Player0, Position::Board(0)),
Err(Error::FieldInvalid)
);
assert!(
board
.is_blocked(Player::Player1, Position::Board(0))
.is_err()
);
assert_eq!(
board.is_blocked(Player::Player1, Position::Board(0)),
Err(Error::FieldInvalid)
);
}
#[test]
fn move_checker_invalid_dice() {
let mut board = Board::new();
let result = board.move_by_dice(Player::Player0, 0, Position::Board(23));
assert_eq!(result, Err(Error::DiceInvalid));
let result = board.move_by_dice(Player::Player0, 7, Position::Board(23));
assert_eq!(result, Err(Error::DiceInvalid));
}
#[test]
fn move_checker_invalid_player() {
let mut board = Board::new();
let result = board.move_by_dice(Player::Nobody, 3, Position::Board(23));
assert_eq!(result, Err(Error::PlayerInvalid));
}
#[test]
fn move_checker_from_bar_player0() -> Result<(), Error> {
let mut board = Board::new();
board.set_checkers(Player::Player0, Position::Bar, 1)?;
board.move_by_dice(Player::Player0, 3, Position::Bar)?;
assert_eq!(board.get_board().bar.0, 0);
assert_eq!(board.get_board().board[21], 1);
board.set_checkers(Player::Player1, Position::Bar, 1)?;
board.move_by_dice(Player::Player1, 3, Position::Bar)?;
assert_eq!(board.get_board().bar.1, 0);
assert_eq!(board.get_board().board[2], -1);
Ok(())
}
#[test]
fn move_checker_from_bar_blocked() -> Result<(), Error> {
let mut board = Board::new();
board.set_checkers(Player::Player0, Position::Bar, 1)?;
let result = board.move_by_dice(Player::Player0, 6, Position::Bar);
assert_eq!(result, Err(Error::FieldBlocked));
board.set_checkers(Player::Player1, Position::Bar, 1)?;
let result = board.move_by_dice(Player::Player1, 6, Position::Bar);
assert_eq!(result, Err(Error::FieldBlocked));
Ok(())
}
#[test]
fn move_checker_from_bar_hitting_opponent() -> Result<(), Error> {
let mut board = Board::new();
board.empty_board()?;
board.set_checkers(Player::Player0, Position::Bar, 1)?;
board.set_checkers(Player::Player1, Position::Board(4), 1)?; board.move_by_dice(Player::Player0, 4, Position::Bar)?;
assert_eq!(board.get_board().bar.0, 0);
assert_eq!(board.get_board().board[20], 1);
assert_eq!(board.get_board().bar.1, 1);
Ok(())
}
#[test]
fn move_checker_from_board_with_bar_not_empty() -> Result<(), Error> {
let mut board = Board::new();
board.set_checkers(Player::Player0, Position::Bar, 1)?;
let result = board.move_by_dice(Player::Player0, 3, Position::Board(23));
assert_eq!(result, Err(Error::MoveInvalidBar));
Ok(())
}
#[test]
fn move_checker_normal_move_blocked() -> Result<(), Error> {
let mut board = Board::new();
board.empty_board()?;
board.set_checkers(Player::Player0, Position::Board(11), 1)?;
board.set_checkers(Player::Player1, Position::Board(17), 2)?; let result = board.move_by_dice(Player::Player0, 3, Position::Board(11));
assert_eq!(result, Err(Error::FieldBlocked));
Ok(())
}
#[test]
fn move_checker_bearing_off_exact_dice() -> Result<(), Error> {
let mut board = Board::new();
board.empty_board()?;
board.set_checkers(Player::Player0, Position::Board(4), 1)?;
board.set_checkers(Player::Player0, Position::Board(6), 14)?;
board.move_by_dice(Player::Player0, 3, Position::Board(4))?;
assert_eq!(board.get_board().board[3], 0);
assert_eq!(board.get_board().board[0], 1);
Ok(())
}
#[test]
fn move_checker_bearing_off2() -> Result<(), Error> {
let mut board = Board::new();
board.empty_board()?;
board.set_checkers(Player::Player0, Position::Board(3), 1)?;
board.move_by_dice(Player::Player0, 5, Position::Board(3))?;
assert_eq!(board.get_board().board[3], 0);
assert_eq!(board.get_off(Player::Player0)?, 1);
Ok(())
}
#[test]
fn move_checker_all_dice_values() -> Result<(), Error> {
for dice in 1..=6 {
let mut board = Board::new();
board.empty_board()?;
board.set_checkers(Player::Player0, Position::Board(13), 1)?;
board.move_by_dice(Player::Player0, dice, Position::Board(13))?;
assert_eq!(board.get_board().board[12], 0);
assert_eq!(board.get_board().board[(12 - dice) as usize], 1);
}
Ok(())
}
#[test]
fn move_checker_from_bar_all_dice_values() -> Result<(), Error> {
for dice in 1..=6 {
let mut board = Board::new();
board.empty_board()?;
board.set_checkers(Player::Player0, Position::Bar, 1)?;
board.move_by_dice(Player::Player0, dice, Position::Bar)?;
assert_eq!(board.get_board().bar.0, 0);
assert_eq!(board.get_board().board[(24 - dice) as usize], 1);
}
Ok(())
}
#[test]
fn ready_for_off_play_player_nobody() {
let board = Board::new();
let result = board.ready_for_off_play(Player::Nobody);
assert_eq!(result, Err(Error::PlayerInvalid));
}
#[test]
fn move_checker_from_bar_all() -> Result<(), Error> {
let mut board = Board::new();
board.set_checkers(Player::Player0, Position::Bar, 6)?;
let m1 = board.move_by_dice(Player::Player0, 1, Position::Bar);
let m2 = board.move_by_dice(Player::Player0, 2, Position::Bar);
let m3 = board.move_by_dice(Player::Player0, 3, Position::Bar);
let m4 = board.move_by_dice(Player::Player0, 4, Position::Bar);
let m5 = board.move_by_dice(Player::Player0, 5, Position::Bar);
let m6 = board.move_by_dice(Player::Player0, 6, Position::Bar);
assert!(m1.is_ok());
assert!(m2.is_ok());
assert!(m3.is_ok());
assert!(m4.is_ok());
assert!(m5.is_ok());
assert!(m6.is_err());
Ok(())
}
#[test]
fn pip_empty_board() -> Result<(), Error> {
let mut board = Board::new();
board.empty_board()?;
let pip = board.pip(Player::Player0)?;
assert_eq!(pip, 0);
Ok(())
}
#[test]
fn pip_invalid_player() -> Result<(), Error> {
let board = Board::new();
let pip = board.pip(Player::Nobody);
assert_eq!(pip, Err(Error::PlayerInvalid));
Ok(())
}
#[test]
fn available_moves_player_nobody() {
let board = Board::new();
let result = board.available_moves_by_dice(Player::Nobody, 3);
assert_eq!(result, Err(Error::PlayerInvalid));
}
#[test]
fn available_moves_empty_board() -> Result<(), Error> {
let mut board = Board::new();
board.empty_board()?;
let moves = board.available_moves_by_dice(Player::Player0, 3)?;
assert!(moves.is_empty());
Ok(())
}
#[test]
fn available_moves_blocked_field() -> Result<(), Error> {
let mut board = Board::new();
board.empty_board()?;
board.set_checkers(Player::Player0, Position::Board(11), 1)?;
board.set_checkers(Player::Player1, Position::Board(17), 2)?; let moves = board.available_moves_by_dice(Player::Player0, 3)?;
assert!(moves.is_empty());
Ok(())
}
#[test]
fn available_moves_blocked_field1() -> Result<(), Error> {
let mut board = Board::new();
board.empty_board()?;
board.set_checkers(Player::Player0, Position::Board(11), 1)?;
board.set_checkers(Player::Player1, Position::Board(17), 2)?; board.set_checkers(Player::Player0, Position::Board(2), 1)?;
let moves = board.available_moves_by_dice(Player::Player0, 3)?;
assert!(moves.is_empty());
Ok(())
}
#[test]
fn available_moves_with_bearing_off() -> Result<(), Error> {
let mut board = Board::new();
board.empty_board()?;
board.set_checkers(Player::Player0, Position::Board(5), 2)?;
board.set_checkers(Player::Player0, Position::Board(3), 3)?;
let moves = board.available_moves_by_dice(Player::Player0, 6)?;
assert_eq!(moves, vec![(Position::Board(5), Position::Off)]);
assert_eq!(moves.len(), 1);
Ok(())
}
#[test]
fn available_moves_with_bearing_off1() -> Result<(), Error> {
let mut board = Board::new();
board.empty_board()?;
board.set_checkers(Player::Player0, Position::Board(4), 2)?;
board.set_checkers(Player::Player0, Position::Board(3), 3)?;
let moves = board.available_moves_by_dice(Player::Player0, 6)?;
assert_eq!(moves, vec![(Position::Board(4), Position::Off)]);
assert_eq!(moves.len(), 1);
Ok(())
}
#[test]
fn available_moves_single_checker_can_hit0() -> Result<(), Error> {
let mut board = Board::new();
board.empty_board()?;
board.set_checkers(Player::Player0, Position::Board(10), 1)?;
board.set_checkers(Player::Player1, Position::Board(16), 1)?; let moves = board.available_moves_by_dice(Player::Player0, 3)?;
assert!(moves.contains(&(Position::Board(10), Position::Board(7))));
Ok(())
}
#[test]
fn available_moves_single_checker_can_hit1() -> Result<(), Error> {
let mut board = Board::new();
board.empty_board()?;
board.set_checkers(Player::Player1, Position::Board(10), 1)?;
board.set_checkers(Player::Player0, Position::Board(16), 1)?; let moves = board.available_moves_by_dice(Player::Player1, 3)?;
assert!(moves.contains(&(Position::Board(10), Position::Board(7))));
Ok(())
}
#[test]
fn available_field_invalid() {
let board = Board::new();
assert_eq!(
board.is_available(Player::Player0, Position::Board(25)),
Err(Error::FieldInvalid)
);
assert_eq!(
board.is_available(Player::Player0, Position::Board(0)),
Err(Error::FieldInvalid)
);
}
#[test]
fn is_available() -> Result<(), Error> {
let board = Board::new();
assert!(board.is_available(Player::Player0, Position::Board(6))?);
assert!(board.is_available(Player::Player0, Position::Board(3))?);
assert!(board.is_available(Player::Player0, Position::Board(24))?);
assert!(board.is_available(Player::Player1, Position::Board(6))?);
assert!(board.is_available(Player::Player1, Position::Board(3))?);
assert!(board.is_available(Player::Player1, Position::Board(24))?);
assert!(!board.is_available(Player::Player0, Position::Board(1))?);
assert!(!board.is_available(Player::Player1, Position::Board(1))?);
Ok(())
}
#[test]
fn is_available_player_nobody() {
let board = Board::new();
assert_eq!(
board.is_available(Player::Nobody, Position::Bar),
Err(Error::PlayerInvalid)
);
}
#[test]
fn available_moves_bar_not_empty_and_available() -> Result<(), Error> {
let mut board = Board::new();
board.empty_board()?;
board.set_checkers(Player::Player0, Position::Bar, 1)?;
let moves = board.available_moves_by_dice(Player::Player0, 3)?;
assert_eq!(moves.len(), 1);
assert_eq!(moves[0], (Position::Bar, Position::Board(22)));
Ok(())
}
#[test]
fn available_moves_bar_not_empty_and_blocked() -> Result<(), Error> {
let mut board = Board::new();
board.empty_board()?;
board.set_checkers(Player::Player0, Position::Bar, 1)?;
board.set_checkers(Player::Player1, Position::Board(3), 2)?;
let moves = board.available_moves_by_dice(Player::Player0, 3)?;
assert!(moves.is_empty());
Ok(())
}
#[test]
fn move_checker_dice_invalid_returns_error() {
let board = Board::new();
let result = board.available_moves_by_dice(Player::Player0, 0);
assert_eq!(result, Err(Error::DiceInvalid));
}
#[test]
fn move_checker_dice_invalid_returns_error1() {
let board = Board::new();
let result = board.available_moves_by_dice(Player::Player0, 7);
assert_eq!(result, Err(Error::DiceInvalid));
}
#[test]
fn move_checker_player_invalid_returns_error() {
let board = Board::new();
let result = board.available_moves_by_dice(Player::Nobody, 2);
assert_eq!(result, Err(Error::PlayerInvalid));
}
#[test]
fn all_available_moves() -> Result<(), Error> {
let mut board = Board::new();
board.set_dice(Player::Nobody, (1, 2))?;
let sequences = board.available_moves(Player::Player0)?;
assert_eq!(sequences.len(), 30);
assert_eq!(
sequences,
vec![
vec![
(Position::Board(6), Position::Board(5)),
(Position::Board(5), Position::Board(3))
],
vec![
(Position::Board(6), Position::Board(5)),
(Position::Board(6), Position::Board(4))
],
vec![
(Position::Board(6), Position::Board(5)),
(Position::Board(8), Position::Board(6))
],
vec![
(Position::Board(6), Position::Board(5)),
(Position::Board(13), Position::Board(11))
],
vec![
(Position::Board(6), Position::Board(5)),
(Position::Board(24), Position::Board(22))
],
vec![
(Position::Board(8), Position::Board(7)),
(Position::Board(6), Position::Board(4))
],
vec![
(Position::Board(8), Position::Board(7)),
(Position::Board(7), Position::Board(5))
],
vec![
(Position::Board(8), Position::Board(7)),
(Position::Board(8), Position::Board(6))
],
vec![
(Position::Board(8), Position::Board(7)),
(Position::Board(13), Position::Board(11))
],
vec![
(Position::Board(8), Position::Board(7)),
(Position::Board(24), Position::Board(22))
],
vec![
(Position::Board(24), Position::Board(23)),
(Position::Board(6), Position::Board(4))
],
vec![
(Position::Board(24), Position::Board(23)),
(Position::Board(8), Position::Board(6))
],
vec![
(Position::Board(24), Position::Board(23)),
(Position::Board(13), Position::Board(11))
],
vec![
(Position::Board(24), Position::Board(23)),
(Position::Board(23), Position::Board(21))
],
vec![
(Position::Board(24), Position::Board(23)),
(Position::Board(24), Position::Board(22))
],
vec![
(Position::Board(6), Position::Board(4)),
(Position::Board(4), Position::Board(3))
],
vec![
(Position::Board(6), Position::Board(4)),
(Position::Board(6), Position::Board(5))
],
vec![
(Position::Board(6), Position::Board(4)),
(Position::Board(8), Position::Board(7))
],
vec![
(Position::Board(6), Position::Board(4)),
(Position::Board(24), Position::Board(23))
],
vec![
(Position::Board(8), Position::Board(6)),
(Position::Board(6), Position::Board(5))
],
vec![
(Position::Board(8), Position::Board(6)),
(Position::Board(8), Position::Board(7))
],
vec![
(Position::Board(8), Position::Board(6)),
(Position::Board(24), Position::Board(23))
],
vec![
(Position::Board(13), Position::Board(11)),
(Position::Board(6), Position::Board(5))
],
vec![
(Position::Board(13), Position::Board(11)),
(Position::Board(8), Position::Board(7))
],
vec![
(Position::Board(13), Position::Board(11)),
(Position::Board(11), Position::Board(10))
],
vec![
(Position::Board(13), Position::Board(11)),
(Position::Board(24), Position::Board(23))
],
vec![
(Position::Board(24), Position::Board(22)),
(Position::Board(6), Position::Board(5))
],
vec![
(Position::Board(24), Position::Board(22)),
(Position::Board(8), Position::Board(7))
],
vec![
(Position::Board(24), Position::Board(22)),
(Position::Board(22), Position::Board(21))
],
vec![
(Position::Board(24), Position::Board(22)),
(Position::Board(24), Position::Board(23))
]
]
);
Ok(())
}
#[test]
fn all_available_moves_second_dice() -> Result<(), Error> {
let mut board = Board::new();
board.empty_board()?;
board.set_checkers(Player::Player0, Position::Board(4), 1)?;
board.set_checkers(Player::Player1, Position::Board(22), 2)?;
board.set_dice(Player::Nobody, (1, 2))?;
assert!(!board.dice_consumed());
assert_eq!(board.dice_available(), &vec![1, 2]);
let sequences = board.available_moves(Player::Player0)?;
assert!(!board.dice_consumed());
assert_eq!(board.dice_available(), &vec![1, 2]);
assert_eq!(sequences.len(), 1);
assert_eq!(
sequences,
vec![vec![
(Position::Board(4), Position::Board(2)),
(Position::Board(2), Position::Board(1))
],]
);
Ok(())
}
#[test]
fn all_available_moves_same_dice() -> Result<(), Error> {
let mut board = Board::new();
board.set_dice(Player::Nobody, (6, 6))?;
let sequences = board.available_moves(Player::Player0)?;
assert_eq!(
sequences,
vec![
vec![
(Position::Board(8), Position::Board(2)),
(Position::Board(8), Position::Board(2)),
(Position::Board(8), Position::Board(2)),
(Position::Board(13), Position::Board(7))
],
vec![
(Position::Board(8), Position::Board(2)),
(Position::Board(8), Position::Board(2)),
(Position::Board(8), Position::Board(2)),
(Position::Board(24), Position::Board(18))
],
vec![
(Position::Board(8), Position::Board(2)),
(Position::Board(8), Position::Board(2)),
(Position::Board(13), Position::Board(7)),
(Position::Board(8), Position::Board(2))
],
vec![
(Position::Board(8), Position::Board(2)),
(Position::Board(8), Position::Board(2)),
(Position::Board(13), Position::Board(7)),
(Position::Board(13), Position::Board(7))
],
vec![
(Position::Board(8), Position::Board(2)),
(Position::Board(8), Position::Board(2)),
(Position::Board(13), Position::Board(7)),
(Position::Board(24), Position::Board(18))
],
vec![
(Position::Board(8), Position::Board(2)),
(Position::Board(8), Position::Board(2)),
(Position::Board(24), Position::Board(18)),
(Position::Board(8), Position::Board(2))
],
vec![
(Position::Board(8), Position::Board(2)),
(Position::Board(8), Position::Board(2)),
(Position::Board(24), Position::Board(18)),
(Position::Board(13), Position::Board(7))
],
vec![
(Position::Board(8), Position::Board(2)),
(Position::Board(8), Position::Board(2)),
(Position::Board(24), Position::Board(18)),
(Position::Board(24), Position::Board(18))
],
vec![
(Position::Board(8), Position::Board(2)),
(Position::Board(13), Position::Board(7)),
(Position::Board(8), Position::Board(2)),
(Position::Board(8), Position::Board(2))
],
vec![
(Position::Board(8), Position::Board(2)),
(Position::Board(13), Position::Board(7)),
(Position::Board(8), Position::Board(2)),
(Position::Board(13), Position::Board(7))
],
vec![
(Position::Board(8), Position::Board(2)),
(Position::Board(13), Position::Board(7)),
(Position::Board(8), Position::Board(2)),
(Position::Board(24), Position::Board(18))
],
vec![
(Position::Board(8), Position::Board(2)),
(Position::Board(13), Position::Board(7)),
(Position::Board(13), Position::Board(7)),
(Position::Board(8), Position::Board(2))
],
vec![
(Position::Board(8), Position::Board(2)),
(Position::Board(13), Position::Board(7)),
(Position::Board(13), Position::Board(7)),
(Position::Board(13), Position::Board(7))
],
vec![
(Position::Board(8), Position::Board(2)),
(Position::Board(13), Position::Board(7)),
(Position::Board(13), Position::Board(7)),
(Position::Board(24), Position::Board(18))
],
vec![
(Position::Board(8), Position::Board(2)),
(Position::Board(13), Position::Board(7)),
(Position::Board(24), Position::Board(18)),
(Position::Board(8), Position::Board(2))
],
vec![
(Position::Board(8), Position::Board(2)),
(Position::Board(13), Position::Board(7)),
(Position::Board(24), Position::Board(18)),
(Position::Board(13), Position::Board(7))
],
vec![
(Position::Board(8), Position::Board(2)),
(Position::Board(13), Position::Board(7)),
(Position::Board(24), Position::Board(18)),
(Position::Board(24), Position::Board(18))
],
vec![
(Position::Board(8), Position::Board(2)),
(Position::Board(24), Position::Board(18)),
(Position::Board(8), Position::Board(2)),
(Position::Board(8), Position::Board(2))
],
vec![
(Position::Board(8), Position::Board(2)),
(Position::Board(24), Position::Board(18)),
(Position::Board(8), Position::Board(2)),
(Position::Board(13), Position::Board(7))
],
vec![
(Position::Board(8), Position::Board(2)),
(Position::Board(24), Position::Board(18)),
(Position::Board(8), Position::Board(2)),
(Position::Board(24), Position::Board(18))
],
vec![
(Position::Board(8), Position::Board(2)),
(Position::Board(24), Position::Board(18)),
(Position::Board(13), Position::Board(7)),
(Position::Board(8), Position::Board(2))
],
vec![
(Position::Board(8), Position::Board(2)),
(Position::Board(24), Position::Board(18)),
(Position::Board(13), Position::Board(7)),
(Position::Board(13), Position::Board(7))
],
vec![
(Position::Board(8), Position::Board(2)),
(Position::Board(24), Position::Board(18)),
(Position::Board(13), Position::Board(7)),
(Position::Board(24), Position::Board(18))
],
vec![
(Position::Board(8), Position::Board(2)),
(Position::Board(24), Position::Board(18)),
(Position::Board(24), Position::Board(18)),
(Position::Board(8), Position::Board(2))
],
vec![
(Position::Board(8), Position::Board(2)),
(Position::Board(24), Position::Board(18)),
(Position::Board(24), Position::Board(18)),
(Position::Board(13), Position::Board(7))
],
vec![
(Position::Board(13), Position::Board(7)),
(Position::Board(8), Position::Board(2)),
(Position::Board(8), Position::Board(2)),
(Position::Board(8), Position::Board(2))
],
vec![
(Position::Board(13), Position::Board(7)),
(Position::Board(8), Position::Board(2)),
(Position::Board(8), Position::Board(2)),
(Position::Board(13), Position::Board(7))
],
vec![
(Position::Board(13), Position::Board(7)),
(Position::Board(8), Position::Board(2)),
(Position::Board(8), Position::Board(2)),
(Position::Board(24), Position::Board(18))
],
vec![
(Position::Board(13), Position::Board(7)),
(Position::Board(8), Position::Board(2)),
(Position::Board(13), Position::Board(7)),
(Position::Board(8), Position::Board(2))
],
vec![
(Position::Board(13), Position::Board(7)),
(Position::Board(8), Position::Board(2)),
(Position::Board(13), Position::Board(7)),
(Position::Board(13), Position::Board(7))
],
vec![
(Position::Board(13), Position::Board(7)),
(Position::Board(8), Position::Board(2)),
(Position::Board(13), Position::Board(7)),
(Position::Board(24), Position::Board(18))
],
vec![
(Position::Board(13), Position::Board(7)),
(Position::Board(8), Position::Board(2)),
(Position::Board(24), Position::Board(18)),
(Position::Board(8), Position::Board(2))
],
vec![
(Position::Board(13), Position::Board(7)),
(Position::Board(8), Position::Board(2)),
(Position::Board(24), Position::Board(18)),
(Position::Board(13), Position::Board(7))
],
vec![
(Position::Board(13), Position::Board(7)),
(Position::Board(8), Position::Board(2)),
(Position::Board(24), Position::Board(18)),
(Position::Board(24), Position::Board(18))
],
vec![
(Position::Board(13), Position::Board(7)),
(Position::Board(13), Position::Board(7)),
(Position::Board(8), Position::Board(2)),
(Position::Board(8), Position::Board(2))
],
vec![
(Position::Board(13), Position::Board(7)),
(Position::Board(13), Position::Board(7)),
(Position::Board(8), Position::Board(2)),
(Position::Board(13), Position::Board(7))
],
vec![
(Position::Board(13), Position::Board(7)),
(Position::Board(13), Position::Board(7)),
(Position::Board(8), Position::Board(2)),
(Position::Board(24), Position::Board(18))
],
vec![
(Position::Board(13), Position::Board(7)),
(Position::Board(13), Position::Board(7)),
(Position::Board(13), Position::Board(7)),
(Position::Board(8), Position::Board(2))
],
vec![
(Position::Board(13), Position::Board(7)),
(Position::Board(13), Position::Board(7)),
(Position::Board(13), Position::Board(7)),
(Position::Board(13), Position::Board(7))
],
vec![
(Position::Board(13), Position::Board(7)),
(Position::Board(13), Position::Board(7)),
(Position::Board(13), Position::Board(7)),
(Position::Board(24), Position::Board(18))
],
vec![
(Position::Board(13), Position::Board(7)),
(Position::Board(13), Position::Board(7)),
(Position::Board(24), Position::Board(18)),
(Position::Board(8), Position::Board(2))
],
vec![
(Position::Board(13), Position::Board(7)),
(Position::Board(13), Position::Board(7)),
(Position::Board(24), Position::Board(18)),
(Position::Board(13), Position::Board(7))
],
vec![
(Position::Board(13), Position::Board(7)),
(Position::Board(13), Position::Board(7)),
(Position::Board(24), Position::Board(18)),
(Position::Board(24), Position::Board(18))
],
vec![
(Position::Board(13), Position::Board(7)),
(Position::Board(24), Position::Board(18)),
(Position::Board(8), Position::Board(2)),
(Position::Board(8), Position::Board(2))
],
vec![
(Position::Board(13), Position::Board(7)),
(Position::Board(24), Position::Board(18)),
(Position::Board(8), Position::Board(2)),
(Position::Board(13), Position::Board(7))
],
vec![
(Position::Board(13), Position::Board(7)),
(Position::Board(24), Position::Board(18)),
(Position::Board(8), Position::Board(2)),
(Position::Board(24), Position::Board(18))
],
vec![
(Position::Board(13), Position::Board(7)),
(Position::Board(24), Position::Board(18)),
(Position::Board(13), Position::Board(7)),
(Position::Board(8), Position::Board(2))
],
vec![
(Position::Board(13), Position::Board(7)),
(Position::Board(24), Position::Board(18)),
(Position::Board(13), Position::Board(7)),
(Position::Board(13), Position::Board(7))
],
vec![
(Position::Board(13), Position::Board(7)),
(Position::Board(24), Position::Board(18)),
(Position::Board(13), Position::Board(7)),
(Position::Board(24), Position::Board(18))
],
vec![
(Position::Board(13), Position::Board(7)),
(Position::Board(24), Position::Board(18)),
(Position::Board(24), Position::Board(18)),
(Position::Board(8), Position::Board(2))
],
vec![
(Position::Board(13), Position::Board(7)),
(Position::Board(24), Position::Board(18)),
(Position::Board(24), Position::Board(18)),
(Position::Board(13), Position::Board(7))
],
vec![
(Position::Board(24), Position::Board(18)),
(Position::Board(8), Position::Board(2)),
(Position::Board(8), Position::Board(2)),
(Position::Board(8), Position::Board(2))
],
vec![
(Position::Board(24), Position::Board(18)),
(Position::Board(8), Position::Board(2)),
(Position::Board(8), Position::Board(2)),
(Position::Board(13), Position::Board(7))
],
vec![
(Position::Board(24), Position::Board(18)),
(Position::Board(8), Position::Board(2)),
(Position::Board(8), Position::Board(2)),
(Position::Board(24), Position::Board(18))
],
vec![
(Position::Board(24), Position::Board(18)),
(Position::Board(8), Position::Board(2)),
(Position::Board(13), Position::Board(7)),
(Position::Board(8), Position::Board(2))
],
vec![
(Position::Board(24), Position::Board(18)),
(Position::Board(8), Position::Board(2)),
(Position::Board(13), Position::Board(7)),
(Position::Board(13), Position::Board(7))
],
vec![
(Position::Board(24), Position::Board(18)),
(Position::Board(8), Position::Board(2)),
(Position::Board(13), Position::Board(7)),
(Position::Board(24), Position::Board(18))
],
vec![
(Position::Board(24), Position::Board(18)),
(Position::Board(8), Position::Board(2)),
(Position::Board(24), Position::Board(18)),
(Position::Board(8), Position::Board(2))
],
vec![
(Position::Board(24), Position::Board(18)),
(Position::Board(8), Position::Board(2)),
(Position::Board(24), Position::Board(18)),
(Position::Board(13), Position::Board(7))
],
vec![
(Position::Board(24), Position::Board(18)),
(Position::Board(13), Position::Board(7)),
(Position::Board(8), Position::Board(2)),
(Position::Board(8), Position::Board(2))
],
vec![
(Position::Board(24), Position::Board(18)),
(Position::Board(13), Position::Board(7)),
(Position::Board(8), Position::Board(2)),
(Position::Board(13), Position::Board(7))
],
vec![
(Position::Board(24), Position::Board(18)),
(Position::Board(13), Position::Board(7)),
(Position::Board(8), Position::Board(2)),
(Position::Board(24), Position::Board(18))
],
vec![
(Position::Board(24), Position::Board(18)),
(Position::Board(13), Position::Board(7)),
(Position::Board(13), Position::Board(7)),
(Position::Board(8), Position::Board(2))
],
vec![
(Position::Board(24), Position::Board(18)),
(Position::Board(13), Position::Board(7)),
(Position::Board(13), Position::Board(7)),
(Position::Board(13), Position::Board(7))
],
vec![
(Position::Board(24), Position::Board(18)),
(Position::Board(13), Position::Board(7)),
(Position::Board(13), Position::Board(7)),
(Position::Board(24), Position::Board(18))
],
vec![
(Position::Board(24), Position::Board(18)),
(Position::Board(13), Position::Board(7)),
(Position::Board(24), Position::Board(18)),
(Position::Board(8), Position::Board(2))
],
vec![
(Position::Board(24), Position::Board(18)),
(Position::Board(13), Position::Board(7)),
(Position::Board(24), Position::Board(18)),
(Position::Board(13), Position::Board(7))
],
vec![
(Position::Board(24), Position::Board(18)),
(Position::Board(24), Position::Board(18)),
(Position::Board(8), Position::Board(2)),
(Position::Board(8), Position::Board(2))
],
vec![
(Position::Board(24), Position::Board(18)),
(Position::Board(24), Position::Board(18)),
(Position::Board(8), Position::Board(2)),
(Position::Board(13), Position::Board(7))
],
vec![
(Position::Board(24), Position::Board(18)),
(Position::Board(24), Position::Board(18)),
(Position::Board(13), Position::Board(7)),
(Position::Board(8), Position::Board(2))
],
vec![
(Position::Board(24), Position::Board(18)),
(Position::Board(24), Position::Board(18)),
(Position::Board(13), Position::Board(7)),
(Position::Board(13), Position::Board(7))
]
]
);
Ok(())
}
#[test]
fn all_available_moves_bar() -> Result<(), Error> {
let mut board = Board::new();
board.empty_board()?;
board.set_checkers(Player::Player0, Position::Bar, 1)?;
board.set_checkers(Player::Player1, Position::Board(2), 2)?;
board.set_dice(Player::Nobody, (2, 1))?;
let sequences = board.available_moves(Player::Player0)?;
assert_eq!(sequences.len(), 1);
assert_eq!(
sequences,
vec![vec![
(Position::Bar, Position::Board(24)),
(Position::Board(24), Position::Board(22))
],]
);
Ok(())
}
#[test]
fn all_available_moves_off() -> Result<(), Error> {
let mut board = Board::new();
board.empty_board()?;
board.set_checkers(Player::Player0, Position::Board(2), 2)?;
board.set_checkers(Player::Player0, Position::Board(1), 2)?;
board.set_dice(Player::Nobody, (2, 1))?;
let sequences = board.available_moves(Player::Player0)?;
assert_eq!(
sequences,
vec![
vec![
(Position::Board(2), Position::Off),
(Position::Board(1), Position::Off)
],
vec![
(Position::Board(2), Position::Off),
(Position::Board(2), Position::Board(1))
],
vec![
(Position::Board(1), Position::Off),
(Position::Board(2), Position::Off)
],
vec![
(Position::Board(2), Position::Board(1)),
(Position::Board(2), Position::Off)
],
]
);
Ok(())
}
#[test]
fn all_available_no_moves1() -> Result<(), Error> {
let mut board = Board::new();
board.empty_board()?;
board.set_checkers(Player::Player0, Position::Board(11), 2)?;
board.set_checkers(Player::Player1, Position::Board(18), 2)?;
board.set_dice(Player::Nobody, (4, 4))?;
let sequences = board.available_moves(Player::Player0)?;
assert!(sequences.is_empty());
Ok(())
}
#[test]
fn all_available_dead_end_check() -> Result<(), Error> {
let mut board = Board::new();
board.empty_board()?;
board.set_checkers(Player::Player0, Position::Board(11), 2)?;
board.set_checkers(Player::Player1, Position::Board(18), 2)?;
board.set_checkers(Player::Player1, Position::Board(20), 2)?;
board.set_dice(Player::Nobody, (4, 2))?;
let sequences = board.available_moves(Player::Player0)?;
assert_eq!(
sequences,
vec![vec![(Position::Board(11), Position::Board(9))],]
);
Ok(())
}
#[test]
fn all_available_higher_die_precedence() -> Result<(), Error> {
let mut board = Board::new();
board.empty_board()?;
board.set_checkers(Player::Player0, Position::Board(24), 1)?;
board.set_checkers(Player::Player1, Position::Board(2), 2)?;
board.set_checkers(Player::Player1, Position::Board(3), 2)?;
board.set_checkers(Player::Player1, Position::Board(4), 2)?;
board.set_checkers(Player::Player1, Position::Board(5), 2)?;
board.set_checkers(Player::Player1, Position::Board(8), 2)?;
board.set_checkers(Player::Player1, Position::Board(9), 2)?;
board.set_checkers(Player::Player1, Position::Board(10), 2)?;
board.set_checkers(Player::Player1, Position::Board(11), 2)?;
board.set_checkers(Player::Player1, Position::Board(12), 2)?;
board.set_dice(Player::Nobody, (6, 5))?;
let sequences = board.available_moves(Player::Player0)?;
assert_eq!(
sequences,
vec![vec![(Position::Board(24), Position::Board(18))],]
);
Ok(())
}
#[test]
fn has_checker_at_player0_default_board() -> Result<(), Error> {
let board = Board::new();
assert!(board.has_checker_at(Player::Player0, Position::Board(6))?);
assert!(board.has_checker_at(Player::Player0, Position::Board(8))?);
assert!(board.has_checker_at(Player::Player0, Position::Board(13))?);
assert!(board.has_checker_at(Player::Player0, Position::Board(24))?);
Ok(())
}
#[test]
fn has_checker_at_player1_default_board() -> Result<(), Error> {
let board = Board::new();
assert!(board.has_checker_at(Player::Player1, Position::Board(6))?);
assert!(board.has_checker_at(Player::Player1, Position::Board(8))?);
assert!(board.has_checker_at(Player::Player1, Position::Board(13))?);
assert!(board.has_checker_at(Player::Player1, Position::Board(24))?);
Ok(())
}
#[test]
fn has_checker_at_empty_field() -> Result<(), Error> {
let board = Board::new();
assert!(!board.has_checker_at(Player::Player0, Position::Board(1))?);
assert!(!board.has_checker_at(Player::Player0, Position::Board(11))?);
assert!(!board.has_checker_at(Player::Player1, Position::Board(1))?);
assert!(!board.has_checker_at(Player::Player1, Position::Board(11))?);
Ok(())
}
#[test]
fn has_checker_at_invalid_player() {
let board = Board::new();
let result = board.has_checker_at(Player::Nobody, Position::Board(5));
assert_eq!(result, Err(Error::PlayerInvalid));
}
#[test]
fn has_checker_at_after_move() -> Result<(), Error> {
let mut board = Board::new();
board.empty_board()?;
board.set_checkers(Player::Player0, Position::Board(10), 1)?;
assert!(board.has_checker_at(Player::Player0, Position::Board(10))?);
board.move_by_dice(Player::Player0, 3, Position::Board(10))?;
assert!(!board.has_checker_at(Player::Player0, Position::Board(10))?);
assert!(board.has_checker_at(Player::Player0, Position::Board(7))?);
Ok(())
}
#[test]
fn has_checker_at_player0_field_invalid() {
let board = Board::new();
let result = board.has_checker_at(Player::Player0, Position::Board(25));
assert_eq!(result, Err(Error::FieldInvalid));
let result = board.has_checker_at(Player::Player1, Position::Board(25));
assert_eq!(result, Err(Error::FieldInvalid));
let result = board.has_checker_at(Player::Player0, Position::Board(0));
assert_eq!(result, Err(Error::FieldInvalid));
let result = board.has_checker_at(Player::Player1, Position::Board(0));
assert_eq!(result, Err(Error::FieldInvalid));
}
#[test]
fn move_checkers_from_bar_to_board() -> Result<(), Error> {
let mut board = Board::new();
board.empty_board()?;
board.set_checkers(Player::Player0, Position::Bar, 1)?;
board.set_dice(Player::Nobody, (2, 4))?;
board.move_checkers(Player::Player0, vec![(Position::Bar, Position::Board(21))])?;
assert_eq!(board.get_bar(Player::Player0)?, 0);
assert_eq!(board.get_board().board[20], 1);
Ok(())
}
#[test]
fn move_checkers_invalid_player() {
let mut board = Board::new();
let result = board.move_checkers(
Player::Nobody,
vec![(Position::Board(23), Position::Board(20))],
);
assert_eq!(result, Err(Error::PlayerInvalid));
}
#[test]
fn move_checkers_from_bar_to_off_returns_error() {
let mut board = Board::new();
board
.set_checkers(Player::Player0, Position::Bar, 1)
.unwrap();
let result = board.move_checkers(Player::Player0, vec![(Position::Bar, Position::Off)]);
assert_eq!(result, Err(Error::MoveInvalidOff));
}
#[test]
fn move_checkers_from_bar_blocked() -> Result<(), Error> {
let mut board = Board::new();
board.empty_board()?;
board.set_checkers(Player::Player0, Position::Bar, 1)?;
board.set_checkers(Player::Player1, Position::Board(4), 2)?; board.set_dice(Player::Nobody, (4, 2))?;
let result =
board.move_checkers(Player::Player0, vec![(Position::Bar, Position::Board(21))]);
assert_eq!(result, Err(Error::FieldBlocked));
Ok(())
}
#[test]
fn move_checkers_from_board_to_off() -> Result<(), Error> {
let mut board = Board::new();
board.empty_board()?;
board.set_checkers(Player::Player0, Position::Board(2), 1)?;
board.set_dice(Player::Nobody, (4, 1))?;
board.move_checkers(Player::Player0, vec![(Position::Board(2), Position::Off)])?;
assert_eq!(board.get_board().board[2], 0);
assert_eq!(board.get_off(Player::Player0)?, 1);
Ok(())
}
#[test]
fn move_checkers_from_board_to_board() -> Result<(), Error> {
let mut board = Board::new();
board.empty_board()?;
board.set_checkers(Player::Player0, Position::Board(11), 1)?;
board.set_dice(Player::Nobody, (1, 3))?;
board.move_checkers(
Player::Player0,
vec![(Position::Board(11), Position::Board(8))],
)?;
assert_eq!(board.get_board().board[10], 0);
assert_eq!(board.get_board().board[7], 1);
Ok(())
}
#[test]
fn move_checkers_from_board_to_board_blocked() -> Result<(), Error> {
let mut board = Board::new();
board.empty_board()?;
board.set_checkers(Player::Player0, Position::Board(11), 1)?;
board.set_checkers(Player::Player1, Position::Board(17), 2)?;
let result = board.move_checkers(
Player::Player0,
vec![(Position::Board(11), Position::Board(8))],
);
assert_eq!(result, Err(Error::FieldBlocked));
Ok(())
}
#[test]
fn move_checkers_multiple_moves() -> Result<(), Error> {
let mut board = Board::new();
board.set_dice(Player::Nobody, (2, 2))?;
let result = board.move_checkers(
Player::Player0,
vec![
(Position::Board(24), Position::Board(22)),
(Position::Board(22), Position::Board(20)),
],
);
assert_eq!(result, Ok(()));
assert_eq!(board.get_board().board[23], 1);
assert_eq!(board.get_board().board[21], 0);
assert_eq!(board.get_board().board[19], 1);
Ok(())
}
#[test]
fn move_checkers_multiple_moves1() -> Result<(), Error> {
let mut board = Board::new();
board.set_dice(Player::Nobody, (1, 2))?;
assert_eq!(board.dice_available(), &vec![1, 2]);
let result = board.move_checkers(
Player::Player0,
vec![
(Position::Board(24), Position::Board(22)),
(Position::Board(24), Position::Board(23)),
],
);
assert_eq!(result, Ok(()));
assert_eq!(board.dice_available(), &vec![]);
assert_eq!(
board.has_checker_at(Player::Player0, Position::Board(23)),
Ok(true)
);
assert_eq!(
board.has_checker_at(Player::Player0, Position::Board(22)),
Ok(true)
);
Ok(())
}
#[test]
fn set_field_greater_than_24() {
let mut board = Board::new();
let result = board.set_checkers(Player::Player0, Position::Board(25), 1);
assert_eq!(result, Err(Error::FieldInvalid));
let result = board.set_checkers(Player::Player1, Position::Board(0), 1);
assert_eq!(result, Err(Error::FieldInvalid));
}
#[test]
fn set_off_negative_amount_returns_error() {
let mut board = Board::new();
let result = board.set_checkers(Player::Player0, Position::Off, -1);
assert_eq!(result, Err(Error::MoveInvalid));
let result = board.set_checkers(Player::Player1, Position::Off, -1);
assert_eq!(result, Err(Error::MoveInvalid));
}
#[test]
fn move_checkers_from_bar_to_bar_returns_error() -> Result<(), Error> {
let mut board = Board::new();
board.empty_board()?;
board.set_checkers(Player::Player0, Position::Bar, 1)?;
board.set_dice(Player::Nobody, (3, 4))?;
let result = board.move_checkers(Player::Player0, vec![(Position::Bar, Position::Bar)]);
assert_eq!(result, Err(Error::MoveInvalid));
Ok(())
}
#[test]
fn has_checker_at_player0_off_position() -> Result<(), Error> {
let mut board = Board::new();
board.empty_board()?;
assert!(!board.has_checker_at(Player::Player0, Position::Off)?);
board.set_checkers(Player::Player0, Position::Off, 2)?;
board.set_checkers(Player::Player1, Position::Off, 2)?;
assert!(board.has_checker_at(Player::Player0, Position::Off)?);
assert!(board.has_checker_at(Player::Player1, Position::Off)?);
Ok(())
}
#[test]
fn move_checkers_no_checker_at_source() -> Result<(), Error> {
let mut board = Board::new();
board.empty_board()?;
board.set_dice(Player::Nobody, (3, 4))?;
let result = board.move_checkers(
Player::Player0,
vec![(Position::Board(10), Position::Board(7))],
);
assert_eq!(result, Err(Error::MoveInvalid));
Ok(())
}
#[test]
fn move_checkers_from_bar_invalid_target_field() -> Result<(), Error> {
let mut board = Board::new();
board.empty_board()?;
board.set_checkers(Player::Player0, Position::Bar, 1)?;
board.set_dice(Player::Nobody, (6, 5))?;
let result =
board.move_checkers(Player::Player0, vec![(Position::Bar, Position::Board(18))]);
assert_eq!(result, Err(Error::FieldInvalid));
let result =
board.move_checkers(Player::Player0, vec![(Position::Bar, Position::Board(24))]);
assert_eq!(result, Err(Error::DiceInvalid));
Ok(())
}
#[test]
fn move_checkers_from_bar_dice_not_available() -> Result<(), Error> {
let mut board = Board::new();
board.empty_board()?;
board.set_checkers(Player::Player0, Position::Bar, 1)?;
board.set_dice(Player::Nobody, (2, 3))?;
let result =
board.move_checkers(Player::Player0, vec![(Position::Bar, Position::Board(20))]);
assert_eq!(result, Err(Error::DiceInvalid));
Ok(())
}
#[test]
fn move_checkers_from_board_to_off_not_ready() -> Result<(), Error> {
let mut board = Board::new();
board.empty_board()?;
board.set_checkers(Player::Player0, Position::Board(10), 1)?;
board.set_checkers(Player::Player0, Position::Board(3), 1)?;
board.set_dice(Player::Nobody, (4, 2))?;
let result =
board.move_checkers(Player::Player0, vec![(Position::Board(3), Position::Off)]);
assert_eq!(result, Err(Error::MoveInvalidOff));
Ok(())
}
#[test]
fn test_move_checkers_exact_bear_off() -> Result<(), Error> {
let mut board = Board::new();
board.empty_board()?;
board.set_checkers(Player::Player0, Position::Board(2), 1)?;
board.set_dice(Player::Nobody, (2, 3))?;
board.move_checkers(Player::Player0, vec![(Position::Board(2), Position::Off)])?;
assert_eq!(board.get_board().board[2], 0);
assert_eq!(board.get_off(Player::Player0)?, 1);
Ok(())
}
#[test]
fn test_move_checkers_overshoot_with_higher_checkers() -> Result<(), Error> {
let mut board = Board::new();
board.empty_board()?;
board.set_checkers(Player::Player0, Position::Board(2), 1)?;
board.set_checkers(Player::Player0, Position::Board(4), 1)?;
board.set_dice(Player::Nobody, (5, 3))?;
let result =
board.move_checkers(Player::Player0, vec![(Position::Board(2), Position::Off)]);
assert_eq!(result, Err(Error::MoveInvalidOff));
Ok(())
}
#[test]
fn move_checkers_backwards_movement_returns_error() -> Result<(), Error> {
let mut board = Board::new();
board.empty_board()?;
board.set_checkers(Player::Player0, Position::Board(10), 1)?;
board.set_dice(Player::Nobody, (3, 4))?;
let result = board.move_checkers(
Player::Player0,
vec![(Position::Board(10), Position::Board(15))],
);
assert_eq!(result, Err(Error::MoveInvalid));
Ok(())
}
#[test]
fn test_move_checkers_board_to_board_dice_not_available() -> Result<(), Error> {
let mut board = Board::new();
board.empty_board()?;
board.set_checkers(Player::Player0, Position::Board(10), 1)?;
board.set_dice(Player::Nobody, (2, 3))?;
let result = board.move_checkers(
Player::Player0,
vec![(Position::Board(10), Position::Board(6))],
);
assert_eq!(result, Err(Error::DiceInvalid));
Ok(())
}
#[test]
fn move_checkers_from_board_to_bar_returns_error() -> Result<(), Error> {
let mut board = Board::new();
board.empty_board()?;
board.set_checkers(Player::Player0, Position::Board(10), 1)?;
board.set_dice(Player::Nobody, (3, 4))?;
let result =
board.move_checkers(Player::Player0, vec![(Position::Board(10), Position::Bar)]);
assert_eq!(result, Err(Error::MoveInvalid));
Ok(())
}
#[test]
fn move_checkers_from_off_returns_error() -> Result<(), Error> {
let mut board = Board::new();
board.empty_board()?;
board.set_checkers(Player::Player0, Position::Off, 1)?;
board.set_dice(Player::Nobody, (3, 4))?;
let result =
board.move_checkers(Player::Player0, vec![(Position::Off, Position::Board(10))]);
assert_eq!(result, Err(Error::MoveInvalid));
Ok(())
}
#[test]
fn move_by_dice_from_off_returns_error() {
let mut board = Board::new();
let result = board.move_by_dice(Player::Player0, 3, Position::Off);
assert_eq!(result, Err(Error::MoveInvalid));
}
#[test]
fn move_by_dice_invalid_field_zero() {
let mut board = Board::new();
let result = board.move_by_dice(Player::Player0, 3, Position::Board(0));
assert_eq!(result, Err(Error::FieldInvalid));
}
#[test]
fn move_by_dice_invalid_field_above_24() {
let mut board = Board::new();
let result = board.move_by_dice(Player::Player0, 3, Position::Board(25));
assert_eq!(result, Err(Error::FieldInvalid));
}
#[test]
fn set_field_invalid_in_set_method() {
let mut board = Board::new();
let result = board.set_checkers(Player::Player0, Position::Board(0), 1);
assert_eq!(result, Err(Error::FieldInvalid));
let result = board.set_checkers(Player::Player0, Position::Board(25), 1);
assert_eq!(result, Err(Error::FieldInvalid));
let result = board.set_checkers(Player::Player1, Position::Board(0), 1);
assert_eq!(result, Err(Error::FieldInvalid));
let result = board.set_checkers(Player::Player1, Position::Board(25), 1);
assert_eq!(result, Err(Error::FieldInvalid));
}
#[test]
fn move_checkers_from_board_invalid_source_field() -> Result<(), Error> {
let mut board = Board::new();
board.empty_board()?;
board.set_checkers(Player::Player0, Position::Board(10), 1)?;
board.set_dice(Player::Nobody, (3, 4))?;
let result = board.move_checkers(
Player::Player0,
vec![(Position::Board(0), Position::Board(3))],
);
assert_eq!(result, Err(Error::FieldInvalid));
let result = board.move_checkers(
Player::Player0,
vec![(Position::Board(25), Position::Board(22))],
);
assert_eq!(result, Err(Error::FieldInvalid));
Ok(())
}
#[test]
fn move_checkers_from_board_to_board_invalid_target_field() -> Result<(), Error> {
let mut board = Board::new();
board.empty_board()?;
board.set_checkers(Player::Player0, Position::Board(10), 1)?;
board.set_dice(Player::Nobody, (3, 4))?;
let result = board.move_checkers(
Player::Player0,
vec![(Position::Board(10), Position::Board(0))],
);
assert_eq!(result, Err(Error::FieldInvalid));
let result = board.move_checkers(
Player::Player0,
vec![(Position::Board(10), Position::Board(25))],
);
assert_eq!(result, Err(Error::FieldInvalid));
Ok(())
}
#[test]
fn move_by_dice_exact_bear_off_not_ready_returns_error() -> Result<(), Error> {
let mut board = Board::new();
board.empty_board()?;
board.set_checkers(Player::Player0, Position::Board(3), 1)?;
board.set_checkers(Player::Player0, Position::Board(10), 1)?;
let result = board.move_by_dice(Player::Player0, 3, Position::Board(3));
assert_eq!(result, Err(Error::MoveInvalidOff));
Ok(())
}
#[test]
fn move_by_dice_overshoot_bear_off_with_higher_checkers() -> Result<(), Error> {
let mut board = Board::new();
board.empty_board()?;
board.set_checkers(Player::Player0, Position::Board(2), 1)?;
board.set_checkers(Player::Player0, Position::Board(4), 1)?;
let result = board.move_by_dice(Player::Player0, 6, Position::Board(2));
assert_eq!(result, Err(Error::MoveInvalidOff));
Ok(())
}
#[test]
fn position_debug_fmt() {
assert_eq!(format!("{:?}", Position::Board(1)), "1");
assert_eq!(format!("{:?}", Position::Board(24)), "24");
assert_eq!(format!("{:?}", Position::Bar), "Bar");
assert_eq!(format!("{:?}", Position::Off), "Off");
}
#[test]
fn test_position_display_fmt() {
assert_eq!(format!("{}", Position::Board(1)), "1");
assert_eq!(format!("{}", Position::Board(24)), "24");
assert_eq!(format!("{}", Position::Bar), "Bar");
assert_eq!(format!("{}", Position::Off), "Off");
}
#[test]
fn test_get_baroff_nobody() {
let board = Board::new();
let b = board.get_bar(Player::Nobody);
assert_eq!(b, Err(Error::PlayerInvalid));
let o = board.get_off(Player::Nobody);
assert_eq!(o, Err(Error::PlayerInvalid))
}
#[test]
fn all_checkers_off_player0_all_off() -> Result<(), Error> {
let mut board = Board::new();
board.empty_board()?;
board.set_checkers(Player::Player0, Position::Off, 15)?;
assert!(board.all_checkers_off(Player::Player0)?);
board.set_checkers(Player::Player1, Position::Off, 15)?;
assert!(board.all_checkers_off(Player::Player1)?);
Ok(())
}
#[test]
fn test_backgammon_loss_position_player0_has_checkers_in_opponent_home() -> Result<(), Error> {
let mut board = Board::new();
board.empty_board()?;
board.set_checkers(Player::Player0, Position::Board(19), 1)?;
assert!(board.backgammon_loss_position(Player::Player0)?);
board.set_checkers(Player::Player1, Position::Board(19), 1)?;
assert!(board.backgammon_loss_position(Player::Player1)?);
Ok(())
}
#[test]
fn test_backgammon_loss_position_player0_on_bar() -> Result<(), Error> {
let mut board = Board::new();
board.empty_board()?;
board.set_checkers(Player::Player0, Position::Bar, 1)?;
assert!(board.backgammon_loss_position(Player::Player0)?);
board.set_checkers(Player::Player1, Position::Bar, 1)?;
board.set_checkers(Player::Player1, Position::Board(1), 1)?;
assert!(board.backgammon_loss_position(Player::Player1)?);
Ok(())
}
#[test]
fn test_backgammon_loss_position_player0_no_loss_position() -> Result<(), Error> {
let mut board = Board::new();
board.empty_board()?;
board.set_checkers(Player::Player0, Position::Board(6), 5)?;
board.set_checkers(Player::Player0, Position::Board(18), 3)?;
assert!(!board.backgammon_loss_position(Player::Player0)?);
board.set_checkers(Player::Player1, Position::Board(6), 5)?;
board.set_checkers(Player::Player1, Position::Board(18), 3)?;
assert!(!board.backgammon_loss_position(Player::Player1)?);
Ok(())
}
#[test]
fn test_backgammon_loss_position_player_nobody() {
let board = Board::new();
let result = board.backgammon_loss_position(Player::Nobody);
assert_eq!(result, Err(Error::PlayerInvalid));
}
}