diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/game.rs | 34 | ||||
| -rw-r--r-- | src/main.rs | 167 |
2 files changed, 153 insertions, 48 deletions
diff --git a/src/game.rs b/src/game.rs index be9d23d..a6c79a4 100644 --- a/src/game.rs +++ b/src/game.rs @@ -661,8 +661,8 @@ impl GameState { } enum TurnOrder { - BlackPlacesWhite, WhitePlacesBlack, + BlackPlacesWhite, Normal, } @@ -692,8 +692,8 @@ impl Game { black_player_name: black_player_name.to_string(), states: vec![GameState::new(size)], actions: Vec::new(), - current_player: Player::Black, - turn_order: TurnOrder::BlackPlacesWhite, + current_player: Player::White, + turn_order: TurnOrder::WhitePlacesBlack, }, warning, ) @@ -719,8 +719,8 @@ impl Game { pub fn query_stone_owner(&self) -> Player { match self.turn_order { - TurnOrder::BlackPlacesWhite => Player::White, TurnOrder::WhitePlacesBlack => Player::Black, + TurnOrder::BlackPlacesWhite => Player::White, TurnOrder::Normal => self.current_player, } } @@ -734,11 +734,11 @@ impl Game { let mut newline = true; let num_actions = self.actions.len(); if num_actions > 0 { - result += "0. "; + result += "1. "; 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!("{}. ", i / 2 + 1); } result += &format!("{} ", self.actions[i]); if i > 0 && !newline { @@ -761,27 +761,27 @@ impl Game { let state = maybe_state.unwrap(); let new_state_either = match &act { Action::Place(player, pos, stone) => match self.turn_order { - TurnOrder::BlackPlacesWhite => { - if (self.current_player == Player::Black) - && (*player == Player::White) + TurnOrder::WhitePlacesBlack => { + if (self.current_player == Player::White) + && (*player == Player::Black) && (*stone == Stone::Flat) { state.place_stone(*player, pos, *stone) } else { Err(String::from( - "At the start of the game, B must place a W flat.", + "At the start of the game, W must place a B flat.", )) } } - TurnOrder::WhitePlacesBlack => { - if (self.current_player == Player::White) - && (*player == Player::Black) + TurnOrder::BlackPlacesWhite => { + if (self.current_player == Player::Black) + && (*player == Player::White) && (*stone == Stone::Flat) { state.place_stone(*player, pos, *stone) } else { Err(String::from( - "At the start of the game, W must place a B flat.", + "At the start of the game, B must place a W flat.", )) } } @@ -810,8 +810,8 @@ impl Game { self.states.push(new_state); self.actions.push(act); self.current_player = match self.turn_order { + TurnOrder::WhitePlacesBlack => Player::Black, TurnOrder::BlackPlacesWhite => Player::White, - TurnOrder::WhitePlacesBlack => Player::White, TurnOrder::Normal => match self.current_player { Player::Black => Player::White, Player::White => Player::Black, @@ -819,8 +819,8 @@ impl Game { }; self.turn_order = match self.turn_order { - TurnOrder::BlackPlacesWhite => TurnOrder::WhitePlacesBlack, - TurnOrder::WhitePlacesBlack => TurnOrder::Normal, + TurnOrder::WhitePlacesBlack => TurnOrder::BlackPlacesWhite, + TurnOrder::BlackPlacesWhite => TurnOrder::Normal, TurnOrder::Normal => TurnOrder::Normal, }; return Ok((pos_vec, self.last_state().check_win())); diff --git a/src/main.rs b/src/main.rs index be24a77..8335422 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,5 @@ +extern crate argparse; + mod consulter; mod game; mod gui; @@ -7,23 +9,22 @@ use crate::consulter::*; use crate::game::*; use crate::gui::*; use crate::parser::*; + +use argparse::*; use std::io::Error; +use std::time::SystemTime; -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), - } - } +struct GUI { + screen: Window, + width: i32, + height: i32, + game_log: GameLog, + message_log: MessageLog, + action_entry: ActionEntry, + board_gui: BoardGUI, } -fn main() { +fn init_gui(size: u8) -> GUI { let screen = initscr(); cbreak(); noecho(); @@ -45,7 +46,6 @@ fn main() { screen.refresh(); - let size = 5; let cell_height = 4; let cell_width = 8; let hoff = 3; @@ -53,7 +53,7 @@ fn main() { let board_bottom = (size * cell_height + 3) as i32; let board_right = (size * cell_width + hoff + 3) as i32; - let mut board_gui = BoardGUI::new( + let board_gui = BoardGUI::new( 0, 0, size, @@ -87,27 +87,127 @@ fn main() { red_colour, ); - let (mut game, warning) = Game::new(5, "tslil", "taktician"); - message_log.log_error(warning); - game_log.update(&game); + GUI { + screen, + width, + height, + game_log, + message_log, + action_entry, + board_gui, + } +} + +fn human_action(gui: &GUI, game: &Game) -> Result<Action, Error> { + loop { + let inp = gui.action_entry.read_action(); + match parse_action(&game, &inp) { + Err(err) => gui + .message_log + .log_error(format!("Input \"{}\": {}", inp, err)), + Ok(action) => { + gui.action_entry.clear_entry_area(); + return Ok(action); + } + } + } +} + +fn main() { + let mut p1_name = String::from("Player1"); + let mut p2_name = String::from("Player2"); + let mut computer_opponent = String::new(); + let mut size: u8 = 5; + + { + let mut ap = ArgumentParser::new(); + ap.set_description("Test description."); + + ap.refer(&mut p1_name).add_option( + &["--player1"], + Store, + "Name of first player, Black/White assignment is still random.", + ); + + ap.refer(&mut p2_name).add_option( + &["--player2"], + Store, + "Name of second player, ignored if playing against a + computer opponent.", + ); + + ap.refer(&mut computer_opponent).add_option( + &["-e", "--engine"], + Store, + "Name of process which will be used as a computer opponent. + The process must accept a single argument point to a PTN file + of the current game state, and must generate a single PTN action + on STDOUT.", + ); + + ap.refer(&mut size).add_option( + &["-s", "--size"], + Store, + "Size of board (one dimension), default is 5.", + ); + + ap.add_option( + &["-V", "--version"], + Print(env!("CARGO_PKG_VERSION").to_string()), + "Show version", + ); + ap.parse_args_or_exit(); + } + + let human_first; + let call_proc; + if !computer_opponent.is_empty() { + p2_name = computer_opponent.clone(); + call_proc = true; + // Perhaps there's a better way. + human_first = match SystemTime::now().duration_since(SystemTime::UNIX_EPOCH) { + Ok(n) => n.as_secs() % 2 == 0, + Err(_) => false, + }; + } else { + human_first = false; + call_proc = false; + } + + let gui = init_gui(size); + + let (mut game, warning) = Game::new(size, &p1_name, &p2_name); + gui.message_log.log_error(warning); + gui.game_log.update(&game); - const CONSULT_PROC: &str = "/home/tslil/bin/wrap_taktician"; loop { let inp = match game.query_current_player() { - Player::Black => consult_next_action(&game, CONSULT_PROC), - Player::White => human_action(&action_entry, &message_log, &game), + Player::Black => { + if call_proc && human_first { + consult_next_action(&game, &computer_opponent) + } else { + human_action(&gui, &game) + } + } + Player::White => { + if call_proc && (!human_first) { + consult_next_action(&game, &computer_opponent) + } else { + human_action(&gui, &game) + } + } }; match inp { Err(err) => { - message_log.log_error(format!("{}", err)); + gui.message_log.log_error(format!("{}", err)); break; } Ok(act) => { let stone_owner = game.query_stone_owner(); let player = game.query_current_player(); - message_log.log_message(format!( + gui.message_log.log_message(format!( "{} performs {}{}", player, act, @@ -119,28 +219,33 @@ fn main() { )); match game.perform_action(act) { Err(e) => { - message_log.log_error(e); - if game.query_current_player() == Player::Black { - // external and internal gamestates diverged + gui.message_log.log_error(e); + let current = game.query_current_player(); + if call_proc + && ((human_first && current == Player::Black) + || ((!human_first) && current == Player::White)) + { + gui.message_log.log_error(String::from( + "Error: external and internal game states disagree.", + )); break; } } Ok((pos_vec, win)) => { - board_gui.update(&game, pos_vec); - game_log.update(&game); + gui.board_gui.update(&game, pos_vec); + gui.game_log.update(&game); if let Some(w) = win { - message_log.log_message(format!("{}", w)); + gui.message_log.log_message(format!("{}", w)); break; } } } } } - action_entry.clear_entry_area(); } - screen.getch(); + gui.screen.getch(); // board_gui.read_action(); endwin(); } |
