summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authortslil clingman <>2020-01-28 12:08:35 -0800
committertslil clingman <>2020-01-28 12:08:35 -0800
commita51bcf3262350c4316a6bf7eaeee3134d5cd7e31 (patch)
tree4dbe5a90d1a7bb32e72eda762cd99c82b3dd1d79 /src
parent04d6efc6eaf31a3ba8c304884725d3c5e9bab9ae (diff)
restructured main loop to handle GUI element focus
Diffstat (limited to 'src')
-rw-r--r--src/consulter.rs12
-rw-r--r--src/gui.rs60
-rw-r--r--src/main.rs153
3 files changed, 137 insertions, 88 deletions
diff --git a/src/consulter.rs b/src/consulter.rs
index a8e666f..7c7bca7 100644
--- a/src/consulter.rs
+++ b/src/consulter.rs
@@ -3,11 +3,12 @@ use std::io::{Error, ErrorKind, Result, Write};
use std::process::Command;
use crate::game::*;
+use crate::gui::*;
use crate::parser::*;
const FILE_NAME: &str = "/tmp/takwrap_ptn_consult.ptn";
-pub fn consult_next_action(game: &Game, proc: &str) -> Result<Action> {
+pub fn consult_next_action(game: &Game, proc: &str) -> Result<GUIResult> {
let file = File::create(FILE_NAME)?;
write!(&file, "{}", game)?;
@@ -16,9 +17,10 @@ pub fn consult_next_action(game: &Game, proc: &str) -> Result<Action> {
match String::from_utf8(output.stdout) {
Err(e) => Err(Error::new(ErrorKind::InvalidData, e)),
- Ok(string) => match parse_action(game.query_stone_owner(), &string.trim()) {
- Err(string) => Err(Error::new(ErrorKind::InvalidData, string)),
- Ok(action) => Ok(action),
- },
+ Ok(raw) => Ok(GUIResult::Raw(raw)),
+ // Ok(string) => match parse_action(game.query_stone_owner(), &string.trim()) {
+ // Err(string) => Err(Error::new(ErrorKind::InvalidData, string)),
+ // Ok(action) => GUIResult::Selected(action),
+ // },
}
}
diff --git a/src/gui.rs b/src/gui.rs
index ed5acb5..4899bb7 100644
--- a/src/gui.rs
+++ b/src/gui.rs
@@ -5,6 +5,22 @@ pub use pancurses::*;
use crate::game::*;
+#[derive(PartialEq)]
+pub enum GUIResult {
+ Undo,
+ SwitchElement,
+ Raw(String),
+}
+
+impl GUIResult {
+ pub fn is_raw(&self) -> bool {
+ match self {
+ GUIResult::Raw(_) => true,
+ _ => false,
+ }
+ }
+}
+
pub struct GameLog {
action_window: Window,
pieces_window: Window,
@@ -23,13 +39,17 @@ impl GameLog {
white_colour: u8,
black_colour: u8,
) -> GameLog {
- GameLog {
+ let gl = GameLog {
pieces_window: newwin(4, width, ypos, xpos),
- action_window: newwin(height, width, ypos + 5, xpos),
+ action_window: newwin(height - 5, width, ypos + 5, xpos),
has_colours: has_colours,
white_colour: white_colour,
black_colour: black_colour,
- }
+ };
+
+ gl.action_window.setscrreg(0, height);
+ gl.action_window.scrollok(true);
+ gl
}
pub fn update(&self, game: &Game) {
@@ -78,7 +98,7 @@ impl GameLog {
self.pieces_window.attrset(Attribute::Normal);
self.pieces_window.mv(3, 0);
- self.pieces_window.addstr("Player: ");
+ self.pieces_window.addstr("Turn: ");
match game.query_current_player() {
Player::Black => {
if self.has_colours {
@@ -115,11 +135,6 @@ pub struct BoardGUI {
black_colour: u8,
}
-pub enum BGAction {
- Quit,
- Selected(Action),
-}
-
impl BoardGUI {
fn draw_grid(&self) {
let s: i32 = self.size as i32;
@@ -224,7 +239,7 @@ impl BoardGUI {
self.board_window.untouch();
}
- pub fn read_action(&mut self) -> BGAction {
+ pub fn read_action(&mut self) -> GUIResult {
loop {
if let Some(key) = self.board_window.getch() {
match key {
@@ -252,7 +267,7 @@ impl BoardGUI {
self.mv_to_cell(&self.cur_cell, 0);
}
}
- Character('q') => return BGAction::Quit,
+ Character('q') => (),
x => {
self.board_window.addstr(format!("{:?}", x));
@@ -285,7 +300,12 @@ impl BoardGUI {
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));
+ cell_windows.push(newwin(
+ h - 1,
+ w - 1,
+ (s - y - 1) * h + 1 + ypos,
+ hoff + x * w + 1 + xpos,
+ ));
}
let bg = BoardGUI {
@@ -357,7 +377,7 @@ impl ActionEntry {
ae
}
- pub fn read_action(&self) -> String {
+ pub fn read_action(&self) -> GUIResult {
self.window.mv(0, self.xstart);
self.window.refresh();
@@ -365,8 +385,9 @@ impl ActionEntry {
loop {
if let Some(inp) = self.window.getch() {
match inp {
- Character('\n') => return result,
- KeyEnter => return result, // TODO: is this ever used?
+ Character('\t') => return GUIResult::SwitchElement,
+ Character('\n') => break,
+
Character(c) => {
// Annoyingly there are two backspace possibilities
let ascii = c as usize;
@@ -392,11 +413,15 @@ impl ActionEntry {
self.window.mv(y, x - 1);
}
}
+
+ KeyEnter => break, // TODO: is this ever used?
_ => (),
};
}
self.window.refresh();
}
+ self.clear_entry_area();
+ return GUIResult::Raw(result);
}
}
@@ -415,12 +440,11 @@ impl MessageLog {
has_colours: bool,
red_colour: u8,
) -> MessageLog {
- let ml = MessageLog {
+ MessageLog {
window: newwin(height, width, ypos, xpos),
has_colours: has_colours,
red_colour: red_colour,
- };
- ml
+ }
}
pub fn log_message(&self, str: String) {
diff --git a/src/main.rs b/src/main.rs
index e46a855..9ddaa50 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -33,9 +33,6 @@ fn init_gui(size: u8) -> GUI {
noecho();
curs_set(2);
- let width = screen.get_max_x();
- let height = screen.get_max_y();
-
let has_colours = has_colors();
let (black_colour, white_colour, red_colour): (u8, u8, u8) = (1, 2, 3);
@@ -47,17 +44,28 @@ fn init_gui(size: u8) -> GUI {
init_pair(red_colour as i16, COLOR_RED, -1);
}
+ screen.addstr(format!(
+ "takwrap {} | <TAB> to switch GUI element",
+ env!("CARGO_PKG_VERSION").to_string()
+ ));
+
+ screen.mvchgat(0, 0, -1, A_REVERSE, -1);
+ let voff = 2;
+
+ let width = screen.get_max_x();
+ let height = screen.get_max_y() - voff;
+
screen.refresh();
let cell_height = 4;
let cell_width = 8;
let hoff = 3;
- let board_bottom = (size * cell_height + 3) as i32;
- let board_right = (size * cell_width + hoff + 3) as i32;
+ let board_bottom = voff + (size * cell_height + 3) as i32;
+ let board_right = (hoff + size * cell_width + 3) as i32;
let board_gui = BoardGUI::new(
- 0,
+ voff,
0,
size,
cell_height,
@@ -69,10 +77,10 @@ fn init_gui(size: u8) -> GUI {
);
let game_log = GameLog::new(
- 0,
+ voff,
board_right,
height,
- 20,
+ width - board_right,
has_colours,
white_colour,
black_colour,
@@ -101,23 +109,6 @@ fn init_gui(size: u8) -> GUI {
}
}
-fn human_action(gui: &GUI, game: &Game) -> Result<Action, Error> {
- loop {
- let inp = gui.action_entry.read_action();
- match parse_action(game.query_stone_owner(), &inp) {
- Err(err) => {
- gui.message_log
- .log_error(format!("Input \"{}\": {}", inp, err));
- gui.action_entry.clear_entry_area();
- }
- Ok(action) => {
- gui.action_entry.clear_entry_area();
- return Ok(action);
- }
- }
- }
-}
-
fn main() {
let mut p1_name = match env::var("USER") {
Err(_) => String::from("Player1"),
@@ -215,68 +206,100 @@ fn main() {
gui.game_log.update(&game);
loop {
- let inp = match game.query_current_player() {
+ let player = game.query_current_player();
+ let engine_turn = call_proc
+ && ((p1_white && player == Player::Black) || ((!p1_white) && player == Player::White));
+
+ let result = match player {
Player::Black => {
if call_proc && p1_white {
+ gui.message_log
+ .log_message(String::from("Opponent is thinking..."));
consult_next_action(&game, &engine)
} else {
- human_action(&gui, &game)
+ Ok(gui.action_entry.read_action())
}
}
Player::White => {
if call_proc && (!p1_white) {
+ gui.message_log
+ .log_message(String::from("Opponent is thinking..."));
consult_next_action(&game, &engine)
} else {
- human_action(&gui, &game)
+ Ok(gui.action_entry.read_action())
}
}
};
- match inp {
- Err(err) => {
- gui.message_log.log_error(format!("{}", err));
+ match result {
+ Err(e) => {
+ gui.message_log.log_error(format!("Engine error: {}", e));
break;
}
- Ok(act) => {
- let stone_owner = game.query_stone_owner();
- let player = game.query_current_player();
- let pn = game.query_current_player_name();
-
- gui.message_log.log_message(format!(
- "{} performs {}{}",
- pn,
- act,
- if stone_owner != player {
- format!(" with a {} stone.", stone_owner)
- } else {
- String::from(".")
+ Ok(gui_result) => match gui_result {
+ GUIResult::SwitchElement => {
+ if engine_turn {
+ gui.message_log.log_error(String::from(
+ "Internal error: engine passed switch-element message somehow.",
+ ));
+ break;
}
- ));
- match game.perform_action(act) {
- Err(e) => {
- gui.message_log.log_error(e);
- let current = game.query_current_player();
- if call_proc
- && ((p1_white && current == Player::Black)
- || ((!p1_white) && current == Player::White))
- {
- gui.message_log.log_error(String::from(
- "Error: external and internal game states disagree.",
- ));
- break;
- }
+ }
+ GUIResult::Undo => {
+ if engine_turn {
+ gui.message_log.log_error(String::from(
+ "Internal error: engine passed undo message somehow.",
+ ));
+ break;
}
+ }
+ GUIResult::Raw(raw) => {
+ let stone_owner = game.query_stone_owner();
+ let act = parse_action(stone_owner, &raw);
+ match act {
+ Err(err) => {
+ gui.message_log.log_error(format!("Input {}: {}", raw, err));
+ if engine_turn {
+ break;
+ }
+ }
+ Ok(act) => {
+ let pn = game.query_current_player_name();
+ gui.message_log.log_message(format!(
+ "{} performs {}{}",
+ pn,
+ act,
+ if stone_owner != player {
+ format!(" with a {} stone.", stone_owner)
+ } else {
+ String::from(".")
+ }
+ ));
+ match game.perform_action(act) {
+ Err(e) => {
+ gui.message_log.log_error(e);
+ let current = game.query_current_player();
+ if engine_turn {
+ gui.message_log.log_error(String::from(
+ "Error: external and internal game states disagree.",
+ ));
+ break;
+ }
+ }
- Ok((pos_vec, win)) => {
- gui.board_gui.update(&game, pos_vec);
- gui.game_log.update(&game);
- if let Some(w) = win {
- gui.message_log.log_message(format!("{}", w));
- break;
+ Ok((pos_vec, win)) => {
+ gui.board_gui.update(&game, pos_vec);
+ gui.game_log.update(&game);
+ if let Some(w) = win {
+ gui.message_log.log_message(format!("{}", w));
+ break;
+ }
+ }
+ }
}
}
}
- }
+ },
}
}