aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortslil clingman <>2020-01-26 20:57:55 -0800
committertslil clingman <>2020-01-26 20:57:55 -0800
commit3a1c20ebba57632392443a050fc10d44e3048843 (patch)
tree3f70bcbc43a40d64f58f8454e92d6da6bac7b3f7
parent1930b067982a5ee324cd2832ace295e67603d2dc (diff)
Playing against the computer actually works!
-rw-r--r--src/consulter.rs24
-rw-r--r--src/game.rs24
-rw-r--r--src/gui.rs47
-rw-r--r--src/main.rs43
4 files changed, 105 insertions, 33 deletions
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<Action> {
+ 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<WinType> {
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<Position>) {
// 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<Action, Error> {
+ 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();
}