aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortslil clingman <>2020-01-18 17:03:09 -0500
committertslil clingman <>2020-01-18 17:03:09 -0500
commitcdbcc1d2faf198629f5d598bb9a7ba6ab15a922a (patch)
tree9ba2960ba2444d879df42d574ba4b0390c0e8116
parentf6a94720061877903487ed98bfee9f19df264a9d (diff)
working on game tracking
-rw-r--r--src/board.rs362
-rw-r--r--src/game.rs461
-rw-r--r--src/main.rs24
3 files changed, 474 insertions, 373 deletions
diff --git a/src/board.rs b/src/board.rs
deleted file mode 100644
index 578842c..0000000
--- a/src/board.rs
+++ /dev/null
@@ -1,362 +0,0 @@
-use std::fmt;
-
-#[derive(Clone, Copy)]
-pub struct Position {
- pub x: u8,
- pub y: u8,
-}
-impl fmt::Display for Position {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "{:x}{}", 10 + self.x, self.y + 1)
- }
-}
-
-#[derive(PartialEq)]
-pub enum Player {
- Black,
- White,
-}
-
-impl fmt::Display for Player {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(
- f,
- "{}",
- match self {
- Player::Black => "B",
- Player::White => "W",
- }
- )
- }
-}
-
-#[derive(PartialEq)]
-pub enum Stone {
- Flat,
- Standing,
- Capstone,
-}
-
-impl fmt::Display for Stone {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(
- f,
- "{}",
- match self {
- Stone::Flat => "",
- Stone::Standing => "S",
- Stone::Capstone => "C",
- }
- )
- }
-}
-
-// #[derive(Clone, Copy)]
-pub enum Direction {
- Up,
- Down,
- Left,
- Right,
-}
-
-impl fmt::Display for Direction {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(
- f,
- "{}",
- match self {
- Direction::Up => "+",
- Direction::Down => "-",
- Direction::Left => "<",
- Direction::Right => ">",
- }
- )
- }
-}
-
-pub enum Action {
- Place(Player, Position, Stone),
- Move(Player, Position, Direction, Vec<u8>),
-}
-
-impl fmt::Display for Action {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- match self {
- Action::Place(player, pos, stone) => write!(f, "{}{}{}", pos, player, stone),
- Action::Move(_, pos, direction, drops) => write!(
- f,
- "{}{}{}",
- pos,
- direction,
- drops.into_iter().map(|q| q.to_string()).collect::<String>()
- ),
- }
- }
-}
-
-pub type Stack = Vec<(Player, Stone)>;
-
-pub struct Board<L>
-where
- L: Fn(String),
-{
- size: u8,
- black_flats: u8,
- white_flats: u8,
- black_capstones: u8,
- white_capstones: u8,
- board: Vec<Stack>,
- log: L,
-}
-
-// How to solve code duplication between is_legal_action and
-// perform_action?
-
-// TODO: Generate all legal actions for a given player
-
-impl<L: Fn(String)> Board<L> {
- pub fn get_size(&self) -> u8 {
- self.size
- }
-
- // Defaults to 5x5 if requested things are out of range
- pub fn new(size: u8, log: L) -> (Board<L>, bool) {
- let (flats, caps, correct) = match size {
- 3 => (10, 0, true),
- 4 => (15, 0, true),
- 6 => (30, 1, true),
- 7 => (40, 2, true),
- 8 => (50, 2, true),
- _ => (21, 1, false),
- };
- (
- Board {
- size: size,
- black_flats: flats,
- white_flats: flats,
- black_capstones: caps,
- white_capstones: caps,
- board: {
- let mut v: Vec<Stack> = Vec::new();
- for _i in 0..size * size {
- v.push(Vec::new());
- }
- v
- },
- log: log,
- },
- correct,
- )
- }
-
- pub fn remaining_pieces(&self, player: &Player, stone: &Stone) -> u8 {
- match player {
- Player::Black => {
- if *stone == Stone::Capstone {
- self.black_capstones
- } else {
- self.black_flats
- }
- }
- Player::White => {
- if *stone == Stone::Capstone {
- self.white_capstones
- } else {
- self.white_flats
- }
- }
- }
- }
-
- fn within_bounds(&self, pos: &Position) -> bool {
- if (pos.x < self.size) && (pos.y < self.size) {
- true
- } else {
- false
- }
- }
-
- pub fn query_square(&self, pos: &Position) -> Option<&Stack> {
- if self.within_bounds(pos) {
- self.board.get(self.pos_to_idx(pos))
- } else {
- None
- }
- }
-
- fn pos_to_idx(&self, pos: &Position) -> usize {
- let y: usize = pos.y as usize;
- let x: usize = pos.x as usize;
- x + y * (self.size as usize)
- }
-
- fn is_legal_place(&self, player: &Player, pos: &Position, stone: &Stone) -> bool {
- /* In order to legally place a piece:
- 1. The desired square must be empty
- 2. The player must have sufficient pieces
- */
- if self.within_bounds(pos) {
- if let Some(stack) = &self.board.get(self.pos_to_idx(pos)) {
- if stack.len() > 0 {
- (self.log)(format!("{} is already occupied.", pos));
- false
- } else if self.remaining_pieces(&player, &stone) == 0 {
- (self.log)(format!(
- "{} has no more remaining {} pieces.",
- player, stone
- ));
- false
- } else {
- true
- }
- } else {
- (self.log)(format!(
- "Internal error: lookup for {} failed in is_legal_place.",
- pos
- ));
- false
- }
- } else {
- (self.log)(format!("Position {} is not within bounds.", pos));
- false
- }
- }
-
- fn is_legal_move(
- &self,
- player: &Player,
- pos: &Position,
- direction: &Direction,
- drops: &Vec<u8>,
- ) -> bool {
- if self.within_bounds(pos) {
- /* Rules for moving a stack:
- 0. There are stones
- 1. Top stone belongs to player
- 2. Zero or One stones dropped on starting square
- 3. Total number of stones moved does not exceed the carry capacity
- 4. Direction does not contain a capstone
- 5. Wall may only appear on last spot if it's capstone alone that covers
- 6. All stones are used up before then end of the board is met
- */
- if let Some(stack) = &self.board.get(self.pos_to_idx(pos)) {
- if stack.len() == 0 {
- (self.log)(format!("{} has no stones to move.", pos));
- return false;
- } else if drops.len() == 0 {
- (self.log)(format!("A drop sequence for must be specified for a move."));
- return false;
- } else if stack[0].0 != *player {
- (self.log)(format!(
- "{} may not move the stack at {} as it belongs to {}.",
- player, pos, stack[0].0
- ));
- return false;
- } else if drops[0] > 1 {
- (self.log)(format!(
- "A move may only drop 0 or 1 stones at it's origin square."
- ));
- return false;
- // Do the sum in u32 just in case ?
- } else if drops.iter().map(|&d| d as u32).sum::<u32>() > self.size as u32 {
- (self.log)(format!(
- "A move may not exceed the carry limit of {} stones.",
- self.size
- ));
- return false;
- }
- let mut steps: usize = drops.len() - 1;
- let cap: bool = stack[0].1 == Stone::Capstone;
- let mut pos_new = Position { x: pos.x, y: pos.y };
-
- while steps > 0 {
- steps -= 1;
- if {
- match direction {
- Direction::Up => pos_new.y + 1 >= self.size,
- Direction::Down => pos_new.y == 0,
- Direction::Left => pos_new.x + 1 >= self.size,
- Direction::Right => pos_new.x == 0,
- }
- } {
- (self.log)(format!("A move may not extend past the board."));
- return false;
- } else {
- match direction {
- Direction::Up => pos_new.y += 1,
- Direction::Down => pos_new.y -= 1,
- Direction::Left => pos_new.x += 1,
- Direction::Right => pos_new.x -= 1,
- }
- if let Some(stack) = &self.board.get(self.pos_to_idx(&pos_new)) {
- if stack.len() > 0 {
- match stack[0].1 {
- Stone::Capstone => {
- (self.log)(format!("A move may not cover a capstone."));
- return false;
- }
- Stone::Standing => {
- if (steps > 1) || (!cap) {
- (self.log)(format!(
- "A move may not cover a standing stone."
- ));
- return false;
- }
- }
- Stone::Flat => (),
- }
- }
- } else {
- (self.log)(format!(
- "Internal error: lookup for {} failed in is_legal_move (1).",
- pos_new
- ));
- return false;
- }
- }
- }
- return true;
- } else {
- (self.log)(format!(
- "Internal error: lookup for {} failed in is_legal_move (2).",
- pos
- ));
- return false;
- }
- } else {
- (self.log)(format!("Position {} is not within bounds.", pos));
- false
- }
- }
-
- pub fn is_legal_action(&self, act: &Action) -> bool {
- match act {
- Action::Place(player, pos, stone) => self.is_legal_place(player, pos, stone),
- Action::Move(player, pos, direction, drops) => {
- self.is_legal_move(player, pos, direction, drops)
- }
- }
- }
-
- // Unconditional and so could lead to invalid state, but private
- fn place_stone(&mut self, player: Player, pos: Position, stone: Stone) {
- let idx = self.pos_to_idx(&pos);
- self.board[idx].push((player, stone));
- }
-
- fn move_stack(&mut self, player: Player, pos: Position, direction: Direction, drops: Vec<u8>) {}
-
- pub fn perform_action(&mut self, act: Action) -> bool {
- if self.is_legal_action(&act) {
- match act {
- Action::Place(player, pos, stone) => self.place_stone(player, pos, stone),
- Action::Move(player, pos, direction, drops) => {
- self.move_stack(player, pos, direction, drops)
- }
- }
- true
- } else {
- false
- }
- }
-}
diff --git a/src/game.rs b/src/game.rs
new file mode 100644
index 0000000..6307843
--- /dev/null
+++ b/src/game.rs
@@ -0,0 +1,461 @@
+use std::fmt;
+
+#[derive(Clone, Copy)]
+pub struct Position {
+ pub x: u8,
+ pub y: u8,
+}
+impl fmt::Display for Position {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "{:x}{}", 10 + self.x, self.y + 1)
+ }
+}
+
+#[derive(PartialEq, Clone, Copy)]
+pub enum Player {
+ Black,
+ White,
+}
+
+impl fmt::Display for Player {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(
+ f,
+ "{}",
+ match self {
+ Player::Black => "B",
+ Player::White => "W",
+ }
+ )
+ }
+}
+
+#[derive(PartialEq, Clone, Copy)]
+pub enum Stone {
+ Flat,
+ Standing,
+ Capstone,
+}
+
+impl fmt::Display for Stone {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(
+ f,
+ "{}",
+ match self {
+ Stone::Flat => "",
+ Stone::Standing => "S",
+ Stone::Capstone => "C",
+ }
+ )
+ }
+}
+
+#[derive(Clone, Copy)]
+pub enum Direction {
+ Up,
+ Down,
+ Left,
+ Right,
+}
+
+impl fmt::Display for Direction {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(
+ f,
+ "{}",
+ match self {
+ Direction::Up => "+",
+ Direction::Down => "-",
+ Direction::Left => "<",
+ Direction::Right => ">",
+ }
+ )
+ }
+}
+
+pub enum Action {
+ Place(Player, Position, Stone),
+ Move(Player, Position, Direction, Vec<u8>),
+}
+
+impl fmt::Display for Action {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match self {
+ Action::Place(player, pos, stone) => write!(f, "{}{}{}", pos, player, stone),
+ Action::Move(_, pos, direction, drops) => write!(
+ f,
+ "{}{}{}",
+ pos,
+ direction,
+ drops.into_iter().map(|q| q.to_string()).collect::<String>()
+ ),
+ }
+ }
+}
+
+#[derive(Clone, Copy)]
+pub struct Piece {
+ pub player: Player,
+ pub stone: Stone,
+}
+pub type Stack = Vec<Piece>;
+
+pub struct GameState {
+ size: u8,
+ black_flats: u8,
+ white_flats: u8,
+ black_capstones: u8,
+ white_capstones: u8,
+ board: Vec<Stack>,
+}
+
+// TODO: Generate all legal actions for a given player
+
+impl GameState {
+ pub fn get_size(&self) -> u8 {
+ self.size
+ }
+
+ pub fn copy(&self) -> GameState {
+ let mut copy = GameState {
+ size: self.size,
+ black_flats: self.black_flats,
+ white_flats: self.white_flats,
+ black_capstones: self.black_capstones,
+ white_capstones: self.white_capstones,
+ board: Vec::new(),
+ };
+ for i in 0..self.board.len() {
+ for j in 0..self.board[i].len() {
+ copy.board[i].push(self.board[i][j]);
+ }
+ }
+ copy
+ }
+
+ // Defaults to 5x5 if requested things are out of range
+ pub fn new(size: u8) -> GameState {
+ let (flats, caps) = match size {
+ 3 => (10, 0),
+ 4 => (15, 0),
+ 6 => (30, 1),
+ 7 => (40, 2),
+ 8 => (50, 2),
+ _ => (21, 1),
+ };
+ GameState {
+ size: size,
+ black_flats: flats,
+ white_flats: flats,
+ black_capstones: caps,
+ white_capstones: caps,
+ board: {
+ let mut v: Vec<Stack> = Vec::new();
+ for _i in 0..size * size {
+ v.push(Vec::new());
+ }
+ v
+ },
+ }
+ }
+
+ fn remaining_pieces(&self, player: &Player, stone: &Stone) -> u8 {
+ match player {
+ Player::Black => {
+ if *stone == Stone::Capstone {
+ self.black_capstones
+ } else {
+ self.black_flats
+ }
+ }
+ Player::White => {
+ if *stone == Stone::Capstone {
+ self.white_capstones
+ } else {
+ self.white_flats
+ }
+ }
+ }
+ }
+
+ fn within_bounds(&self, pos: &Position) -> bool {
+ if (pos.x < self.size) && (pos.y < self.size) {
+ true
+ } else {
+ false
+ }
+ }
+
+ pub fn query_square(&self, pos: &Position) -> Option<&Stack> {
+ if self.within_bounds(pos) {
+ self.board.get(self.pos_to_idx(pos))
+ } else {
+ None
+ }
+ }
+
+ fn pos_to_idx(&self, pos: &Position) -> usize {
+ let y: usize = pos.y as usize;
+ let x: usize = pos.x as usize;
+ x + y * (self.size as usize)
+ }
+
+ // Unconditional and so could lead to invalid state, but private
+ fn place_stone(&self, player: Player, pos: &Position, stone: Stone) -> GameState {
+ let mut copy = self.copy();
+ let idx = self.pos_to_idx(&pos);
+ copy.board[idx].push(Piece {
+ player: player,
+ stone: stone,
+ });
+ copy
+ }
+
+ fn move_stack(&self, pos: &Position, direction: Direction, drops: &Vec<u8>) -> GameState {
+ let mut copy = self.copy();
+ let mut pos_new = Position { x: pos.x, y: pos.y };
+ let stack: &Stack = &self.board[self.pos_to_idx(pos)];
+
+ let mut k = 0;
+ for &d in drops {
+ let idx = copy.pos_to_idx(&pos_new);
+ for i in 0..d {
+ copy.board[idx].push(stack[(k + i) as usize]);
+ }
+ k += d;
+ match direction {
+ Direction::Up => pos_new.y + 1 >= self.size,
+ Direction::Down => pos_new.y == 0,
+ Direction::Left => pos_new.x + 1 >= self.size,
+ Direction::Right => pos_new.x == 0,
+ };
+ }
+ copy
+ }
+}
+
+pub struct Game<L>
+where
+ L: Fn(String),
+{
+ size: u8,
+ white_player_name: String,
+ black_player_name: String,
+ actions: Vec<Action>,
+ states: Vec<GameState>,
+ log: L,
+}
+
+impl<L: Fn(String)> Game<L> {
+ fn new(size: u8, white_player_name: &str, black_player_name: &str, log: L) -> Game<L> {
+ let size = if (size <= 3) || (size >= 8) {
+ (log)(format!(
+ "Warning: the requested game size of {}x{} is not supported, defaulting to 5x5.",
+ size, size
+ ));
+ 5
+ } else {
+ size
+ };
+ Game {
+ size: size,
+ white_player_name: white_player_name.to_string(),
+ black_player_name: black_player_name.to_string(),
+ turn: 0,
+ states: vec![GameState::new(size)],
+ actions: Vec::new(),
+ log: log,
+ }
+ }
+
+ pub fn get_size(&self) -> u8 {
+ self.size
+ }
+
+ fn is_legal_place(&self, player: &Player, pos: &Position, stone: &Stone) -> bool {
+ if let Some(state) = self.states.last() {
+ /* In order to legally place a piece:
+ 1. The desired square must be empty
+ 2. The player must have sufficient pieces
+ */
+ if state.within_bounds(pos) {
+ if let Some(stack) = &state.board.get(state.pos_to_idx(pos)) {
+ if stack.len() > 0 {
+ (self.log)(format!("{} is already occupied.", pos));
+ false
+ } else if state.remaining_pieces(&player, &stone) == 0 {
+ (self.log)(format!(
+ "{} has no more remaining {} pieces.",
+ player, stone
+ ));
+ false
+ } else {
+ true
+ }
+ } else {
+ (self.log)(format!(
+ "Internal error: lookup for {} failed in is_legal_place.",
+ pos
+ ));
+ false
+ }
+ } else {
+ (self.log)(format!("Position {} is not within bounds.", pos));
+ false
+ }
+ } else {
+ (self.log)(format!(
+ "Internal error: cannot check action with no game state."
+ ));
+ false
+ }
+ }
+
+ fn is_legal_move(
+ &self,
+ player: &Player,
+ pos: &Position,
+ direction: &Direction,
+ drops: &Vec<u8>,
+ ) -> bool {
+ if let Some(state) = self.states.last() {
+ if state.within_bounds(pos) {
+ /* Rules for moving a stack:
+ 0. There are stones
+ 1. Top stone belongs to player
+ 2. Zero or One stones dropped on starting square
+ 3. Total number of stones moved does not exceed the carry capacity
+ 4. Direction does not contain a capstone
+ 5. Wall may only appear on last spot if it's capstone alone that covers
+ 6. All stones are used up before then end of the board is met
+ */
+ if let Some(stack) = &state.board.get(state.pos_to_idx(pos)) {
+ if stack.len() == 0 {
+ (self.log)(format!("{} has no stones to move.", pos));
+ return false;
+ } else if drops.len() == 0 {
+ (self.log)(format!("A drop sequence for must be specified for a move."));
+ return false;
+ } else if stack[0].player != *player {
+ (self.log)(format!(
+ "{} may not move the stack at {} as it belongs to {}.",
+ player, pos, stack[0].player
+ ));
+ return false;
+ } else if drops[0] > 1 {
+ (self.log)(format!(
+ "A move may only drop 0 or 1 stones at it's origin square."
+ ));
+ return false;
+ // Do the sum in u32 just in case ?
+ } else if drops.iter().map(|&d| d as u32).sum::<u32>() > state.size as u32 {
+ (self.log)(format!(
+ "A move may not exceed the carry limit of {} stones.",
+ state.size
+ ));
+ return false;
+ }
+ let mut steps: usize = drops.len() - 1;
+ let cap: bool = stack[0].stone == Stone::Capstone;
+ let mut pos_new = Position { x: pos.x, y: pos.y };
+
+ while steps > 0 {
+ steps -= 1;
+ if {
+ match direction {
+ Direction::Up => pos_new.y + 1 >= state.size,
+ Direction::Down => pos_new.y == 0,
+ Direction::Left => pos_new.x + 1 >= state.size,
+ Direction::Right => pos_new.x == 0,
+ }
+ } {
+ (self.log)(format!("A move may not extend past the board."));
+ return false;
+ } else {
+ match direction {
+ Direction::Up => pos_new.y += 1,
+ Direction::Down => pos_new.y -= 1,
+ Direction::Left => pos_new.x += 1,
+ Direction::Right => pos_new.x -= 1,
+ }
+ if let Some(stack) = &state.board.get(state.pos_to_idx(&pos_new)) {
+ if stack.len() > 0 {
+ match stack[0].stone {
+ Stone::Capstone => {
+ (self.log)(format!("A move may not cover a capstone."));
+ return false;
+ }
+ Stone::Standing => {
+ if (steps > 1) || (!cap) {
+ (self.log)(format!(
+ "A move may not cover a standing stone."
+ ));
+ return false;
+ }
+ }
+ Stone::Flat => (),
+ }
+ }
+ } else {
+ (self.log)(format!(
+ "Internal error: lookup for {} failed in is_legal_move (1).",
+ pos_new
+ ));
+ return false;
+ }
+ }
+ }
+ return true;
+ } else {
+ (self.log)(format!(
+ "Internal error: lookup for {} failed in is_legal_move (2).",
+ pos
+ ));
+ return false;
+ }
+ } else {
+ (self.log)(format!("Position {} is not within bounds.", pos));
+ false
+ }
+ } else {
+ (self.log)(format!(
+ "Internal error: cannot check action with no game state."
+ ));
+ false
+ }
+ }
+
+ pub fn is_legal_action(&self, act: &Action) -> bool {
+ match act {
+ Action::Place(player, pos, stone) => self.is_legal_place(player, pos, stone),
+ Action::Move(player, pos, direction, drops) => {
+ self.is_legal_move(player, pos, direction, drops)
+ }
+ }
+ }
+
+ pub fn perform_action(&mut self, act: &Action) -> bool {
+ if self.is_legal_action(act) {
+ let state = &self.states[self.states.len() - 1];
+ let new_state = match act {
+ Action::Place(player, pos, stone) => state.place_stone(*player, pos, *stone),
+ Action::Move(_, pos, direction, drops) => state.move_stack(pos, *direction, drops),
+ };
+ self.states.push(new_state);
+ true
+ } else {
+ false
+ }
+ }
+}
+
+impl<L: Fn(String)> fmt::Display for Game<L> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(
+ f,
+ "[Date \"\"]\n[Player1 \"{}\"]\n[Player2 \"{}\"]\n[Size \"{}\"]\n{}",
+ self.white_player_name, self.black_player_name, self.size, ptn
+ )
+ }
+}
diff --git a/src/main.rs b/src/main.rs
index 6d110e1..d664025 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -3,9 +3,9 @@ extern crate pancurses;
use pancurses::Input::*;
use pancurses::*;
-mod board;
+mod game;
-use crate::board::*;
+use crate::game::*;
struct BoardGui {
win: Window,
@@ -99,8 +99,8 @@ impl BoardGui {
let l = stack.len() as i32;
if l > 0 {
for i in 0..l {
- let (player, stone) = &stack[i as usize];
- self.draw_stone(win, i == l - 1, player, stone);
+ let piece = &stack[i as usize];
+ self.draw_stone(win, i == l - 1, &piece.player, &piece.stone);
}
}
win.refresh();
@@ -108,15 +108,15 @@ impl BoardGui {
}
// Is this really the best way to do this?
- fn draw_board<L: Fn(String)>(&self, board: &Board<L>) {
+ fn draw_game_state(&self, game_state: &GameState) {
// ????
- assert!(board.get_size() == self.size);
+ assert!(game_state.get_size() == self.size);
let mut pos = Position { x: 0, y: 0 };
for y in 0..self.size {
pos.y = y;
for x in 0..self.size {
pos.x = x;
- if let Some(stack) = board.query_square(&pos) {
+ if let Some(stack) = game_state.query_square(&pos) {
self.draw_stack(&pos, stack);
}
}
@@ -288,11 +288,13 @@ fn main() {
me.init();
ml.init();
- let (mut board, _) = Board::new(5, |s| MessageLog::log_error(&ml, s));
+ let log = |s| MessageLog::log_error(&ml, s);
+ let game_state = GameState::new(5);
let pos = Position { x: 0, y: 0 };
- board.perform_action(Action::Place(Player::White, pos, Stone::Flat));
- board.is_legal_action(&Action::Move(Player::White, pos, Direction::Up, vec![0, 1]));
- bg.draw_board(&board);
+ let action = Action::Place(Player::White, pos, Stone::Flat);
+ // game_state.perform_action(&action);
+ // game_state.is_legal_action(&Action::Move(Player::White, pos, Direction::Up, vec![0, 1]));
+ // bg.draw_game_state(&game_state);
loop {
if let Some(inp) = screen.getch() {