diff --git a/t4t-games/src/tic_tac_toe.rs b/t4t-games/src/tic_tac_toe.rs index 9b6f9a5..2487922 100644 --- a/t4t-games/src/tic_tac_toe.rs +++ b/t4t-games/src/tic_tac_toe.rs @@ -8,6 +8,7 @@ //! # Example //! //! ``` +//! use log::warn; //! use t4t::*; //! use t4t_games::tic_tac_toe::*; //! @@ -23,10 +24,14 @@ //! let mut cats_games = 0; //! //! // Play 5 games, letting Random go first. -//! for _ in 0..5 { +//! for i in 0..5 { //! let outcome = //! TicTacToe.play(&Matchup::from_players([random.clone(), minimax.clone()])).unwrap(); //! +//! // Print the final board state. +//! println!("\nGame {}:", i + 1); +//! outcome.final_state().print(); +//! //! // Update the scores. //! let payoff = *outcome.payoff(); //! if payoff == Payoff::zeros() { @@ -187,6 +192,21 @@ impl Board { } None } + + /// Print the current state of the board to stdout. + pub fn print(&self) { + let mark = |r: usize, c: usize| match self.squares[r][c] { + None => ' ', + Some(Mark::X) => 'X', + Some(Mark::O) => 'O', + }; + + println!("{}|{}|{}", mark(0, 0), mark(0, 1), mark(0, 2)); + println!("-----"); + println!("{}|{}|{}", mark(1, 0), mark(1, 1), mark(1, 2)); + println!("-----"); + println!("{}|{}|{}", mark(2, 0), mark(2, 1), mark(2, 2)); + } } impl Default for Board { diff --git a/t4t/src/combinatorial.rs b/t4t/src/combinatorial.rs index 437c97c..86c0548 100644 --- a/t4t/src/combinatorial.rs +++ b/t4t/src/combinatorial.rs @@ -40,10 +40,14 @@ fn generate_tree + 'static, const P: usize>( game: Arc, state: G::State, transcript: Transcript, -) -> GameTree, P> { +) -> GameTree, P> +{ let player = game.whose_turn(&state); match game.payoff(&state) { - Some(payoff) => GameTree::end(state, SequentialOutcome::new(transcript, payoff)), + Some(payoff) => GameTree::end( + state.clone(), + SequentialOutcome::new(state, transcript, payoff), + ), None => GameTree::player(state, player, move |state, the_move| { let next_state = game.next_state(state, the_move)?; @@ -61,7 +65,7 @@ fn generate_tree + 'static, const P: usize>( } impl + 'static, const P: usize> Playable

for G { - type Outcome = SequentialOutcome; + type Outcome = SequentialOutcome; fn into_game_tree(self) -> GameTree { let initial_state = self.initial_state(); diff --git a/t4t/src/history.rs b/t4t/src/history.rs index 701c8c4..729db2d 100644 --- a/t4t/src/history.rs +++ b/t4t/src/history.rs @@ -2,7 +2,7 @@ use std::marker::PhantomData; use crate::{ Move, Outcome, Past, Payoff, PlayerIndex, Plies, Profile, Record, SequentialOutcome, - SimultaneousOutcome, Summary, Transcript, Utility, + SimultaneousOutcome, State, Summary, Transcript, Utility, }; /// For repeated games, a history of previously played games. @@ -74,7 +74,9 @@ impl History History, P> { +impl + History, P> +{ /// Get an iterator over the transcripts of previously played games. pub fn transcripts(&self) -> Past<&Transcript> { Past::from_iter( diff --git a/t4t/src/outcome.rs b/t4t/src/outcome.rs index 07f759f..b3e2fcb 100644 --- a/t4t/src/outcome.rs +++ b/t4t/src/outcome.rs @@ -1,7 +1,9 @@ use std::fmt::Debug; use std::sync::Arc; -use crate::{Move, Payoff, PlayerIndex, PossibleProfiles, Profile, Record, Transcript, Utility}; +use crate::{ + Move, Payoff, PlayerIndex, PossibleProfiles, Profile, Record, State, Transcript, Utility, +}; /// A (potential) outcome of a game. A payoff combined with a record of the moves that produced it. /// @@ -69,15 +71,25 @@ impl Outcome for SimultaneousOutco /// /// For extensive-form games, an outcome corresponds to a path through the game tree. #[derive(Clone, Debug, PartialEq, Hash)] -pub struct SequentialOutcome { +pub struct SequentialOutcome { + final_state: S, transcript: Transcript, payoff: Payoff, } -impl SequentialOutcome { +impl SequentialOutcome { /// Construct a new sequential game outcome. - pub fn new(transcript: Transcript, payoff: Payoff) -> Self { - SequentialOutcome { transcript, payoff } + pub fn new(final_state: S, transcript: Transcript, payoff: Payoff) -> Self { + SequentialOutcome { + final_state, + transcript, + payoff, + } + } + + /// The final state when the game ended. + pub fn final_state(&self) -> &S { + &self.final_state } /// The move transcript associated with this outcome. @@ -86,7 +98,9 @@ impl SequentialOutcome { } } -impl Outcome for SequentialOutcome { +impl Outcome + for SequentialOutcome +{ type Record = Transcript; fn record(&self) -> &Transcript {