From 3a1c20ebba57632392443a050fc10d44e3048843 Mon Sep 17 00:00:00 2001 From: tslil clingman <> Date: Sun, 26 Jan 2020 20:57:55 -0800 Subject: Playing against the computer actually works! --- src/consulter.rs | 24 ++++++++++++++++++++++++ src/game.rs | 24 ++++++++++++++---------- src/gui.rs | 47 +++++++++++++++++++++++++++++------------------ src/main.rs | 43 ++++++++++++++++++++++++++++++++++++++----- 4 files changed, 105 insertions(+), 33 deletions(-) create mode 100644 src/consulter.rs diff --git a/src/consulter.rs b/src/consulter.rs new file mode 100644 index 0000000..1f27124 --- /dev/null +++ b/src/consulter.rs @@ -0,0 +1,24 @@ +use std::fs::File; +use std::io::{Error, ErrorKind, Result, Write}; +use std::process::Command; + +use crate::game::*; +use crate::parser::*; + +const FILE_NAME: &str = "/tmp/takwrap_ptn_consult.ptn"; + +pub fn consult_next_action(game: &Game, proc: &str) -> Result { + let file = File::create(FILE_NAME)?; + + write!(&file, "{}", game)?; + + let output = Command::new(proc).args(&[FILE_NAME]).output()?; + + match String::from_utf8(output.stdout) { + Err(e) => Err(Error::new(ErrorKind::InvalidData, e)), + Ok(string) => match parse_action(game, &string) { + Err(string) => Err(Error::new(ErrorKind::InvalidData, string)), + Ok(action) => Ok(action), + }, + } +} diff --git a/src/game.rs b/src/game.rs index 04bd76a..be9d23d 100644 --- a/src/game.rs +++ b/src/game.rs @@ -650,6 +650,7 @@ impl GameState { return None; } + // TODO: this does not handle the case dragon edge case fn check_win(&self) -> Option { if let Some(w) = self.check_road_win() { return Some(w); @@ -731,17 +732,20 @@ impl Game { pub fn query_action_lines(&self) -> String { let mut result = String::new(); let mut newline = true; - result += "0. "; - for i in 0..self.actions.len() { - if i > 1 && newline { - // TODO: Is placing the opponent's first stone the zeroeth action? - result += &format!("{}. ", i); - } - result += &format!("{} ", self.actions[i]); - if i > 0 && !newline { - result.push('\n'); + let num_actions = self.actions.len(); + if num_actions > 0 { + result += "0. "; + for i in 0..num_actions { + if i > 1 && newline { + // TODO: Is placing the opponent's first stone the zeroeth action? + result += &format!("{}. ", i); + } + result += &format!("{} ", self.actions[i]); + if i > 0 && !newline { + result.push('\n'); + } + newline = !newline; } - newline = !newline; } result } diff --git a/src/gui.rs b/src/gui.rs index 428c8c1..bd7ca7c 100644 --- a/src/gui.rs +++ b/src/gui.rs @@ -117,10 +117,9 @@ pub struct BoardGUI { black_colour: u8, } -#[derive(PartialEq)] pub enum BGAction { Quit, - None, + Selected(Action), } impl BoardGUI { @@ -194,11 +193,21 @@ impl BoardGUI { fn draw_stack(&self, pos: &Position, stack: &Stack) { if let Some(win) = self.cell_windows.get(self.pos_to_idx(pos)) { win.clear(); - 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); + let height = stack.len() as usize; + if height > 0 { + let carry_capacity = self.size as usize; + let tall = height > carry_capacity; + if tall { + win.attrset(Attribute::Normal); + win.addch('('); + } + for i in 0..height { + let piece = &stack[i]; + self.draw_stone(win, i + 1 == height, &piece.player, &piece.stone); + if tall && i + 2 == carry_capacity { + win.attrset(Attribute::Normal); + win.addch(')'); + } } } win.refresh(); @@ -208,14 +217,6 @@ impl BoardGUI { pub fn update(&self, game: &Game, squares: Vec) { // Is this really the `best' way? assert!(game.get_size() == self.size); - // for x in 0..self.size { - // for y in 0..self.size { - // let pos = Position { x: x, y: y }; - // if let Some(stack) = game.query_square(&pos) { - // self.draw_stack(&pos, stack); - // } - // } - // } for p in squares { if let Some(stack) = game.query_square(&p) { self.draw_stack(&p, stack); @@ -369,9 +370,19 @@ impl ActionEntry { 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); + // Annoyingly there are two backspace possibilities + let ascii = c as usize; + if !result.is_empty() && (ascii == 127) || (ascii == 8) { + 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); + } else { + if result.len() < self.max_len { + result.push(c); + self.window.addch(c); + } } } KeyBackspace => { diff --git a/src/main.rs b/src/main.rs index 263997f..be24a77 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,10 +1,27 @@ +mod consulter; mod game; mod gui; mod parser; +use crate::consulter::*; use crate::game::*; use crate::gui::*; use crate::parser::*; +use std::io::Error; + +fn human_action( + action_entry: &ActionEntry, + message_log: &MessageLog, + game: &Game, +) -> Result { + loop { + let inp = action_entry.read_action(); + match parse_action(&game, &inp) { + Err(err) => message_log.log_error(format!("Input \"{}\": {}", inp, err)), + Ok(action) => return Ok(action), + } + } +} fn main() { let screen = initscr(); @@ -74,10 +91,18 @@ fn main() { message_log.log_error(warning); game_log.update(&game); + const CONSULT_PROC: &str = "/home/tslil/bin/wrap_taktician"; loop { - let inp = action_entry.read_action(); - match parse_action(&game, &inp) { - Err(err) => message_log.log_error(format!("Input \"{}\": {}", inp, err)), + let inp = match game.query_current_player() { + Player::Black => consult_next_action(&game, CONSULT_PROC), + Player::White => human_action(&action_entry, &message_log, &game), + }; + + match inp { + Err(err) => { + message_log.log_error(format!("{}", err)); + break; + } Ok(act) => { let stone_owner = game.query_stone_owner(); let player = game.query_current_player(); @@ -93,7 +118,14 @@ fn main() { } )); match game.perform_action(act) { - Err(e) => message_log.log_error(e), + Err(e) => { + message_log.log_error(e); + if game.query_current_player() == Player::Black { + // external and internal gamestates diverged + break; + } + } + Ok((pos_vec, win)) => { board_gui.update(&game, pos_vec); game_log.update(&game); @@ -108,6 +140,7 @@ fn main() { action_entry.clear_entry_area(); } - board_gui.read_action(); + screen.getch(); + // board_gui.read_action(); endwin(); } -- cgit v1.3.1