more game logic

master
Ondřej Hruška 4 years ago
parent 109220a3f9
commit 82f2713dca
Signed by: MightyPork
GPG Key ID: 2C5FD5035250423D
  1. 319
      Cargo.lock
  2. 2
      Cargo.toml
  3. 221
      src/game.rs
  4. 158
      src/main.rs

319
Cargo.lock generated

@ -1,16 +1,148 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "arrayref"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544"
[[package]]
name = "arrayvec"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8"
[[package]]
name = "autocfg"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d"
[[package]]
name = "backtrace"
version = "0.3.46"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1e692897359247cc6bb902933361652380af0f1b7651ae5c5013407f30e109e"
dependencies = [
"backtrace-sys",
"cfg-if",
"libc",
"rustc-demangle",
]
[[package]]
name = "backtrace-sys"
version = "0.1.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "18fbebbe1c9d1f383a9cc7e8ccdb471b91c8d024ee9c2ca5b5346121fe8b4399"
dependencies = [
"cc",
"libc",
]
[[package]]
name = "base64"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7"
[[package]]
name = "bitflags"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
[[package]]
name = "blake2b_simd"
version = "0.5.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8fb2d74254a3a0b5cac33ac9f8ed0e44aa50378d9dbb2e5d83bd21ed1dc2c8a"
dependencies = [
"arrayref",
"arrayvec",
"constant_time_eq",
]
[[package]]
name = "cc"
version = "1.0.52"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3d87b23d6a92cd03af510a5ade527033f6aa6fa92161e2d5863a907d4c5e31d"
[[package]]
name = "cfg-if"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
[[package]]
name = "constant_time_eq"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"
[[package]]
name = "crossbeam-utils"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8"
dependencies = [
"autocfg",
"cfg-if",
"lazy_static",
]
[[package]]
name = "dirs"
version = "2.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13aea89a5c93364a98e9b37b2fa237effbb694d5cfe01c5b70941f7eb087d5e3"
dependencies = [
"cfg-if",
"dirs-sys",
]
[[package]]
name = "dirs-sys"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "afa0b23de8fd801745c471deffa6e12d248f962c9fd4b4c33787b055599bde7b"
dependencies = [
"cfg-if",
"libc",
"redox_users",
"winapi",
]
[[package]]
name = "failure"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d32e9bd16cc02eae7db7ef620b392808b89f6a5e16bb3497d159c6b92a0f4f86"
dependencies = [
"backtrace",
"failure_derive",
]
[[package]]
name = "failure_derive"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa4da3c766cd7a0db8242e326e9e4e081edd567072893ed320008189715366a4"
dependencies = [
"proc-macro2",
"quote",
"syn",
"synstructure",
]
[[package]]
name = "gammon"
version = "0.1.0"
dependencies = [
"failure",
"rand",
"rustyline",
]
[[package]]
@ -24,18 +156,70 @@ dependencies = [
"wasi",
]
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "99e85c08494b21a9054e7fe1374a732aeadaff3980b6990b94bfd3a70f690005"
[[package]]
name = "log"
version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
dependencies = [
"cfg-if",
]
[[package]]
name = "memchr"
version = "2.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400"
[[package]]
name = "nix"
version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50e4785f2c3b7589a0d0c1dd60285e1188adac4006e8abd6dd578e1567027363"
dependencies = [
"bitflags",
"cc",
"cfg-if",
"libc",
"void",
]
[[package]]
name = "ppv-lite86"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b"
[[package]]
name = "proc-macro2"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8872cf6f48eee44265156c111456a700ab3483686b3f96df4cf5481c89157319"
dependencies = [
"unicode-xid",
]
[[package]]
name = "quote"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c1f4b0efa5fc5e8ceb705136bfee52cfdb6a4e3509f770b478cd6ed434232a7"
dependencies = [
"proc-macro2",
]
[[package]]
name = "rand"
version = "0.7.3"
@ -77,8 +261,143 @@ dependencies = [
"rand_core",
]
[[package]]
name = "redox_syscall"
version = "0.1.56"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84"
[[package]]
name = "redox_users"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09b23093265f8d200fa7b4c2c76297f47e681c655f6f1285a8780d6a022f7431"
dependencies = [
"getrandom",
"redox_syscall",
"rust-argon2",
]
[[package]]
name = "rust-argon2"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2bc8af4bda8e1ff4932523b94d3dd20ee30a87232323eda55903ffd71d2fb017"
dependencies = [
"base64",
"blake2b_simd",
"constant_time_eq",
"crossbeam-utils",
]
[[package]]
name = "rustc-demangle"
version = "0.1.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783"
[[package]]
name = "rustyline"
version = "6.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1cd20b28d972040c627e209eb29f19c24a71a19d661cc5a220089176e20ee202"
dependencies = [
"cfg-if",
"dirs",
"libc",
"log",
"memchr",
"nix",
"scopeguard",
"unicode-segmentation",
"unicode-width",
"utf8parse",
"winapi",
]
[[package]]
name = "scopeguard"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "syn"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "410a7488c0a728c7ceb4ad59b9567eb4053d02e8cc7f5c0e0eeeb39518369213"
dependencies = [
"proc-macro2",
"quote",
"unicode-xid",
]
[[package]]
name = "synstructure"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67656ea1dc1b41b1451851562ea232ec2e5a80242139f7e679ceccfb5d61f545"
dependencies = [
"proc-macro2",
"quote",
"syn",
"unicode-xid",
]
[[package]]
name = "unicode-segmentation"
version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0"
[[package]]
name = "unicode-width"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479"
[[package]]
name = "unicode-xid"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
[[package]]
name = "utf8parse"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "936e4b492acfd135421d8dca4b1aa80a7bfc26e702ef3af710e0752684df5372"
[[package]]
name = "void"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
[[package]]
name = "wasi"
version = "0.9.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
[[package]]
name = "winapi"
version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"

@ -8,3 +8,5 @@ edition = "2018"
[dependencies]
rand = "0.7.3"
rustyline = "6.1.2"
failure = "0.1.8"

@ -9,7 +9,16 @@ struct Board([Bin; 24]);
impl Board {
fn can_bear_off(&self, color : Color) -> bool {
for i in (HOME_MAX)+1..=BOARD_MAX {
// this range covers the non-home area of the board
let range = if color == Color::White {
// White's home is low indices
6..=23
} else {
// Black's home is high indices
0..=17
};
for i in range {
match (self.0)[i as usize].as_color() {
Some(c) if c == color => {
return false;
@ -67,10 +76,18 @@ impl Board {
#[derive(Debug,Clone,Copy,PartialEq,Eq)]
pub enum Color {
/// Black, home area 18..=23
Black,
/// White, home area 0..=5
White,
}
impl Display for Color {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{:?}", self) // re-use the debug renderer
}
}
impl Color {
fn opposite(self) -> Color {
match self {
@ -111,8 +128,20 @@ impl Bin {
Color::White => Bin::White(1),
}
},
Bin::Black(n) => Bin::Black(*n + 1),
Bin::White(n) => Bin::White(*n + 1),
Bin::Black(n) => {
if color == Color::Black {
Bin::Black(*n + 1)
} else {
Bin::White(1)
}
},
Bin::White(n) => {
if color == Color::White {
Bin::White(*n + 1)
} else {
Bin::Black(1)
}
}
});
}
@ -147,19 +176,17 @@ struct Player {
#[derive(Debug, Clone)]
pub struct State {
move_number : usize,
turn : Color,
board: Board,
roll: Roll,
player : Player,
other : Player,
black : Player,
white : Player,
}
#[derive(Debug,Clone,Copy)]
pub enum Move {
InBoard {
from: u8,
to : u8
},
InBoard(u8, u8),
Enter(u8),
BearOff(u8)
}
@ -256,6 +283,7 @@ impl State {
pub fn start(turn : Option<Color>) -> Self {
// The state is laid out for the white player
let mut state = State {
move_number: 0,
turn: Color::White,
board: Board([
// 1 .. 12 (bottom row, right to left)
@ -286,26 +314,68 @@ impl State {
Bin::White(2), // black player's home side
]),
roll: Roll::new(),
player: Player { born_off: 0, to_place: 0 },
other: Player { born_off: 0, to_place: 0 }
black: Player { born_off: 0, to_place: 0 },
white: Player { born_off: 0, to_place: 0 }
};
if turn.map(|c| c == Color::Black).unwrap_or_else(|| OsRng.gen()) {
// flip the board so black starts
state.switch_sides_mut();
state.turn = Color::Black;
}
state
}
pub fn check_move(&self, mv : Move) -> Result<(), Error> {
pub fn turn(&self) -> (usize, Color) {
(self.move_number, self.turn)
}
fn player(&self) -> &Player {
match self.turn {
Color::Black => &self.black,
Color::White => &self.white,
}
}
fn player_mut(&mut self) -> &mut Player {
match self.turn {
Color::Black => &mut self.black,
Color::White => &mut self.white,
}
}
fn other(&self) -> &Player {
match self.turn {
Color::Black => &self.white,
Color::White => &self.black,
}
}
fn other_mut(&mut self) -> &mut Player {
match self.turn {
Color::Black => &mut self.white,
Color::White => &mut self.black,
}
}
pub fn apply_move(&self, turn : Color, mv : Move) -> Result<Self, Error> {
if turn != self.turn {
return Err(Error::NotYourTurn);
}
print!("{} plays move: ", turn);
let mut next = self.clone();
match mv {
Move::InBoard{from, to} => {
if to > from {
// can only go lower
Move::InBoard(from, to) => {
println!("In-board {} -> {}", from, to);
if (self.turn == Color::White && to >= from) || (self.turn == Color::Black && to <= from) {
return Err(Error::MalformedMove);
}
if self.player.to_place != 0 {
if self.player().to_place != 0 {
return Err(Error::NotAllPlaced);
}
@ -317,15 +387,27 @@ impl State {
return Err(Error::TargetOccupied);
}
let needed = from - to;
let needed = (from as i8 - to as i8).abs() as u8;
if !self.roll.have_equal(needed) {
return Err(Error::NoMatchingRoll);
}
Ok(())
let old_color = next.board.apply_move_mut(from, to);
next.roll.remove_mut(needed);
if let Some(c) = old_color {
if c != self.turn {
println!("{} stone at position {} is hit.", c, to);
// hit opposite color
next.other_mut().to_place += 1;
}
}
},
Move::Enter(pos) => {
if self.player.to_place == 0 {
println!("Enter -> {}", pos);
if self.player().to_place == 0 {
return Err(Error::NothingToPlace);
}
@ -333,7 +415,11 @@ impl State {
return Err(Error::MalformedMove);
}
let needed = 24 - pos;
let needed = if self.turn == Color::White {
24 - pos
} else {
pos + 1
};
if !self.roll.have_equal(needed) {
return Err(Error::NoMatchingRoll);
@ -343,14 +429,27 @@ impl State {
return Err(Error::TargetOccupied);
}
Ok(())
let old_color = next.board.apply_enter_mut(pos, self.turn);
next.roll.remove_mut(needed);
next.player_mut().to_place -= 1;
if let Some(c) = old_color {
if c != self.turn {
println!("{} stone at position {} is hit.", c, pos);
// hit opposite color
next.other_mut().to_place += 1;
}
}
},
Move::BearOff(pos) => {
if pos > HOME_MAX {
println!("Bear off -> {}", pos);
if (self.turn == Color::White && pos > HOME_MAX) || (self.turn == Color::Black && pos < 18) {
return Err(Error::MalformedMove);
}
if self.player.to_place != 0 {
if self.player().to_place != 0 {
return Err(Error::NotAllPlaced);
}
@ -364,66 +463,14 @@ impl State {
// TODO must always bear off the highest possible, if multiple checkers are available
}
Ok(())
},
}
}
pub fn apply_move(&self, turn : Color, mv : Move) -> Result<Self, Error> {
if turn != self.turn {
return Err(Error::NotYourTurn);
}
self.check_move(mv)?;
print!("{:?} plays move: ", turn);
let mut next = self.clone();
match mv {
Move::InBoard { from, to } => {
println!("In-board {} -> {}", from, to);
let old_color = next.board.apply_move_mut(from, to);
let needed = from - to; // move is always downward
next.roll.remove_mut(needed);
if let Some(c) = old_color {
if c != self.turn {
println!("{:?} stone at position {} is hit.", c, to);
// hit opposite color
next.other.to_place += 1;
}
}
},
Move::Enter(pos) => {
println!("Enter -> {}", pos);
let old_color = next.board.apply_enter_mut(pos, self.turn);
let needed = 24 - pos;
next.roll.remove_mut(needed);
next.player.to_place -= 1;
if let Some(c) = old_color {
if c != self.turn {
println!("{:?} stone at position {} is hit.", c, pos);
// hit opposite color
next.other.to_place += 1;
}
}
},
Move::BearOff(pos) => {
println!("Bear off -> {}", pos);
let needed = next.roll.get_equal_or_greater(pos + 1).unwrap();
next.roll.remove_mut(needed);
},
}
if next.roll.remaining_moves.is_empty() {
next.switch_sides_mut();
next.turn = self.turn.opposite();
next.move_number += 1;
next.roll_mut();
// TODO check if any moves are possible with this roll, if not, auto-switch again
@ -441,17 +488,11 @@ impl State {
fn roll_mut(&mut self) {
self.roll = Roll::new();
}
fn switch_sides_mut(&mut self) {
self.board.0.reverse();
mem::swap(&mut self.player, &mut self.other);
self.turn = self.turn.opposite();
}
}
impl Display for State {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "\n# {:?} turn, roll ({},{}), moves to play: [{}]\n",
write!(f, "\n# {} turn, roll ({},{}), moves to play: [{}]\n",
self.turn,
self.roll.dice.0,
self.roll.dice.1,
@ -460,14 +501,16 @@ impl Display for State {
write!(f, "# bearing off? {}, born off: {}, to place: {}\n",
if self.board.can_bear_off(self.turn) { "YES" } else { "no" },
self.player.born_off,
self.player.to_place
self.player().born_off,
self.player().to_place
)?;
f.write_str("White <- ")?;
for n in 0..=23 {
write!(f, "{:02} ", n)?;
write!(f, "{:02} ", n+1)?;
}
f.write_char('\n')?;
f.write_str(" -> Black\n")?;
f.write_str(" ")?;
for n in 0..=23 {
match self.board.0[n] {

@ -1,31 +1,157 @@
use crate::game::{Move, Color, Roll};
use rustyline::error::ReadlineError;
use failure::{Fallible, format_err};
mod game;
fn main() {
let g = game::State::start(Some(Color::Black));
let mut game = game::State::start(None);
let g = g.spoof_roll(Roll::from_dice((3, 5)));
let mut rl = rustyline::Editor::<()>::new();
println!("{}", g);
let mut retry = false;
let mut filled = String::new();
'input: loop {
if !retry {
filled.clear();
}
let g = g.apply_move(Color::Black, Move::InBoard { from: 23, to: 20 }).unwrap();
let g = g.apply_move(Color::Black, Move::InBoard { from: 12, to: 7 }).unwrap();
println!("BOARD:\n{}", game);
// White turn
let g = g.spoof_roll(Roll::from_dice((4, 6)));
println!("{}", g);
let (sn, color) = game.turn();
let cmd = rl.readline_with_initial(&format!("{}> ", color), (&filled, ""));
retry = false;
match cmd {
Ok(line) => {
filled = line;
let g = g.apply_move(Color::White, Move::InBoard { from: 23, to: 17 }).unwrap();
let g = g.apply_move(Color::White, Move::InBoard { from: 7, to: 3 }).unwrap();
let line = filled.trim();
if line.is_empty() {
retry = true;
continue 'input;
}
// Black turn, need to place the hit stone
let g = g.spoof_roll(Roll::from_dice((1, 2)));
println!("{}", g);
match parse_input(line) {
Ok(moves) => {
println!("{:?}", moves);
let mut next = game.clone();
for m in moves {
match next.apply_move(color, m) {
Ok(n) => {
next = n;
println!("{}", next);
}
Err(e) => {
println!("Move failed: {:?}", e);
retry = true;
continue 'input;
}
}
}
if next.turn().0 != sn {
game = next;
} else {
println!("Move NOT complete, reverting.");
retry = true;
}
},
Err(e) => {
println!("Parsing failed: {}", e);
retry = true;
continue 'input;
},
}
},
// Err(ReadlineError::Interrupted) => {
// // just clear the line and retry
// retry = true;
// continue 'input;
// }
Err(_) => {
break 'input;
},
}
}
let g = g.apply_move(Color::Black, Move::Enter(22)).unwrap();
// let g = g.spoof_roll(Roll::from_dice((3, 5)));
//
// println!("{}", g);
//
// let g = g.apply_move(Color::Black, Move::InBoard { from: 0, to: 3 }).unwrap();
// let g = g.apply_move(Color::Black, Move::InBoard { from: 11, to: 16 }).unwrap();
//
// // White turn
// let g = g.spoof_roll(Roll::from_dice((4, 6)));
// println!("{}", g);
//
// let g = g.apply_move(Color::White, Move::InBoard { from: 23, to: 17 }).unwrap();
// let g = g.apply_move(Color::White, Move::InBoard { from: 7, to: 3 }).unwrap();
//
// // Black turn, need to place the hit stone
// let g = g.spoof_roll(Roll::from_dice((1, 2)));
// println!("{}", g);
//
// let g = g.apply_move(Color::Black, Move::Enter(1)).unwrap();
//
// let g = g.apply_move(Color::Black, Move::InBoard { from: 3, to: 4 }).unwrap();
//
// println!("{}", g);
}
fn parse_input(line : &str) -> Fallible<Vec<Move>> {
let line = line.trim();
let mut moves = vec![];
let fragments = line.split(',');
// let mut moves = vec![];
for f in fragments {
if !f.contains('/') {
return Err(format_err!("Bad syntax: \"{}\"", f));
}
let halves : Vec<&str> = f.split('/').collect();
if halves[0].is_empty() && halves[1].is_empty() {
return Err(format_err!("Bad syntax: \"{}\"", f));
}
if halves[0].is_empty() {
let to : u8 = halves[1].parse()?;
if to == 0 || to > 24 {
return Err(format_err!("Out of range: {}", to));
}
moves.push(Move::Enter(to - 1));
continue;
}
if halves[1].is_empty() {
let to : u8 = halves[0].parse()?;
if to == 0 || to > 24 {
return Err(format_err!("Out of range: {}", to));
}
moves.push(Move::BearOff(to - 1));
continue;
}
let from : u8 = halves[0].parse()?;
let to : u8 = halves[1].parse()?;
if from == 0 || from > 24 {
return Err(format_err!("Out of range: {}", to));
}
if to == 0 || to > 24 {
return Err(format_err!("Out of range: {}", to));
}
let g = g.apply_move(Color::Black, Move::InBoard { from: 22, to: 21 }).unwrap();
moves.push(Move::InBoard(from - 1, to - 1));
}
println!("{}", g);
Ok(moves)
}

Loading…
Cancel
Save