summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortslil clingman <>2020-01-19 23:26:29 -0800
committertslil clingman <>2020-01-19 23:26:29 -0800
commit8110985e6636e511f0a2e85a6f30aa8ff109320d (patch)
tree7e6c1b38d04db474aac5cdac2593878f167cac8a
parent4d18fad08c185e07d030f6574963ec6de8441ee5 (diff)
Parsing `by hand', gui in separate module
-rw-r--r--Cargo.lock88
-rw-r--r--Cargo.toml2
-rw-r--r--src/game.rs7
-rw-r--r--src/gui.rs341
-rw-r--r--src/main.rs350
-rw-r--r--src/parser.rs134
6 files changed, 490 insertions, 432 deletions
diff --git a/Cargo.lock b/Cargo.lock
index fc247a3..3211f3d 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1,14 +1,6 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
-name = "arrayvec"
-version = "0.4.12"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "nodrop 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
name = "cc"
version = "1.0.49"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -19,18 +11,6 @@ version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
-name = "lexical-core"
-version = "0.4.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "arrayvec 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
- "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "static_assertions 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
name = "libc"
version = "0.2.66"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -44,11 +24,6 @@ dependencies = [
]
[[package]]
-name = "memchr"
-version = "2.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
name = "ncurses"
version = "5.99.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -59,21 +34,6 @@ dependencies = [
]
[[package]]
-name = "nodrop"
-version = "0.1.14"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "nom"
-version = "5.0.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "lexical-core 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
name = "pancurses"
version = "0.16.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -100,50 +60,13 @@ version = "0.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
-name = "rustc_version"
-version = "0.2.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "ryu"
-version = "1.0.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "semver"
-version = "0.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "semver-parser"
-version = "0.7.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "static_assertions"
-version = "0.3.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
name = "takwrap"
version = "0.1.0"
dependencies = [
- "nom 5.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"pancurses 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
-name = "version_check"
-version = "0.1.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
name = "winapi"
version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -171,25 +94,14 @@ dependencies = [
]
[metadata]
-"checksum arrayvec 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "cd9fd44efafa8690358b7408d253adf110036b88f55672a933f01d616ad9b1b9"
"checksum cc 1.0.49 (registry+https://github.com/rust-lang/crates.io-index)" = "e450b8da92aa6f274e7c6437692f9f2ce6d701fb73bacfcf87897b3f89a4c20e"
"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
-"checksum lexical-core 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2304bccb228c4b020f3a4835d247df0a02a7c4686098d4167762cfbbe4c5cb14"
"checksum libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)" = "d515b1f41455adea1313a4a2ac8a8a477634fbae63cc6100e3aebb207ce61558"
"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
-"checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e"
"checksum ncurses 5.99.0 (registry+https://github.com/rust-lang/crates.io-index)" = "15699bee2f37e9f8828c7b35b2bc70d13846db453f2d507713b758fabe536b82"
-"checksum nodrop 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb"
-"checksum nom 5.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c618b63422da4401283884e6668d39f819a106ef51f5f59b81add00075da35ca"
"checksum pancurses 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d3058bc37c433096b2ac7afef1c5cdfae49ede0a4ffec3dfc1df1df0959d0ff0"
"checksum pdcurses-sys 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "084dd22796ff60f1225d4eb6329f33afaf4c85419d51d440ab6b8c6f4529166b"
"checksum pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)" = "05da548ad6865900e60eaba7f589cc0783590a92e940c26953ff81ddbab2d677"
-"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
-"checksum ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfa8506c1de11c9c4e4c38863ccbe02a305c8188e85a05a784c9e11e1c3910c8"
-"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
-"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
-"checksum static_assertions 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7f3eb36b47e512f8f1c9e3d10c2c1965bc992bd9cdb024fa581e2194501c83d3"
-"checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd"
"checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6"
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
diff --git a/Cargo.toml b/Cargo.toml
index 09711ac..7801309 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -8,4 +8,4 @@ edition = "2018"
[dependencies]
pancurses = "0.16.1"
-nom = "5.0.1"
+# nom = "5.0.1"
diff --git a/src/game.rs b/src/game.rs
index 931a15f..057a307 100644
--- a/src/game.rs
+++ b/src/game.rs
@@ -82,10 +82,11 @@ pub enum Action {
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::Place(_, pos, stone) => write!(f, "{}{}", stone, pos),
Action::Move(_, pos, direction, drops) => write!(
f,
- "{}{}{}",
+ "{}{}{}{}",
+ drops.iter().map(|&d| d as u32).sum::<u32>(),
pos,
direction,
drops.into_iter().map(|q| q.to_string()).collect::<String>()
@@ -244,6 +245,8 @@ enum TurnOrder {
Normal,
}
+// TODO: Redo this logging story with Result<...,String> instead
+
pub struct Game<L>
where
L: Fn(String),
diff --git a/src/gui.rs b/src/gui.rs
new file mode 100644
index 0000000..abeb902
--- /dev/null
+++ b/src/gui.rs
@@ -0,0 +1,341 @@
+extern crate pancurses;
+
+pub use pancurses::Input::*;
+pub use pancurses::*;
+
+use crate::game::*;
+
+pub struct GameLog {
+ action_window: Window,
+ pieces_window: Window,
+}
+
+impl GameLog {
+ pub fn new(ypos: i32, xpos: i32, height: i32, width: i32) -> GameLog {
+ GameLog {
+ pieces_window: newwin(2, width, ypos, xpos),
+ action_window: newwin(height, width, ypos + 3, xpos),
+ }
+ }
+
+ pub fn update<L: Fn(String)>(&self, game: &Game<L>) {
+ self.pieces_window.clear();
+ self.pieces_window.addstr(format!(
+ "W: {:2} B: {:2}\nWC: {} BC: {}",
+ game.query_pieces(Player::White, Stone::Flat),
+ game.query_pieces(Player::Black, Stone::Flat),
+ game.query_pieces(Player::White, Stone::Capstone),
+ game.query_pieces(Player::Black, Stone::Capstone),
+ ));
+ self.pieces_window.refresh();
+
+ self.action_window.clear();
+ self.action_window.addstr(game.query_action_lines());
+ self.action_window.refresh();
+ }
+}
+
+pub struct BoardGUI {
+ board_window: Window,
+ cell_windows: Vec<Window>,
+ size: u8,
+ cell_height: u8,
+ cell_width: u8,
+ hoff: i32,
+ cur_cell: Position,
+ has_colours: bool,
+ white_colour: u8,
+ black_colour: u8,
+}
+
+#[derive(PartialEq)]
+pub enum BGAction {
+ Quit,
+ None,
+}
+
+impl BoardGUI {
+ fn draw_grid(&self) {
+ let s: i32 = self.size as i32;
+ let h: i32 = self.cell_height as i32;
+ let w: i32 = self.cell_width as i32;
+ for y in 0..h * s + 1 {
+ for x in 0..w * s + 1 {
+ if y % h == 0 {
+ if x % w == 0 {
+ self.board_window.mvaddch(y, x + self.hoff, '+');
+ } else {
+ self.board_window.mvaddch(y, x + self.hoff, '-');
+ }
+ } else if x % w == 0 {
+ self.board_window.mvaddch(y, x + self.hoff, '|');
+ }
+ }
+ }
+ for y in 0..s {
+ self.board_window
+ .mvaddstr(y * h + h / 2, 0, format!("{}.", s - y));
+ }
+ for x in 0..s {
+ self.board_window.mvaddstr(
+ s * h + 1,
+ w * x + w / 2 + self.hoff,
+ format!("{:x}.", x + 10),
+ );
+ }
+ self.board_window.refresh();
+ }
+
+ fn pos_to_idx(&self, pos: &Position) -> usize {
+ let y = pos.y as usize;
+ let x = pos.x as usize;
+ x + y * (self.size as usize)
+ }
+
+ fn mv_to_cell(&self, pos: &Position, line: i32) {
+ if let Some(win) = self.cell_windows.get(self.pos_to_idx(pos)) {
+ win.mv(line, 0);
+ win.refresh();
+ }
+ }
+
+ fn draw_stone(&self, win: &Window, top: bool, player: &Player, stone: &Stone) {
+ if self.has_colours {
+ match player {
+ Player::Black => win.attrset(ColorPair(self.black_colour)),
+ Player::White => win.attrset(ColorPair(self.white_colour)),
+ };
+ if top {
+ win.addch(match stone {
+ Stone::Flat => '#',
+ Stone::Standing => '/',
+ Stone::Capstone => '*',
+ });
+ } else {
+ win.addstr(format!("{}", player));
+ }
+ } else {
+ win.addstr(format!("{}", player));
+ if top {
+ win.addstr(format!("{}", stone));
+ }
+ }
+ }
+
+ fn draw_stack(&self, pos: &Position, stack: &Stack) {
+ if let Some(win) = self.cell_windows.get(self.pos_to_idx(pos)) {
+ win.mv(0, 0);
+ let l = stack.len() as i32;
+ if l > 0 {
+ for i in 0..l {
+ let piece = &stack[i as usize];
+ self.draw_stone(win, i == l - 1, &piece.player, &piece.stone);
+ }
+ }
+ win.refresh();
+ }
+ }
+
+ pub fn update<L: Fn(String)>(&self, game: &Game<L>) {
+ // Is this really the `best' way?
+ assert!(game.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) = game.query_square(&pos) {
+ self.draw_stack(&pos, stack);
+ }
+ }
+ }
+ }
+
+ pub fn read_action(&mut self) -> BGAction {
+ loop {
+ if let Some(key) = self.board_window.getch() {
+ match key {
+ KeyDown => {
+ if 0 < self.cur_cell.y {
+ self.cur_cell.y -= 1;
+ self.mv_to_cell(&self.cur_cell, 0);
+ }
+ }
+ KeyUp => {
+ if self.cur_cell.y + 1 < self.size {
+ self.cur_cell.y += 1;
+ self.mv_to_cell(&self.cur_cell, 0);
+ }
+ }
+ KeyLeft => {
+ if 0 < self.cur_cell.x {
+ self.cur_cell.x -= 1;
+ self.mv_to_cell(&self.cur_cell, 0);
+ }
+ }
+ KeyRight => {
+ if self.cur_cell.x + 1 < self.size {
+ self.cur_cell.x += 1;
+ self.mv_to_cell(&self.cur_cell, 0);
+ }
+ }
+ Character('q') => return BGAction::Quit,
+
+ x => {
+ self.board_window.addstr(format!("{:?}", x));
+ self.board_window.refresh();
+ }
+ }
+ }
+ }
+ }
+
+ pub fn new(
+ ypos: i32,
+ xpos: i32,
+ size: u8,
+ cell_height: u8,
+ cell_width: u8,
+ hoff: u8,
+ has_colours: bool,
+ white_colour: u8,
+ black_colour: u8,
+ ) -> BoardGUI {
+ let mut cell_windows: Vec<Window> = Vec::new();
+
+ let hoff = hoff as i32;
+ let s: i32 = size as i32;
+ let h: i32 = cell_height as i32;
+ let w: i32 = cell_width as i32;
+ for i in 0..s * s {
+ let y: i32 = i / s;
+ let x: i32 = i % s;
+ cell_windows.push(newwin(h - 1, w - 1, (s - y - 1) * h + 1, hoff + x * w + 1));
+ }
+
+ let bg = BoardGUI {
+ board_window: newwin(h * s + 3, w * s + 3 + hoff, ypos, xpos),
+ cell_windows: cell_windows,
+ size: size,
+ cell_height: cell_height,
+ cell_width: cell_width,
+ hoff: hoff,
+ cur_cell: Position { x: 0, y: 0 },
+ has_colours: has_colours,
+ black_colour: black_colour,
+ white_colour: white_colour,
+ };
+
+ bg.board_window.keypad(true);
+ bg.board_window.nodelay(false);
+
+ bg.draw_grid();
+
+ // for i in 0..s * s {
+ // let y: i32 = i / s;
+ // let x: i32 = i % s;
+ // let y = (s - y - 1) * h + 1;
+ // let x = hoff + x * w + 1;
+ // bg.cell_windows[i as usize].addstr(format!("{}:({},{})", i, y, x));
+ // bg.cell_windows[i as usize].refresh();
+ // }
+
+ bg.mv_to_cell(&bg.cur_cell, 0);
+ bg.board_window.refresh();
+ bg
+ }
+}
+
+pub struct ActionEntry {
+ window: Window,
+ max_len: usize,
+ xstart: i32,
+}
+
+impl ActionEntry {
+ pub fn new(ypos: i32, xpos: i32, max_len: usize) -> ActionEntry {
+ let txt = "Action entry: ";
+ let xstart = txt.len() as i32;
+ let width = max_len as i32 + xstart + 1;
+
+ let ae = ActionEntry {
+ window: newwin(1, width, ypos, xpos),
+ max_len: max_len,
+ xstart: xstart,
+ };
+
+ ae.window.nodelay(false);
+ ae.window.keypad(true);
+
+ ae.window.addstr(txt);
+
+ for _i in 0..max_len {
+ ae.window.addch('_');
+ }
+
+ ae.window.mv(0, xstart);
+ ae.window.refresh();
+ ae
+ }
+
+ pub fn read_action(&self) -> String {
+ self.window.mv(0, self.xstart);
+ self.window.refresh();
+
+ let mut result = String::new();
+ loop {
+ if let Some(inp) = self.window.getch() {
+ match inp {
+ Character('\n') => return result,
+ KeyEnter => return result, // TODO: is this ever used?
+ Character(c) => {
+ if result.len() < self.max_len {
+ result.push(c);
+ self.window.addch(c);
+ }
+ }
+ KeyBackspace => {
+ if !result.is_empty() {
+ result.pop();
+ let (y, x) = (self.window.get_cur_y(), self.window.get_cur_x());
+ self.window.mv(y, x - 1);
+ self.window.addch('_');
+ self.window.mv(y, x - 1);
+ }
+ }
+ _ => (),
+ };
+ }
+ self.window.refresh();
+ }
+ }
+}
+
+pub struct MessageLog {
+ window: Window,
+}
+
+impl MessageLog {
+ pub fn new(
+ ypos: i32,
+ xpos: i32,
+ height: i32,
+ width: i32,
+ has_colours: bool,
+ red_colour: u8,
+ ) -> MessageLog {
+ let ml = MessageLog {
+ window: newwin(height, width, ypos, xpos),
+ };
+ if has_colours {
+ ml.window.attrset(ColorPair(red_colour));
+ }
+ ml
+ }
+
+ pub fn log_error(&self, str: String) {
+ self.window.clear();
+ self.window.addstr(str);
+ self.window.refresh();
+ }
+}
diff --git a/src/main.rs b/src/main.rs
index 043702a..c7281cf 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,345 +1,10 @@
-extern crate pancurses;
-
-use pancurses::Input::*;
-use pancurses::*;
-
mod game;
-use crate::game::*;
-
-pub struct GameLog {
- action_window: Window,
- pieces_window: Window,
-}
-
-impl GameLog {
- pub fn new(ypos: i32, xpos: i32, height: i32, width: i32) -> GameLog {
- GameLog {
- pieces_window: newwin(2, width, ypos, xpos),
- action_window: newwin(height, width, ypos + 3, xpos),
- }
- }
-
- pub fn update<L: Fn(String)>(&self, game: &Game<L>) {
- self.pieces_window.clear();
- self.pieces_window.addstr(format!(
- "W: {:2} B: {:2}\nWC: {} BC: {}",
- game.query_pieces(Player::White, Stone::Flat),
- game.query_pieces(Player::Black, Stone::Flat),
- game.query_pieces(Player::White, Stone::Capstone),
- game.query_pieces(Player::Black, Stone::Capstone),
- ));
- self.pieces_window.refresh();
-
- self.action_window.clear();
- self.action_window.addstr(game.query_action_lines());
- self.action_window.refresh();
- }
-}
-
-pub struct BoardGUI {
- board_window: Window,
- cell_windows: Vec<Window>,
- size: u8,
- cell_height: u8,
- cell_width: u8,
- hoff: i32,
- cur_cell: Position,
- has_colours: bool,
- white_colour: u8,
- black_colour: u8,
-}
-
-#[derive(PartialEq)]
-pub enum BGAction {
- Quit,
- None,
-}
-
-impl BoardGUI {
- fn draw_grid(&self) {
- let s: i32 = self.size as i32;
- let h: i32 = self.cell_height as i32;
- let w: i32 = self.cell_width as i32;
- for y in 0..h * s + 1 {
- for x in 0..w * s + 1 {
- if y % h == 0 {
- if x % w == 0 {
- self.board_window.mvaddch(y, x + self.hoff, '+');
- } else {
- self.board_window.mvaddch(y, x + self.hoff, '-');
- }
- } else if x % w == 0 {
- self.board_window.mvaddch(y, x + self.hoff, '|');
- }
- }
- }
- for y in 0..s {
- self.board_window
- .mvaddstr(y * h + h / 2, 0, format!("{}.", s - y));
- }
- for x in 0..s {
- self.board_window.mvaddstr(
- s * h + 1,
- w * x + w / 2 + self.hoff,
- format!("{:x}.", x + 10),
- );
- }
- self.board_window.refresh();
- }
-
- fn pos_to_idx(&self, pos: &Position) -> usize {
- let y = pos.y as usize;
- let x = pos.x as usize;
- x + y * (self.size as usize)
- }
-
- fn mv_to_cell(&self, pos: &Position, line: i32) {
- if let Some(win) = self.cell_windows.get(self.pos_to_idx(pos)) {
- win.mv(line, 0);
- win.refresh();
- }
- }
-
- fn draw_stone(&self, win: &Window, top: bool, player: &Player, stone: &Stone) {
- if self.has_colours {
- match player {
- Player::Black => win.attrset(ColorPair(self.black_colour)),
- Player::White => win.attrset(ColorPair(self.white_colour)),
- };
- if top {
- win.addch(match stone {
- Stone::Flat => '#',
- Stone::Standing => '/',
- Stone::Capstone => '*',
- });
- } else {
- win.addstr(format!("{}", player));
- }
- } else {
- win.addstr(format!("{}", player));
- if top {
- win.addstr(format!("{}", stone));
- }
- }
- }
-
- fn draw_stack(&self, pos: &Position, stack: &Stack) {
- if let Some(win) = self.cell_windows.get(self.pos_to_idx(pos)) {
- win.mv(0, 0);
- let l = stack.len() as i32;
- if l > 0 {
- for i in 0..l {
- let piece = &stack[i as usize];
- self.draw_stone(win, i == l - 1, &piece.player, &piece.stone);
- }
- }
- win.refresh();
- }
- }
-
- pub fn update<L: Fn(String)>(&self, game: &Game<L>) {
- // Is this really the `best' way?
- assert!(game.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) = game.query_square(&pos) {
- self.draw_stack(&pos, stack);
- }
- }
- }
- }
-
- fn read_action(&mut self) -> BGAction {
- loop {
- if let Some(key) = self.board_window.getch() {
- match key {
- KeyDown => {
- if 0 < self.cur_cell.y {
- self.cur_cell.y -= 1;
- self.mv_to_cell(&self.cur_cell, 0);
- }
- }
- KeyUp => {
- if self.cur_cell.y + 1 < self.size {
- self.cur_cell.y += 1;
- self.mv_to_cell(&self.cur_cell, 0);
- }
- }
- KeyLeft => {
- if 0 < self.cur_cell.x {
- self.cur_cell.x -= 1;
- self.mv_to_cell(&self.cur_cell, 0);
- }
- }
- KeyRight => {
- if self.cur_cell.x + 1 < self.size {
- self.cur_cell.x += 1;
- self.mv_to_cell(&self.cur_cell, 0);
- }
- }
- Character('q') => return BGAction::Quit,
-
- x => {
- self.board_window.addstr(format!("{:?}", x));
- self.board_window.refresh();
- }
- }
- }
- }
- }
+mod gui;
+mod parser;
- pub fn new(
- ypos: i32,
- xpos: i32,
- size: u8,
- cell_height: u8,
- cell_width: u8,
- hoff: u8,
- has_colours: bool,
- white_colour: u8,
- black_colour: u8,
- ) -> BoardGUI {
- let mut cell_windows: Vec<Window> = Vec::new();
-
- let hoff = hoff as i32;
- let s: i32 = size as i32;
- let h: i32 = cell_height as i32;
- let w: i32 = cell_width as i32;
- for i in 0..s * s {
- let y: i32 = i / s;
- let x: i32 = i % s;
- cell_windows.push(newwin(h - 1, w - 1, (s - y - 1) * h + 1, hoff + x * w + 1));
- }
-
- let bg = BoardGUI {
- board_window: newwin(h * s + 3, w * s + 3 + hoff, ypos, xpos),
- cell_windows: cell_windows,
- size: size,
- cell_height: cell_height,
- cell_width: cell_width,
- hoff: hoff,
- cur_cell: Position { x: 0, y: 0 },
- has_colours: has_colours,
- black_colour: black_colour,
- white_colour: white_colour,
- };
-
- bg.board_window.keypad(true);
- bg.board_window.nodelay(false);
-
- bg.draw_grid();
-
- // for i in 0..s * s {
- // let y: i32 = i / s;
- // let x: i32 = i % s;
- // let y = (s - y - 1) * h + 1;
- // let x = hoff + x * w + 1;
- // bg.cell_windows[i as usize].addstr(format!("{}:({},{})", i, y, x));
- // bg.cell_windows[i as usize].refresh();
- // }
-
- bg.mv_to_cell(&bg.cur_cell, 0);
- bg.board_window.refresh();
- bg
- }
-}
-
-pub struct ActionEntry {
- window: Window,
- max_len: usize,
- xstart: i32,
-}
-
-impl ActionEntry {
- pub fn new(ypos: i32, xpos: i32, max_len: usize) -> ActionEntry {
- let txt = "Action entry: ";
- let xstart = txt.len() as i32;
- let width = max_len as i32 + xstart + 1;
-
- let ae = ActionEntry {
- window: newwin(1, width, ypos, xpos),
- max_len: max_len,
- xstart: xstart,
- };
-
- ae.window.nodelay(false);
- ae.window.keypad(true);
-
- ae.window.addstr(txt);
-
- for _i in 0..max_len {
- ae.window.addch('_');
- }
-
- ae.window.mv(0, xstart);
- ae.window.refresh();
- ae
- }
-
- fn read_action(&self) -> String {
- self.window.mv(0, self.xstart);
- self.window.refresh();
-
- let mut result = String::new();
- loop {
- if let Some(inp) = self.window.getch() {
- match inp {
- Character('\n') => return result,
- KeyEnter => return result, // TODO: is this ever used?
- Character(c) => {
- if result.len() < self.max_len {
- result.push(c);
- self.window.addch(c);
- }
- }
- KeyBackspace => {
- if !result.is_empty() {
- result.pop();
- let (y, x) = (self.window.get_cur_y(), self.window.get_cur_x());
- self.window.mv(y, x - 1);
- self.window.addch('_');
- self.window.mv(y, x - 1);
- }
- }
- _ => (),
- };
- }
- self.window.refresh();
- }
- }
-}
-
-pub struct MessageLog {
- window: Window,
-}
-
-impl MessageLog {
- pub fn new(
- ypos: i32,
- xpos: i32,
- height: i32,
- width: i32,
- has_colours: bool,
- red_colour: u8,
- ) -> MessageLog {
- let ml = MessageLog {
- window: newwin(height, width, ypos, xpos),
- };
- if has_colours {
- ml.window.attrset(ColorPair(red_colour));
- }
- ml
- }
-
- pub fn log_error(&self, str: String) {
- self.window.clear();
- self.window.addstr(str);
- self.window.refresh();
- }
-}
+use crate::game::*;
+use crate::gui::*;
+use crate::parser::*;
fn main() {
let screen = initscr();
@@ -376,7 +41,10 @@ fn main() {
board_gui.update(&game);
game_log.update(&game);
- log(action_entry.read_action());
+ match parse_action(game.query_current_player(), &action_entry.read_action()) {
+ Ok(act) => log(format!("{}", act)),
+ Err(err) => log(err),
+ }
// game_state.perform_action(&action);
// game_state.is_legal_action(&Action::Move(Player::White, pos, Direction::Up, vec![0, 1]));
diff --git a/src/parser.rs b/src/parser.rs
new file mode 100644
index 0000000..49ded9b
--- /dev/null
+++ b/src/parser.rs
@@ -0,0 +1,134 @@
+// #[macro_use]
+// extern crate nom;
+
+// use nom::*;
+
+use crate::game::*;
+
+fn parse_move(player: Player, mv: &str) -> Result<Action, String> {
+ let mut chars = mv.chars();
+
+ let c = chars.next();
+ if c.is_none() {
+ return Err(String::from("Empty string cannot be parsed."));
+ }
+
+ let dc = c.unwrap();
+ if (dc < '1') || ('9' < dc) {
+ return Err(String::from(
+ "Moves must begin with a digit in 1-8 indicating the number of drops.",
+ ));
+ }
+ let sum_drops = dc.to_digit(10).unwrap();
+
+ let c = chars.next();
+ if c.is_none() {
+ return Err(String::from("Moves must specify a stack position."));
+ }
+
+ let x = c.unwrap();
+ if (x < 'a') || (x > 'h') {
+ return Err(String::from(
+ "Moves must specify a position on the game board.",
+ ));
+ }
+ let x: u8 = x as u8 - 'a' as u8;
+
+ let c = chars.next();
+ if c.is_none() {
+ return Err(String::from("Moves must specify a stack position."));
+ }
+
+ let y = c.unwrap();
+ if (y < '1') || (y > '8') {
+ return Err(String::from(
+ "Moves must specify a position on the game board.",
+ ));
+ }
+ let y: u8 = (y.to_digit(10).unwrap() - 1) as u8;
+
+ let c = chars.next();
+ if c.is_none() {
+ return Err(String::from("Moves must specify a move direction."));
+ }
+
+ let c = c.unwrap();
+ let mut dir = Direction::Up;
+ match c {
+ '+' => dir = Direction::Up,
+ '-' => dir = Direction::Down,
+ '<' => dir = Direction::Left,
+ '>' => dir = Direction::Right,
+ _ => return Err(String::from("The valid directions are +,-,<, and >.")),
+ }
+
+ let mut drops: Vec<u8> = Vec::new();
+ for d in chars {
+ if let Some(u) = d.to_digit(10) {
+ if u > 9 {
+ return Err(String::from(
+ "No more than 8 pieces may be dropped on a given square.",
+ ));
+ } else {
+ drops.push(u as u8)
+ }
+ } else {
+ return Err(String::from(
+ "A move must specify a number of pieces dropped for each square.",
+ ));
+ }
+ }
+
+ let sum = drops.iter().map(|&d| d as u32).sum::<u32>();
+ if sum != sum_drops {
+ return Err(format!(
+ "The move called for {} stones, but {} were dropped.",
+ sum_drops, sum
+ ));
+ }
+
+ Ok(Action::Move(player, Position { x: x, y: y }, dir, drops))
+}
+
+fn parse_place(player: Player, pl: &str) -> Result<Action, String> {
+ Ok(Action::Place(player, Position { x: 0, y: 0 }, Stone::Flat))
+}
+
+pub fn parse_action(player: Player, act: &str) -> Result<Action, String> {
+ if act
+ .chars()
+ .any(|c| c == '+' || c == '-' || c == '>' || c == '<')
+ {
+ parse_move(player, act)
+ } else {
+ parse_place(player, act)
+ }
+}
+
+// fn parse_move(mv: &str) -> Result<Action, Err<&str>> {
+// one_of!("abcdefgh");
+// Ok(Action::Place(
+// Player::Black,
+// Position { x: 0, y: 0 },
+// Stone::Flat,
+// ))
+// }
+
+// fn parse_place(pl: &str) -> Result<Action, Err<&str>> {
+// Ok(Action::Place(
+// Player::Black,
+// Position { x: 0, y: 0 },
+// Stone::Flat,
+// ))
+// }
+
+// pub fn parse_action(act: &str) -> Result<Action, Err<&str>> {
+// if act
+// .chars()
+// .any(|c| c == '+' || c == '-' || c == '>' || c == '<')
+// {
+// parse_move(act)
+// } else {
+// parse_place(act)
+// }
+// }