From 188023e13f9b5adb7434a9cf7b9a5f5b9d0e76b2 Mon Sep 17 00:00:00 2001 From: Max Fierro Date: Thu, 18 Apr 2024 20:25:19 -0700 Subject: [PATCH 1/4] Added skeleton for example game module --- src/game/mock/builder.rs | 1 - src/game/mock/example.rs | 612 ++++++++++++++++++++++++++++++++++++++- src/game/mock/mod.rs | 45 ++- 3 files changed, 646 insertions(+), 12 deletions(-) diff --git a/src/game/mock/builder.rs b/src/game/mock/builder.rs index f43d83e..c59cef3 100644 --- a/src/game/mock/builder.rs +++ b/src/game/mock/builder.rs @@ -319,7 +319,6 @@ impl Node { } } -#[cfg(test)] mod tests { use super::*; diff --git a/src/game/mock/example.rs b/src/game/mock/example.rs index 076fca4..d1db503 100644 --- a/src/game/mock/example.rs +++ b/src/game/mock/example.rs @@ -1,4 +1,4 @@ -//! Example Mock Test Game Module +//! # Example Mock Test Game Module //! //! This module provides concrete examples of small games that adhere to useful //! interface definitions that can be used for testing purposes. The games here @@ -6,3 +6,613 @@ //! //! #### Authorship //! - Max Fierro, 4/8/2024 + +/* CONSTANTS */ + +/// Specifies a directory name under which to store visualizations of the games +/// declared in this module. +const MODULE_STORAGE: &str = "mock-game-examples"; + +/* CATEGORIES */ + +/// Contains examples of mock games where utility can be expressed as `WIN`, +/// `LOSE`, `TIE`, or `DRAW` for players. +pub mod simple_utility { + + /* CATEGORIES */ + + /// Contains examples of mock games where payoffs for terminal states can + /// sum to anything across all players. + pub mod general_sum { + + use anyhow::Result; + + use crate::game::{mock::*, SimpleSum}; + use crate::model::SimpleUtility; + use crate::node; + + /* CONSTANTS */ + + const TREE_GAME_NAME: &str = + "simple-utility-general-sum-tree-structure"; + const ACYCLIC_GAME_NAME: &str = + "simple-utility-general-sum-acyclic-structure"; + const CYCLIC_GAME_NAME: &str = + "simple-utility-general-sum-cyclic-structure"; + + /* DEFINITIONS */ + + /// TODO + pub struct TreeExampleGame<'a> { + game: Session<'a>, + } + + /// TODO + pub struct AcyclicExampleGame<'a> { + game: Session<'a>, + } + + /// TODO + pub struct CyclicExampleGame<'a> { + game: Session<'a>, + } + + /* INSTANTIATION */ + + impl<'a> TreeExampleGame<'a> { + /// TODO + pub fn new( + store: &'a mut Vec, + ) -> Result> { + *store = vec![ + node!(0), + node!(1), + node!(1), + node!(1), + node!(0), + node!(0), + node!(0), + node!(0), + node!(0), + node!(0), + node![ + SimpleUtility::LOSE.into(), + SimpleUtility::WIN.into(), + ], + node![ + SimpleUtility::WIN.into(), + SimpleUtility::LOSE.into(), + ], + node![ + SimpleUtility::TIE.into(), + SimpleUtility::WIN.into(), + ], + node![ + SimpleUtility::TIE.into(), + SimpleUtility::TIE.into(), + ], + node![ + SimpleUtility::WIN.into(), + SimpleUtility::WIN.into(), + ], + node![ + SimpleUtility::LOSE.into(), + SimpleUtility::LOSE.into(), + ], + node![ + SimpleUtility::LOSE.into(), + SimpleUtility::WIN.into(), + ], + node![ + SimpleUtility::WIN.into(), + SimpleUtility::LOSE.into(), + ], + node![ + SimpleUtility::LOSE.into(), + SimpleUtility::TIE.into(), + ], + ]; + + let game = builder::SessionBuilder::new(&TREE_GAME_NAME) + .edge(&store[0], &store[1])? + .edge(&store[0], &store[2])? + .edge(&store[0], &store[3])? + .edge(&store[1], &store[4])? + .edge(&store[1], &store[5])? + .edge(&store[1], &store[6])? + .edge(&store[2], &store[7])? + .edge(&store[2], &store[8])? + .edge(&store[2], &store[9])? + .edge(&store[3], &store[10])? + .edge(&store[3], &store[11])? + .edge(&store[3], &store[12])? + .edge(&store[4], &store[13])? + .edge(&store[5], &store[14])? + .edge(&store[6], &store[15])? + .edge(&store[7], &store[16])? + .edge(&store[8], &store[17])? + .edge(&store[9], &store[18])? + .build()?; + + Ok(TreeExampleGame { game }) + } + + /// TODO + pub fn visualize(&self) -> Result<()> { + self.game + .visualize(super::super::MODULE_STORAGE) + } + } + + impl<'a> AcyclicExampleGame<'a> { + /// TODO + pub fn new( + store: &'a mut Vec, + ) -> Result> { + todo!() + } + + /// TODO + pub fn visualize(&self) -> Result<()> { + self.game + .visualize(super::super::MODULE_STORAGE) + } + } + + impl<'a> CyclicExampleGame<'a> { + /// TODO + pub fn new( + store: &'a mut Vec, + ) -> Result> { + todo!() + } + + /// TODO + pub fn visualize(&self) -> Result<()> { + self.game + .visualize(super::super::MODULE_STORAGE) + } + } + + /* TRAVERSAL IMPLEMENTATIONS */ + + impl MockGame for TreeExampleGame<'_> { + fn game(&self) -> &Session<'_> { + &self.game + } + } + + impl MockGame for AcyclicExampleGame<'_> { + fn game(&self) -> &Session<'_> { + &self.game + } + } + + impl MockGame for CyclicExampleGame<'_> { + fn game(&self) -> &Session<'_> { + &self.game + } + } + + /* TREE GAME UTILITY IMPLEMENTATIONS */ + + impl SimpleSum<2> for TreeExampleGame<'_> { + fn utility(&self, state: State) -> [SimpleUtility; 2] { + match self.game.node(state) { + Node::Terminal(vector) => [ + vector[0].try_into().unwrap(), + vector[1].try_into().unwrap(), + ], + Node::Medial(_) => { + panic!("Attempted to fetch utility of medial state.") + }, + } + } + } + } + + /// Contains examples of mock games where payoffs for terminal states always + /// sum to zero across all players. + pub mod zero_sum { + + use anyhow::Result; + + use crate::game::{mock::*, SimpleSum}; + use crate::model::SimpleUtility; + use crate::node; + + /* CONSTANTS */ + + const TREE_GAME_NAME: &str = "simple-utility-zero-sum-tree-structure"; + const ACYCLIC_GAME_NAME: &str = + "simple-utility-zero-sum-acyclic-structure"; + const CYCLIC_GAME_NAME: &str = + "simple-utility-zero-sum-cyclic-structure"; + + /* DEFINITIONS */ + + /// TODO + pub struct TreeExampleGame<'a> { + game: Session<'a>, + } + + /// TODO + pub struct AcyclicExampleGame<'a> { + game: Session<'a>, + } + + /// TODO + pub struct CyclicExampleGame<'a> { + game: Session<'a>, + } + + /* INSTANTIATION */ + + impl<'a> TreeExampleGame<'a> { + /// TODO + pub fn new( + store: &'a mut Vec, + ) -> Result> { + todo!() + } + + /// TODO + pub fn visualize(&self) -> Result<()> { + self.game + .visualize(super::super::MODULE_STORAGE) + } + } + + impl<'a> AcyclicExampleGame<'a> { + /// TODO + pub fn new( + store: &'a mut Vec, + ) -> Result> { + todo!() + } + + /// TODO + pub fn visualize(&self) -> Result<()> { + self.game + .visualize(super::super::MODULE_STORAGE) + } + } + + impl<'a> CyclicExampleGame<'a> { + /// TODO + pub fn new( + store: &'a mut Vec, + ) -> Result> { + todo!() + } + + /// TODO + pub fn visualize(&self) -> Result<()> { + self.game + .visualize(super::super::MODULE_STORAGE) + } + } + + /* TRAVERSAL IMPLEMENTATIONS */ + + impl MockGame for TreeExampleGame<'_> { + fn game(&self) -> &Session<'_> { + &self.game + } + } + + impl MockGame for AcyclicExampleGame<'_> { + fn game(&self) -> &Session<'_> { + &self.game + } + } + + impl MockGame for CyclicExampleGame<'_> { + fn game(&self) -> &Session<'_> { + &self.game + } + } + } +} + +/// Contains examples of mock games where utility can be expressed as an general +/// for players. +pub mod general_utility { + + /* CATEGORIES */ + + /// Contains examples of mock games where payoffs for terminal states can + /// sum to anything across all players. + pub mod general_sum { + + use anyhow::Result; + + use crate::game::{mock::*, SimpleSum}; + use crate::model::SimpleUtility; + use crate::node; + + /* CONSTANTS */ + + const TREE_GAME_NAME: &str = + "general-utility-general-sum-tree-structure"; + const ACYCLIC_GAME_NAME: &str = + "general-utility-general-sum-acyclic-structure"; + const CYCLIC_GAME_NAME: &str = + "general-utility-general-sum-cyclic-structure"; + + /* DEFINITIONS */ + + /// TODO + pub struct TreeExampleGame<'a> { + game: Session<'a>, + } + + /// TODO + pub struct AcyclicExampleGame<'a> { + game: Session<'a>, + } + + /// TODO + pub struct CyclicExampleGame<'a> { + game: Session<'a>, + } + + /* INSTANTIATION */ + + impl<'a> TreeExampleGame<'a> { + /// TODO + pub fn new( + store: &'a mut Vec, + ) -> Result> { + todo!() + } + + /// TODO + pub fn visualize(&self) -> Result<()> { + self.game + .visualize(super::super::MODULE_STORAGE) + } + } + + impl<'a> AcyclicExampleGame<'a> { + /// TODO + pub fn new( + store: &'a mut Vec, + ) -> Result> { + todo!() + } + + /// TODO + pub fn visualize(&self) -> Result<()> { + self.game + .visualize(super::super::MODULE_STORAGE) + } + } + + impl<'a> CyclicExampleGame<'a> { + /// TODO + pub fn new( + store: &'a mut Vec, + ) -> Result> { + todo!() + } + + /// TODO + pub fn visualize(&self) -> Result<()> { + self.game + .visualize(super::super::MODULE_STORAGE) + } + } + + /* TRAVERSAL IMPLEMENTATIONS */ + + impl MockGame for TreeExampleGame<'_> { + fn game(&self) -> &Session<'_> { + &self.game + } + } + + impl MockGame for AcyclicExampleGame<'_> { + fn game(&self) -> &Session<'_> { + &self.game + } + } + + impl MockGame for CyclicExampleGame<'_> { + fn game(&self) -> &Session<'_> { + &self.game + } + } + } + + /// Contains examples of mock games where payoffs for terminal states always + /// sum to zero across all players. + pub mod zero_sum { + + use anyhow::Result; + + use crate::game::{mock::*, SimpleSum}; + use crate::model::SimpleUtility; + use crate::node; + + /* CONSTANTS */ + + const TREE_GAME_NAME: &str = "general-utility-zero-sum-tree-structure"; + const ACYCLIC_GAME_NAME: &str = + "general-utility-zero-sum-acyclic-structure"; + const CYCLIC_GAME_NAME: &str = + "general-utility-zero-sum-cyclic-structure"; + + /* DEFINITIONS */ + + /// TODO + pub struct TreeExampleGame<'a> { + game: Session<'a>, + } + + /// TODO + pub struct AcyclicExampleGame<'a> { + game: Session<'a>, + } + + /// TODO + pub struct CyclicExampleGame<'a> { + game: Session<'a>, + } + + /* INSTANTIATION */ + + impl<'a> TreeExampleGame<'a> { + /// TODO + pub fn new( + store: &'a mut Vec, + ) -> Result> { + todo!() + } + + /// TODO + pub fn visualize(&self) -> Result<()> { + self.game + .visualize(super::super::MODULE_STORAGE) + } + } + + impl<'a> AcyclicExampleGame<'a> { + /// TODO + pub fn new( + store: &'a mut Vec, + ) -> Result> { + todo!() + } + + /// TODO + pub fn visualize(&self) -> Result<()> { + self.game + .visualize(super::super::MODULE_STORAGE) + } + } + + impl<'a> CyclicExampleGame<'a> { + /// TODO + pub fn new( + store: &'a mut Vec, + ) -> Result> { + todo!() + } + + /// TODO + pub fn visualize(&self) -> Result<()> { + self.game + .visualize(super::super::MODULE_STORAGE) + } + } + + /* TRAVERSAL IMPLEMENTATIONS */ + + impl MockGame for TreeExampleGame<'_> { + fn game(&self) -> &Session<'_> { + &self.game + } + } + + impl MockGame for AcyclicExampleGame<'_> { + fn game(&self) -> &Session<'_> { + &self.game + } + } + + impl MockGame for CyclicExampleGame<'_> { + fn game(&self) -> &Session<'_> { + &self.game + } + } + } +} + +mod tests { + + use anyhow::Result; + + use super::*; + + #[test] + fn initialize_simple_utility_general_sum() -> Result<()> { + let mut s = vec![]; + let _ = simple_utility::general_sum::TreeExampleGame::new(&mut s)?; + let _ = simple_utility::general_sum::AcyclicExampleGame::new(&mut s)?; + let _ = simple_utility::general_sum::CyclicExampleGame::new(&mut s)?; + Ok(()) + } + + #[test] + fn initialize_simple_utility_zero_sum() -> Result<()> { + let mut s = vec![]; + let _ = simple_utility::zero_sum::TreeExampleGame::new(&mut s)?; + let _ = simple_utility::zero_sum::AcyclicExampleGame::new(&mut s)?; + let _ = simple_utility::zero_sum::CyclicExampleGame::new(&mut s)?; + Ok(()) + } + + #[test] + fn initialize_general_utility_general_sum() -> Result<()> { + let mut s = vec![]; + let _ = general_utility::general_sum::TreeExampleGame::new(&mut s)?; + let _ = general_utility::general_sum::AcyclicExampleGame::new(&mut s)?; + let _ = general_utility::general_sum::CyclicExampleGame::new(&mut s)?; + Ok(()) + } + + #[test] + fn initialize_general_utility_zero_sum() -> Result<()> { + let mut s = vec![]; + let _ = general_utility::zero_sum::TreeExampleGame::new(&mut s)?; + let _ = general_utility::zero_sum::AcyclicExampleGame::new(&mut s)?; + let _ = general_utility::zero_sum::CyclicExampleGame::new(&mut s)?; + Ok(()) + } + + #[test] + fn visualize_all_example_games() -> Result<()> { + let mut s = vec![]; + let _ = simple_utility::general_sum::TreeExampleGame::new(&mut s)? + .visualize(); + let mut s = vec![]; + let _ = simple_utility::general_sum::AcyclicExampleGame::new(&mut s)? + .visualize(); + let mut s = vec![]; + let _ = simple_utility::general_sum::CyclicExampleGame::new(&mut s)? + .visualize(); + + let mut s = vec![]; + let _ = + simple_utility::zero_sum::TreeExampleGame::new(&mut s)?.visualize(); + let mut s = vec![]; + let _ = simple_utility::zero_sum::AcyclicExampleGame::new(&mut s)? + .visualize(); + let mut s = vec![]; + let _ = simple_utility::zero_sum::CyclicExampleGame::new(&mut s)? + .visualize(); + + let mut s = vec![]; + let _ = general_utility::general_sum::TreeExampleGame::new(&mut s)? + .visualize(); + let mut s = vec![]; + let _ = general_utility::general_sum::AcyclicExampleGame::new(&mut s)? + .visualize(); + let mut s = vec![]; + let _ = general_utility::general_sum::CyclicExampleGame::new(&mut s)? + .visualize(); + + let mut s = vec![]; + let _ = general_utility::zero_sum::TreeExampleGame::new(&mut s)? + .visualize(); + let mut s = vec![]; + let _ = general_utility::zero_sum::AcyclicExampleGame::new(&mut s)? + .visualize(); + let mut s = vec![]; + let _ = general_utility::zero_sum::CyclicExampleGame::new(&mut s)? + .visualize(); + + Ok(()) + } +} diff --git a/src/game/mock/mod.rs b/src/game/mock/mod.rs index 0ad08e0..79c43a5 100644 --- a/src/game/mock/mod.rs +++ b/src/game/mock/mod.rs @@ -1,4 +1,4 @@ -//! Mock Extensive Test Game Module +//! # Mock Extensive Test Game Module //! //! This module provides a way to represent extensive-form games by declaring //! the game via a graph and assigning special conditions to nodes. This makes @@ -53,6 +53,13 @@ pub enum Node { Medial(Turn), } +/// Indicates that something can be turned into a mock game session. Used to +/// create blanket implementations for example mock games. +trait MockGame { + /// Returns an underlying mock game instance. + fn game(&self) -> &Session<'_>; +} + /* API IMPLEMENTATION */ impl<'a> Session<'a> { @@ -103,21 +110,36 @@ impl<'a> Session<'a> { } } -/* UTILITY IMPLEMENTATIONS */ +/* BLANKET IMPLEMENTATIONS */ -impl DTransition for Session<'_> { +impl MockGame for Session<'_> { + fn game(&self) -> &Session<'_> { + self + } +} + +impl DTransition for T +where + T: MockGame, +{ fn prograde(&self, state: State) -> Vec { - self.transition(state, Direction::Outgoing) + self.game() + .transition(state, Direction::Outgoing) } fn retrograde(&self, state: State) -> Vec { - self.transition(state, Direction::Incoming) + self.game() + .transition(state, Direction::Incoming) } } -impl STransition for Session<'_> { +impl STransition for T +where + T: MockGame, +{ fn prograde(&self, state: State) -> [Option; MAX_TRANSITIONS] { let adjacent = self + .game() .transition(state, Direction::Outgoing) .iter() .map(|&h| Some(h)) @@ -134,6 +156,7 @@ impl STransition for Session<'_> { fn retrograde(&self, state: State) -> [Option; MAX_TRANSITIONS] { let adjacent = self + .game() .transition(state, Direction::Incoming) .iter() .map(|&h| Some(h)) @@ -149,20 +172,22 @@ impl STransition for Session<'_> { } } -impl Bounded for Session<'_> { +impl Bounded for T +where + T: MockGame, +{ fn start(&self) -> State { - self.start.index() as State + self.game().start.index() as State } fn end(&self, state: State) -> bool { - match self.node(state) { + match self.game().node(state) { Node::Terminal(_) => true, Node::Medial(_) => false, } } } -#[cfg(test)] mod tests { use super::*; From 74fcbb131860419c181f03afa17ac6ec8325c1da Mon Sep 17 00:00:00 2001 From: Max Fierro Date: Thu, 18 Apr 2024 20:28:18 -0700 Subject: [PATCH 2/4] Fixed no starting node for first example --- src/game/mock/example.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/game/mock/example.rs b/src/game/mock/example.rs index d1db503..96d584b 100644 --- a/src/game/mock/example.rs +++ b/src/game/mock/example.rs @@ -132,6 +132,7 @@ pub mod simple_utility { .edge(&store[7], &store[16])? .edge(&store[8], &store[17])? .edge(&store[9], &store[18])? + .start(&store[0])? .build()?; Ok(TreeExampleGame { game }) From 39683584bd534abf9d558c065ce86584447aab7f Mon Sep 17 00:00:00 2001 From: Max Fierro Date: Thu, 18 Apr 2024 20:38:37 -0700 Subject: [PATCH 3/4] Added docstrings for guidance --- src/game/mock/example.rs | 37 +++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/src/game/mock/example.rs b/src/game/mock/example.rs index 96d584b..a265be3 100644 --- a/src/game/mock/example.rs +++ b/src/game/mock/example.rs @@ -60,11 +60,16 @@ pub mod simple_utility { /* INSTANTIATION */ impl<'a> TreeExampleGame<'a> { - /// TODO + /// Creates a new [`TreeExampleGame`] by instantiating all of its + /// nodes and appending them to `store` non-destructively (even if + /// the function fails). The example game returned will reference + /// the nodes added to `store` internally, so removing them from + /// `store` and attempting to use the returned game after is + /// undefined behavior. pub fn new( store: &'a mut Vec, ) -> Result> { - *store = vec![ + let mut nodes = vec![ node!(0), node!(1), node!(1), @@ -113,6 +118,10 @@ pub mod simple_utility { ], ]; + let length = store.len(); + store.append(&mut nodes); + let store = &store[length..]; + let game = builder::SessionBuilder::new(&TREE_GAME_NAME) .edge(&store[0], &store[1])? .edge(&store[0], &store[2])? @@ -138,7 +147,7 @@ pub mod simple_utility { Ok(TreeExampleGame { game }) } - /// TODO + /// Creates a PNG image of the game being represented. pub fn visualize(&self) -> Result<()> { self.game .visualize(super::super::MODULE_STORAGE) @@ -153,7 +162,7 @@ pub mod simple_utility { todo!() } - /// TODO + /// Creates a PNG image of the game being represented. pub fn visualize(&self) -> Result<()> { self.game .visualize(super::super::MODULE_STORAGE) @@ -168,7 +177,7 @@ pub mod simple_utility { todo!() } - /// TODO + /// Creates a PNG image of the game being represented. pub fn visualize(&self) -> Result<()> { self.game .visualize(super::super::MODULE_STORAGE) @@ -257,7 +266,7 @@ pub mod simple_utility { todo!() } - /// TODO + /// Creates a PNG image of the game being represented. pub fn visualize(&self) -> Result<()> { self.game .visualize(super::super::MODULE_STORAGE) @@ -272,7 +281,7 @@ pub mod simple_utility { todo!() } - /// TODO + /// Creates a PNG image of the game being represented. pub fn visualize(&self) -> Result<()> { self.game .visualize(super::super::MODULE_STORAGE) @@ -287,7 +296,7 @@ pub mod simple_utility { todo!() } - /// TODO + /// Creates a PNG image of the game being represented. pub fn visualize(&self) -> Result<()> { self.game .visualize(super::super::MODULE_STORAGE) @@ -368,7 +377,7 @@ pub mod general_utility { todo!() } - /// TODO + /// Creates a PNG image of the game being represented. pub fn visualize(&self) -> Result<()> { self.game .visualize(super::super::MODULE_STORAGE) @@ -383,7 +392,7 @@ pub mod general_utility { todo!() } - /// TODO + /// Creates a PNG image of the game being represented. pub fn visualize(&self) -> Result<()> { self.game .visualize(super::super::MODULE_STORAGE) @@ -398,7 +407,7 @@ pub mod general_utility { todo!() } - /// TODO + /// Creates a PNG image of the game being represented. pub fn visualize(&self) -> Result<()> { self.game .visualize(super::super::MODULE_STORAGE) @@ -471,7 +480,7 @@ pub mod general_utility { todo!() } - /// TODO + /// Creates a PNG image of the game being represented. pub fn visualize(&self) -> Result<()> { self.game .visualize(super::super::MODULE_STORAGE) @@ -486,7 +495,7 @@ pub mod general_utility { todo!() } - /// TODO + /// Creates a PNG image of the game being represented. pub fn visualize(&self) -> Result<()> { self.game .visualize(super::super::MODULE_STORAGE) @@ -501,7 +510,7 @@ pub mod general_utility { todo!() } - /// TODO + /// Creates a PNG image of the game being represented. pub fn visualize(&self) -> Result<()> { self.game .visualize(super::super::MODULE_STORAGE) From 946a45af69489f1b4a3937ffff539c7f583b7308 Mon Sep 17 00:00:00 2001 From: Benjamin Riley Zimmerman Date: Fri, 19 Apr 2024 18:55:12 -0700 Subject: [PATCH 4/4] new example game visualization module diff: + src/game/mock/example/ ! + general_utility/ /\_/\ ( + general_sum/ + Tree - Ayclic - Cyclic ( ^.^ ) _) + zero_sum/ - Tree - Ayclic - Cyclic \ / ( + simple_utility/ ( | | ) + general_sum/ + Tree + Ayclic + Cyclic (__d b__) + zero_sum/ + Tree + Ayclic + Cyclic --- src/game/mock/builder.rs | 1 + src/game/mock/example.rs | 628 ------------------ .../general_utility/general_sum/mod.rs | 139 ++++ src/game/mock/example/general_utility/mod.rs | 10 + .../example/general_utility/zero_sum/mod.rs | 91 +++ src/game/mock/example/mod.rs | 77 +++ .../example/simple_utility/general_sum/mod.rs | 352 ++++++++++ src/game/mock/example/simple_utility/mod.rs | 10 + .../example/simple_utility/zero_sum/mod.rs | 286 ++++++++ src/game/mock/mod.rs | 1 + 10 files changed, 967 insertions(+), 628 deletions(-) delete mode 100644 src/game/mock/example.rs create mode 100644 src/game/mock/example/general_utility/general_sum/mod.rs create mode 100644 src/game/mock/example/general_utility/mod.rs create mode 100644 src/game/mock/example/general_utility/zero_sum/mod.rs create mode 100644 src/game/mock/example/mod.rs create mode 100644 src/game/mock/example/simple_utility/general_sum/mod.rs create mode 100644 src/game/mock/example/simple_utility/mod.rs create mode 100644 src/game/mock/example/simple_utility/zero_sum/mod.rs diff --git a/src/game/mock/builder.rs b/src/game/mock/builder.rs index c59cef3..f43d83e 100644 --- a/src/game/mock/builder.rs +++ b/src/game/mock/builder.rs @@ -319,6 +319,7 @@ impl Node { } } +#[cfg(test)] mod tests { use super::*; diff --git a/src/game/mock/example.rs b/src/game/mock/example.rs deleted file mode 100644 index a265be3..0000000 --- a/src/game/mock/example.rs +++ /dev/null @@ -1,628 +0,0 @@ -//! # Example Mock Test Game Module -//! -//! This module provides concrete examples of small games that adhere to useful -//! interface definitions that can be used for testing purposes. The games here -//! are built over the `mock` game graph implementation. -//! -//! #### Authorship -//! - Max Fierro, 4/8/2024 - -/* CONSTANTS */ - -/// Specifies a directory name under which to store visualizations of the games -/// declared in this module. -const MODULE_STORAGE: &str = "mock-game-examples"; - -/* CATEGORIES */ - -/// Contains examples of mock games where utility can be expressed as `WIN`, -/// `LOSE`, `TIE`, or `DRAW` for players. -pub mod simple_utility { - - /* CATEGORIES */ - - /// Contains examples of mock games where payoffs for terminal states can - /// sum to anything across all players. - pub mod general_sum { - - use anyhow::Result; - - use crate::game::{mock::*, SimpleSum}; - use crate::model::SimpleUtility; - use crate::node; - - /* CONSTANTS */ - - const TREE_GAME_NAME: &str = - "simple-utility-general-sum-tree-structure"; - const ACYCLIC_GAME_NAME: &str = - "simple-utility-general-sum-acyclic-structure"; - const CYCLIC_GAME_NAME: &str = - "simple-utility-general-sum-cyclic-structure"; - - /* DEFINITIONS */ - - /// TODO - pub struct TreeExampleGame<'a> { - game: Session<'a>, - } - - /// TODO - pub struct AcyclicExampleGame<'a> { - game: Session<'a>, - } - - /// TODO - pub struct CyclicExampleGame<'a> { - game: Session<'a>, - } - - /* INSTANTIATION */ - - impl<'a> TreeExampleGame<'a> { - /// Creates a new [`TreeExampleGame`] by instantiating all of its - /// nodes and appending them to `store` non-destructively (even if - /// the function fails). The example game returned will reference - /// the nodes added to `store` internally, so removing them from - /// `store` and attempting to use the returned game after is - /// undefined behavior. - pub fn new( - store: &'a mut Vec, - ) -> Result> { - let mut nodes = vec![ - node!(0), - node!(1), - node!(1), - node!(1), - node!(0), - node!(0), - node!(0), - node!(0), - node!(0), - node!(0), - node![ - SimpleUtility::LOSE.into(), - SimpleUtility::WIN.into(), - ], - node![ - SimpleUtility::WIN.into(), - SimpleUtility::LOSE.into(), - ], - node![ - SimpleUtility::TIE.into(), - SimpleUtility::WIN.into(), - ], - node![ - SimpleUtility::TIE.into(), - SimpleUtility::TIE.into(), - ], - node![ - SimpleUtility::WIN.into(), - SimpleUtility::WIN.into(), - ], - node![ - SimpleUtility::LOSE.into(), - SimpleUtility::LOSE.into(), - ], - node![ - SimpleUtility::LOSE.into(), - SimpleUtility::WIN.into(), - ], - node![ - SimpleUtility::WIN.into(), - SimpleUtility::LOSE.into(), - ], - node![ - SimpleUtility::LOSE.into(), - SimpleUtility::TIE.into(), - ], - ]; - - let length = store.len(); - store.append(&mut nodes); - let store = &store[length..]; - - let game = builder::SessionBuilder::new(&TREE_GAME_NAME) - .edge(&store[0], &store[1])? - .edge(&store[0], &store[2])? - .edge(&store[0], &store[3])? - .edge(&store[1], &store[4])? - .edge(&store[1], &store[5])? - .edge(&store[1], &store[6])? - .edge(&store[2], &store[7])? - .edge(&store[2], &store[8])? - .edge(&store[2], &store[9])? - .edge(&store[3], &store[10])? - .edge(&store[3], &store[11])? - .edge(&store[3], &store[12])? - .edge(&store[4], &store[13])? - .edge(&store[5], &store[14])? - .edge(&store[6], &store[15])? - .edge(&store[7], &store[16])? - .edge(&store[8], &store[17])? - .edge(&store[9], &store[18])? - .start(&store[0])? - .build()?; - - Ok(TreeExampleGame { game }) - } - - /// Creates a PNG image of the game being represented. - pub fn visualize(&self) -> Result<()> { - self.game - .visualize(super::super::MODULE_STORAGE) - } - } - - impl<'a> AcyclicExampleGame<'a> { - /// TODO - pub fn new( - store: &'a mut Vec, - ) -> Result> { - todo!() - } - - /// Creates a PNG image of the game being represented. - pub fn visualize(&self) -> Result<()> { - self.game - .visualize(super::super::MODULE_STORAGE) - } - } - - impl<'a> CyclicExampleGame<'a> { - /// TODO - pub fn new( - store: &'a mut Vec, - ) -> Result> { - todo!() - } - - /// Creates a PNG image of the game being represented. - pub fn visualize(&self) -> Result<()> { - self.game - .visualize(super::super::MODULE_STORAGE) - } - } - - /* TRAVERSAL IMPLEMENTATIONS */ - - impl MockGame for TreeExampleGame<'_> { - fn game(&self) -> &Session<'_> { - &self.game - } - } - - impl MockGame for AcyclicExampleGame<'_> { - fn game(&self) -> &Session<'_> { - &self.game - } - } - - impl MockGame for CyclicExampleGame<'_> { - fn game(&self) -> &Session<'_> { - &self.game - } - } - - /* TREE GAME UTILITY IMPLEMENTATIONS */ - - impl SimpleSum<2> for TreeExampleGame<'_> { - fn utility(&self, state: State) -> [SimpleUtility; 2] { - match self.game.node(state) { - Node::Terminal(vector) => [ - vector[0].try_into().unwrap(), - vector[1].try_into().unwrap(), - ], - Node::Medial(_) => { - panic!("Attempted to fetch utility of medial state.") - }, - } - } - } - } - - /// Contains examples of mock games where payoffs for terminal states always - /// sum to zero across all players. - pub mod zero_sum { - - use anyhow::Result; - - use crate::game::{mock::*, SimpleSum}; - use crate::model::SimpleUtility; - use crate::node; - - /* CONSTANTS */ - - const TREE_GAME_NAME: &str = "simple-utility-zero-sum-tree-structure"; - const ACYCLIC_GAME_NAME: &str = - "simple-utility-zero-sum-acyclic-structure"; - const CYCLIC_GAME_NAME: &str = - "simple-utility-zero-sum-cyclic-structure"; - - /* DEFINITIONS */ - - /// TODO - pub struct TreeExampleGame<'a> { - game: Session<'a>, - } - - /// TODO - pub struct AcyclicExampleGame<'a> { - game: Session<'a>, - } - - /// TODO - pub struct CyclicExampleGame<'a> { - game: Session<'a>, - } - - /* INSTANTIATION */ - - impl<'a> TreeExampleGame<'a> { - /// TODO - pub fn new( - store: &'a mut Vec, - ) -> Result> { - todo!() - } - - /// Creates a PNG image of the game being represented. - pub fn visualize(&self) -> Result<()> { - self.game - .visualize(super::super::MODULE_STORAGE) - } - } - - impl<'a> AcyclicExampleGame<'a> { - /// TODO - pub fn new( - store: &'a mut Vec, - ) -> Result> { - todo!() - } - - /// Creates a PNG image of the game being represented. - pub fn visualize(&self) -> Result<()> { - self.game - .visualize(super::super::MODULE_STORAGE) - } - } - - impl<'a> CyclicExampleGame<'a> { - /// TODO - pub fn new( - store: &'a mut Vec, - ) -> Result> { - todo!() - } - - /// Creates a PNG image of the game being represented. - pub fn visualize(&self) -> Result<()> { - self.game - .visualize(super::super::MODULE_STORAGE) - } - } - - /* TRAVERSAL IMPLEMENTATIONS */ - - impl MockGame for TreeExampleGame<'_> { - fn game(&self) -> &Session<'_> { - &self.game - } - } - - impl MockGame for AcyclicExampleGame<'_> { - fn game(&self) -> &Session<'_> { - &self.game - } - } - - impl MockGame for CyclicExampleGame<'_> { - fn game(&self) -> &Session<'_> { - &self.game - } - } - } -} - -/// Contains examples of mock games where utility can be expressed as an general -/// for players. -pub mod general_utility { - - /* CATEGORIES */ - - /// Contains examples of mock games where payoffs for terminal states can - /// sum to anything across all players. - pub mod general_sum { - - use anyhow::Result; - - use crate::game::{mock::*, SimpleSum}; - use crate::model::SimpleUtility; - use crate::node; - - /* CONSTANTS */ - - const TREE_GAME_NAME: &str = - "general-utility-general-sum-tree-structure"; - const ACYCLIC_GAME_NAME: &str = - "general-utility-general-sum-acyclic-structure"; - const CYCLIC_GAME_NAME: &str = - "general-utility-general-sum-cyclic-structure"; - - /* DEFINITIONS */ - - /// TODO - pub struct TreeExampleGame<'a> { - game: Session<'a>, - } - - /// TODO - pub struct AcyclicExampleGame<'a> { - game: Session<'a>, - } - - /// TODO - pub struct CyclicExampleGame<'a> { - game: Session<'a>, - } - - /* INSTANTIATION */ - - impl<'a> TreeExampleGame<'a> { - /// TODO - pub fn new( - store: &'a mut Vec, - ) -> Result> { - todo!() - } - - /// Creates a PNG image of the game being represented. - pub fn visualize(&self) -> Result<()> { - self.game - .visualize(super::super::MODULE_STORAGE) - } - } - - impl<'a> AcyclicExampleGame<'a> { - /// TODO - pub fn new( - store: &'a mut Vec, - ) -> Result> { - todo!() - } - - /// Creates a PNG image of the game being represented. - pub fn visualize(&self) -> Result<()> { - self.game - .visualize(super::super::MODULE_STORAGE) - } - } - - impl<'a> CyclicExampleGame<'a> { - /// TODO - pub fn new( - store: &'a mut Vec, - ) -> Result> { - todo!() - } - - /// Creates a PNG image of the game being represented. - pub fn visualize(&self) -> Result<()> { - self.game - .visualize(super::super::MODULE_STORAGE) - } - } - - /* TRAVERSAL IMPLEMENTATIONS */ - - impl MockGame for TreeExampleGame<'_> { - fn game(&self) -> &Session<'_> { - &self.game - } - } - - impl MockGame for AcyclicExampleGame<'_> { - fn game(&self) -> &Session<'_> { - &self.game - } - } - - impl MockGame for CyclicExampleGame<'_> { - fn game(&self) -> &Session<'_> { - &self.game - } - } - } - - /// Contains examples of mock games where payoffs for terminal states always - /// sum to zero across all players. - pub mod zero_sum { - - use anyhow::Result; - - use crate::game::{mock::*, SimpleSum}; - use crate::model::SimpleUtility; - use crate::node; - - /* CONSTANTS */ - - const TREE_GAME_NAME: &str = "general-utility-zero-sum-tree-structure"; - const ACYCLIC_GAME_NAME: &str = - "general-utility-zero-sum-acyclic-structure"; - const CYCLIC_GAME_NAME: &str = - "general-utility-zero-sum-cyclic-structure"; - - /* DEFINITIONS */ - - /// TODO - pub struct TreeExampleGame<'a> { - game: Session<'a>, - } - - /// TODO - pub struct AcyclicExampleGame<'a> { - game: Session<'a>, - } - - /// TODO - pub struct CyclicExampleGame<'a> { - game: Session<'a>, - } - - /* INSTANTIATION */ - - impl<'a> TreeExampleGame<'a> { - /// TODO - pub fn new( - store: &'a mut Vec, - ) -> Result> { - todo!() - } - - /// Creates a PNG image of the game being represented. - pub fn visualize(&self) -> Result<()> { - self.game - .visualize(super::super::MODULE_STORAGE) - } - } - - impl<'a> AcyclicExampleGame<'a> { - /// TODO - pub fn new( - store: &'a mut Vec, - ) -> Result> { - todo!() - } - - /// Creates a PNG image of the game being represented. - pub fn visualize(&self) -> Result<()> { - self.game - .visualize(super::super::MODULE_STORAGE) - } - } - - impl<'a> CyclicExampleGame<'a> { - /// TODO - pub fn new( - store: &'a mut Vec, - ) -> Result> { - todo!() - } - - /// Creates a PNG image of the game being represented. - pub fn visualize(&self) -> Result<()> { - self.game - .visualize(super::super::MODULE_STORAGE) - } - } - - /* TRAVERSAL IMPLEMENTATIONS */ - - impl MockGame for TreeExampleGame<'_> { - fn game(&self) -> &Session<'_> { - &self.game - } - } - - impl MockGame for AcyclicExampleGame<'_> { - fn game(&self) -> &Session<'_> { - &self.game - } - } - - impl MockGame for CyclicExampleGame<'_> { - fn game(&self) -> &Session<'_> { - &self.game - } - } - } -} - -mod tests { - - use anyhow::Result; - - use super::*; - - #[test] - fn initialize_simple_utility_general_sum() -> Result<()> { - let mut s = vec![]; - let _ = simple_utility::general_sum::TreeExampleGame::new(&mut s)?; - let _ = simple_utility::general_sum::AcyclicExampleGame::new(&mut s)?; - let _ = simple_utility::general_sum::CyclicExampleGame::new(&mut s)?; - Ok(()) - } - - #[test] - fn initialize_simple_utility_zero_sum() -> Result<()> { - let mut s = vec![]; - let _ = simple_utility::zero_sum::TreeExampleGame::new(&mut s)?; - let _ = simple_utility::zero_sum::AcyclicExampleGame::new(&mut s)?; - let _ = simple_utility::zero_sum::CyclicExampleGame::new(&mut s)?; - Ok(()) - } - - #[test] - fn initialize_general_utility_general_sum() -> Result<()> { - let mut s = vec![]; - let _ = general_utility::general_sum::TreeExampleGame::new(&mut s)?; - let _ = general_utility::general_sum::AcyclicExampleGame::new(&mut s)?; - let _ = general_utility::general_sum::CyclicExampleGame::new(&mut s)?; - Ok(()) - } - - #[test] - fn initialize_general_utility_zero_sum() -> Result<()> { - let mut s = vec![]; - let _ = general_utility::zero_sum::TreeExampleGame::new(&mut s)?; - let _ = general_utility::zero_sum::AcyclicExampleGame::new(&mut s)?; - let _ = general_utility::zero_sum::CyclicExampleGame::new(&mut s)?; - Ok(()) - } - - #[test] - fn visualize_all_example_games() -> Result<()> { - let mut s = vec![]; - let _ = simple_utility::general_sum::TreeExampleGame::new(&mut s)? - .visualize(); - let mut s = vec![]; - let _ = simple_utility::general_sum::AcyclicExampleGame::new(&mut s)? - .visualize(); - let mut s = vec![]; - let _ = simple_utility::general_sum::CyclicExampleGame::new(&mut s)? - .visualize(); - - let mut s = vec![]; - let _ = - simple_utility::zero_sum::TreeExampleGame::new(&mut s)?.visualize(); - let mut s = vec![]; - let _ = simple_utility::zero_sum::AcyclicExampleGame::new(&mut s)? - .visualize(); - let mut s = vec![]; - let _ = simple_utility::zero_sum::CyclicExampleGame::new(&mut s)? - .visualize(); - - let mut s = vec![]; - let _ = general_utility::general_sum::TreeExampleGame::new(&mut s)? - .visualize(); - let mut s = vec![]; - let _ = general_utility::general_sum::AcyclicExampleGame::new(&mut s)? - .visualize(); - let mut s = vec![]; - let _ = general_utility::general_sum::CyclicExampleGame::new(&mut s)? - .visualize(); - - let mut s = vec![]; - let _ = general_utility::zero_sum::TreeExampleGame::new(&mut s)? - .visualize(); - let mut s = vec![]; - let _ = general_utility::zero_sum::AcyclicExampleGame::new(&mut s)? - .visualize(); - let mut s = vec![]; - let _ = general_utility::zero_sum::CyclicExampleGame::new(&mut s)? - .visualize(); - - Ok(()) - } -} diff --git a/src/game/mock/example/general_utility/general_sum/mod.rs b/src/game/mock/example/general_utility/general_sum/mod.rs new file mode 100644 index 0000000..7cfd4e9 --- /dev/null +++ b/src/game/mock/example/general_utility/general_sum/mod.rs @@ -0,0 +1,139 @@ +//! # Example Game Module - General Utility General Sum [WIP] +//! +//! This module contains games of type tree, acyclic, and cyclic that +//! adhere to the following definitions: +//! General Utility - Player utilities are expressed numerically. +//! General Sum - Sum of all utilities is not necessarily zero. + +/* IMPORTS */ + +use crate::game::mock::example::{ + AcyclicExampleGame, CyclicExampleGame, TreeExampleGame, Visualizer, +}; +use crate::game::mock::{builder, Node}; +use crate::node; +use anyhow::Result; + +/* CONSTANTS */ + +const TREE_GAME_NAME: &str = "general-utility-general-sum-tree-structure"; +const ACYCLIC_GAME_NAME: &str = "general-utility-general-sum-acyclic-structure"; +const CYCLIC_GAME_NAME: &str = "general-utility-general-sum-cyclic-structure"; + +/* DEFINITIONS */ + +trait ExampleGame<'a>: Sized { + fn new(nodes: &'a mut Vec) -> Result; +} + +/* IMPLEMENTATIONS */ + +impl<'a> ExampleGame<'a> for TreeExampleGame<'a> { + fn new(store: &'a mut Vec) -> Result> { + let mut nodes = vec![ + node!(0), + node!(1), + node!(1), + node!(1), + node!(0), + node!(0), + node!(0), + node!(0), + node!(0), + node!(0), + node![-1, 1], + node![2, -3], + node![2, 1], + node![0, 0], + node![4, 5], + node![-1, -2], + node![-2, 2], + node![4, -5], + node![-1, 0], + ]; + + let length = store.len(); + store.append(&mut nodes); + let store = &store[length..]; + + let game = builder::SessionBuilder::new(&TREE_GAME_NAME) + .edge(&store[0], &store[1])? + .edge(&store[0], &store[2])? + .edge(&store[0], &store[3])? + .edge(&store[1], &store[4])? + .edge(&store[1], &store[5])? + .edge(&store[1], &store[6])? + .edge(&store[2], &store[7])? + .edge(&store[2], &store[8])? + .edge(&store[2], &store[9])? + .edge(&store[3], &store[10])? + .edge(&store[3], &store[11])? + .edge(&store[3], &store[12])? + .edge(&store[4], &store[13])? + .edge(&store[5], &store[14])? + .edge(&store[6], &store[15])? + .edge(&store[7], &store[16])? + .edge(&store[8], &store[17])? + .edge(&store[9], &store[18])? + .start(&store[0])? + .build()?; + + Ok(TreeExampleGame { game }) + } +} + +impl<'a> ExampleGame<'a> for AcyclicExampleGame<'a> { + fn new(store: &'a mut Vec) -> Result> { + todo!() + } +} + +impl<'a> ExampleGame<'a> for CyclicExampleGame<'a> { + fn new(store: &'a mut Vec) -> Result> { + todo!() + } +} + +/* TESTING */ + +#[cfg(test)] +mod tests { + use super::*; + use anyhow::Result; + + #[test] + fn initialize_example_tree_game() -> Result<()> { + let _ = TreeExampleGame::new(&mut vec![])?; + Ok(()) + } + + #[test] + fn initialize_example_acyclic_game() -> Result<()> { + let _ = AcyclicExampleGame::new(&mut vec![])?; + Ok(()) + } + + #[test] + fn initialize_example_cyclic_game() -> Result<()> { + let _ = CyclicExampleGame::new(&mut vec![])?; + Ok(()) + } + + #[test] + fn visualize_example_tree_game() -> Result<()> { + let _ = TreeExampleGame::new(&mut vec![])?.visualize(); + Ok(()) + } + + #[test] + fn visualize_example_acyclic_game() -> Result<()> { + let _ = AcyclicExampleGame::new(&mut vec![])?.visualize(); + Ok(()) + } + + #[test] + fn visualize_example_cyclic_game() -> Result<()> { + let _ = CyclicExampleGame::new(&mut vec![])?.visualize(); + Ok(()) + } +} diff --git a/src/game/mock/example/general_utility/mod.rs b/src/game/mock/example/general_utility/mod.rs new file mode 100644 index 0000000..aafbb72 --- /dev/null +++ b/src/game/mock/example/general_utility/mod.rs @@ -0,0 +1,10 @@ +//! # Example Game Module - General Utility [WIP] +//! +//! This module contains games of type tree, acyclic, and cyclic that +//! adhere to the following definitions: +//! General Utility - Player utilities are expressed numerically. + +/* SUBMODULES */ + +pub mod general_sum; +pub mod zero_sum; diff --git a/src/game/mock/example/general_utility/zero_sum/mod.rs b/src/game/mock/example/general_utility/zero_sum/mod.rs new file mode 100644 index 0000000..ad0d26e --- /dev/null +++ b/src/game/mock/example/general_utility/zero_sum/mod.rs @@ -0,0 +1,91 @@ +//! # Example Game Module - General Utility Zero Sum [WIP] +//! +//! This module contains games of type tree, acyclic, and cyclic that +//! adhere to the following definitions: +//! General Utility - Player utilities are expressed numerically. +//! Zero Sum - Sum of all utilities is zero. + +/* IMPORTS */ + +use crate::game::mock::example::{ + AcyclicExampleGame, CyclicExampleGame, TreeExampleGame, Visualizer, +}; +use crate::game::mock::{builder, Node}; +use crate::node; +use anyhow::Result; + +/* CONSTANTS */ + +const TREE_GAME_NAME: &str = "general-utility-zero-sum-tree-structure"; +const ACYCLIC_GAME_NAME: &str = "general-utility-zero-sum-acyclic-structure"; +const CYCLIC_GAME_NAME: &str = "general-utility-zero-sum-cyclic-structure"; + +/* DEFINITIONS */ + +trait ExampleGame<'a>: Sized { + fn new(nodes: &'a mut Vec) -> Result; +} + +/* IMPLEMENTATIONS */ + +impl<'a> ExampleGame<'a> for TreeExampleGame<'a> { + fn new(store: &'a mut Vec) -> Result> { + todo!() + } +} + +impl<'a> ExampleGame<'a> for AcyclicExampleGame<'a> { + fn new(store: &'a mut Vec) -> Result> { + todo!() + } +} + +impl<'a> ExampleGame<'a> for CyclicExampleGame<'a> { + fn new(store: &'a mut Vec) -> Result> { + todo!() + } +} + +/* TESTING */ + +#[cfg(test)] +mod tests { + use super::*; + use anyhow::Result; + + #[test] + fn initialize_example_tree_game() -> Result<()> { + let _ = TreeExampleGame::new(&mut vec![])?; + Ok(()) + } + + #[test] + fn initialize_example_acyclic_game() -> Result<()> { + let _ = AcyclicExampleGame::new(&mut vec![])?; + Ok(()) + } + + #[test] + fn initialize_example_cyclic_game() -> Result<()> { + let _ = CyclicExampleGame::new(&mut vec![])?; + Ok(()) + } + + #[test] + fn visualize_example_tree_game() -> Result<()> { + let _ = TreeExampleGame::new(&mut vec![])?.visualize(); + Ok(()) + } + + #[test] + fn visualize_example_acyclic_game() -> Result<()> { + let _ = AcyclicExampleGame::new(&mut vec![])?.visualize(); + Ok(()) + } + + #[test] + fn visualize_example_cyclic_game() -> Result<()> { + let _ = CyclicExampleGame::new(&mut vec![])?.visualize(); + Ok(()) + } +} diff --git a/src/game/mock/example/mod.rs b/src/game/mock/example/mod.rs new file mode 100644 index 0000000..13030d0 --- /dev/null +++ b/src/game/mock/example/mod.rs @@ -0,0 +1,77 @@ +//! # Example Mock Test Game Module [WIP] +//! +//! This module provides sub modules with concrete examples of small games that adhere +//! to useful interface definitions that can be used for testing purposes. The games here +//! are built over the `mock` game graph implementation. + +/* IMPORTS */ + +use crate::game::mock::{MockGame, Session}; +use anyhow::Result; + +/* CONSTANTS */ + +const MODULE_STORAGE: &str = "mock-game-examples"; + +/* SUBMODULES */ + +pub mod general_utility; +pub mod simple_utility; + +/* DEFINITIONS */ + +pub struct TreeExampleGame<'a> { + game: Session<'a>, +} + +pub struct AcyclicExampleGame<'a> { + game: Session<'a>, +} + +pub struct CyclicExampleGame<'a> { + game: Session<'a>, +} + +pub trait Visualizer { + fn visualize(&self) -> Result<()>; +} + +/* TRAVERSAL IMPLEMENTATIONS */ + +impl MockGame for TreeExampleGame<'_> { + fn game(&self) -> &Session<'_> { + &self.game + } +} + +impl MockGame for AcyclicExampleGame<'_> { + fn game(&self) -> &Session<'_> { + &self.game + } +} + +impl MockGame for CyclicExampleGame<'_> { + fn game(&self) -> &Session<'_> { + &self.game + } +} + +/* VISUALIZER IMPLEMENTATIONS */ + +impl Visualizer for TreeExampleGame<'_> { + fn visualize(&self) -> Result<()> { + self.game.visualize(MODULE_STORAGE) + } +} + +impl Visualizer for AcyclicExampleGame<'_> { + fn visualize(&self) -> Result<()> { + self.game.visualize(MODULE_STORAGE) + } +} + +impl Visualizer for CyclicExampleGame<'_> { + fn visualize(&self) -> Result<()> { + self.game.visualize(MODULE_STORAGE) + } +} diff --git a/src/game/mock/example/simple_utility/general_sum/mod.rs b/src/game/mock/example/simple_utility/general_sum/mod.rs new file mode 100644 index 0000000..349772b --- /dev/null +++ b/src/game/mock/example/simple_utility/general_sum/mod.rs @@ -0,0 +1,352 @@ +//! # Example Game Module - Simple Utility General Sum +//! +//! This module contains games of type tree, acyclic, and cyclic that +//! adhere to the following definitions: +//! Simple Utility - Player utilities are defined as WIN, LOSE, TIE, or DRAW. +//! General Sum - Sum of all utilities is not necessarily zero. + +/* IMPORTS */ + +use crate::game::mock::example::{ + AcyclicExampleGame, CyclicExampleGame, TreeExampleGame, Visualizer, +}; +use crate::game::mock::{builder, Node}; +use crate::game::{SimpleSum, SimpleUtility}; +use crate::model::State; +use crate::node; +use anyhow::Result; + +/* CONSTANTS */ + +const TREE_GAME_NAME: &str = "simple-utility-general-sum-tree-structure"; +const ACYCLIC_GAME_NAME: &str = "simple-utility-general-sum-acyclic-structure"; +const CYCLIC_GAME_NAME: &str = "simple-utility-general-sum-cyclic-structure"; + +/* DEFINITIONS */ + +trait ExampleGame<'a>: Sized { + fn new(nodes: &'a mut Vec) -> Result; +} + +/* IMPLEMENTATIONS */ + +impl<'a> ExampleGame<'a> for TreeExampleGame<'a> { + fn new(store: &'a mut Vec) -> Result> { + let mut nodes = vec![ + node!(0), + node!(1), + node!(1), + node!(1), + node!(0), + node!(0), + node!(0), + node!(0), + node!(0), + node!(0), + node![ + SimpleUtility::LOSE.into(), + SimpleUtility::WIN.into(), + ], + node![ + SimpleUtility::WIN.into(), + SimpleUtility::LOSE.into(), + ], + node![ + SimpleUtility::TIE.into(), + SimpleUtility::WIN.into(), + ], + node![ + SimpleUtility::TIE.into(), + SimpleUtility::TIE.into(), + ], + node![ + SimpleUtility::WIN.into(), + SimpleUtility::WIN.into(), + ], + node![ + SimpleUtility::LOSE.into(), + SimpleUtility::LOSE.into(), + ], + node![ + SimpleUtility::LOSE.into(), + SimpleUtility::WIN.into(), + ], + node![ + SimpleUtility::WIN.into(), + SimpleUtility::LOSE.into(), + ], + node![ + SimpleUtility::LOSE.into(), + SimpleUtility::TIE.into(), + ], + ]; + + let length = store.len(); + store.append(&mut nodes); + let store = &store[length..]; + + let game = builder::SessionBuilder::new(&TREE_GAME_NAME) + .edge(&store[0], &store[1])? + .edge(&store[0], &store[2])? + .edge(&store[0], &store[3])? + .edge(&store[1], &store[4])? + .edge(&store[1], &store[5])? + .edge(&store[1], &store[6])? + .edge(&store[2], &store[7])? + .edge(&store[2], &store[8])? + .edge(&store[2], &store[9])? + .edge(&store[3], &store[10])? + .edge(&store[3], &store[11])? + .edge(&store[3], &store[12])? + .edge(&store[4], &store[13])? + .edge(&store[5], &store[14])? + .edge(&store[6], &store[15])? + .edge(&store[7], &store[16])? + .edge(&store[8], &store[17])? + .edge(&store[9], &store[18])? + .start(&store[0])? + .build()?; + + Ok(TreeExampleGame { game }) + } +} + +impl<'a> ExampleGame<'a> for AcyclicExampleGame<'a> { + fn new(store: &'a mut Vec) -> Result> { + let mut nodes = vec![ + node!(0), + node!(1), + node!(0), + node!(1), + node!(0), + node!(1), + node!(0), + node!(1), + node!(0), + node!(1), + node!(0), + node!(1), + node!(0), + node!(1), + node!(0), + node!(1), + node!(0), + node!(1), + node![ + SimpleUtility::LOSE.into(), + SimpleUtility::WIN.into(), + ], + node![ + SimpleUtility::WIN.into(), + SimpleUtility::LOSE.into(), + ], + node![ + SimpleUtility::WIN.into(), + SimpleUtility::TIE.into(), + ], + node![ + SimpleUtility::WIN.into(), + SimpleUtility::TIE.into(), + ], + node![ + SimpleUtility::TIE.into(), + SimpleUtility::TIE.into(), + ], + node![ + SimpleUtility::WIN.into(), + SimpleUtility::WIN.into(), + ], + node![ + SimpleUtility::LOSE.into(), + SimpleUtility::LOSE.into(), + ], + ]; + + let length = store.len(); + store.append(&mut nodes); + let store = &store[length..]; + + let game = builder::SessionBuilder::new(&ACYCLIC_GAME_NAME) + .edge(&store[0], &store[1])? + .edge(&store[0], &store[3])? + .edge(&store[1], &store[2])? + .edge(&store[1], &store[4])? + .edge(&store[2], &store[5])? + .edge(&store[2], &store[7])? + .edge(&store[3], &store[4])? + .edge(&store[3], &store[6])? + .edge(&store[4], &store[7])? + .edge(&store[4], &store[9])? + .edge(&store[5], &store[6])? + .edge(&store[5], &store[8])? + .edge(&store[6], &store[9])? + .edge(&store[6], &store[11])? + .edge(&store[7], &store[8])? + .edge(&store[7], &store[10])? + .edge(&store[8], &store[11])? + .edge(&store[8], &store[13])? + .edge(&store[9], &store[10])? + .edge(&store[9], &store[12])? + .edge(&store[10], &store[13])? + .edge(&store[10], &store[15])? + .edge(&store[11], &store[12])? + .edge(&store[11], &store[14])? + .edge(&store[12], &store[15])? + .edge(&store[12], &store[17])? + .edge(&store[13], &store[14])? + .edge(&store[13], &store[16])? + .edge(&store[14], &store[17])? + .edge(&store[14], &store[19])? + .edge(&store[15], &store[16])? + .edge(&store[15], &store[18])? + .edge(&store[16], &store[19])? + .edge(&store[16], &store[20])? + .edge(&store[17], &store[21])? + .edge(&store[17], &store[22])? + .start(&store[0])? + .build()?; + + Ok(AcyclicExampleGame { game }) + } +} + +impl<'a> ExampleGame<'a> for CyclicExampleGame<'a> { + fn new(store: &'a mut Vec) -> Result> { + let mut nodes = vec![ + node!(0), + node!(1), + node!(0), + node!(1), + node!(0), + node!(1), + node!(0), + node!(1), + node!(0), + node!(1), + node!(0), + node![ + SimpleUtility::LOSE.into(), + SimpleUtility::LOSE.into(), + ], + node![ + SimpleUtility::WIN.into(), + SimpleUtility::LOSE.into(), + ], + node![ + SimpleUtility::TIE.into(), + SimpleUtility::WIN.into(), + ], + node![ + SimpleUtility::LOSE.into(), + SimpleUtility::WIN.into(), + ], + node![ + SimpleUtility::LOSE.into(), + SimpleUtility::LOSE.into(), + ], + node![ + SimpleUtility::WIN.into(), + SimpleUtility::LOSE.into(), + ], + node![ + SimpleUtility::TIE.into(), + SimpleUtility::WIN.into(), + ], + ]; + + let length = store.len(); + store.append(&mut nodes); + let store = &store[length..]; + + let game = builder::SessionBuilder::new(&CYCLIC_GAME_NAME) + .edge(&store[0], &store[1])? + .edge(&store[0], &store[3])? + .edge(&store[0], &store[5])? + .edge(&store[1], &store[8])? + .edge(&store[1], &store[10])? + .edge(&store[2], &store[1])? + .edge(&store[2], &store[3])? + .edge(&store[2], &store[5])? + .edge(&store[3], &store[2])? + .edge(&store[3], &store[4])? + .edge(&store[4], &store[5])? + .edge(&store[4], &store[7])? + .edge(&store[5], &store[6])? + .edge(&store[5], &store[8])? + .edge(&store[6], &store[7])? + .edge(&store[6], &store[9])? + .edge(&store[6], &store[16])? + .edge(&store[7], &store[11])? + .edge(&store[7], &store[12])? + .edge(&store[7], &store[4])? + .edge(&store[8], &store[9])? + .edge(&store[8], &store[14])? + .edge(&store[9], &store[13])? + .edge(&store[10], &store[15])? + .edge(&store[10], &store[13])? + .start(&store[0])? + .build()?; + + Ok(CyclicExampleGame { game }) + } +} + +/* TREE GAME UTILITY IMPLEMENTATIONS */ + +impl SimpleSum<2> for TreeExampleGame<'_> { + fn utility(&self, state: State) -> [SimpleUtility; 2] { + match self.game.node(state) { + Node::Terminal(vector) => [ + vector[0].try_into().unwrap(), + vector[1].try_into().unwrap(), + ], + Node::Medial(_) => { + panic!("Attempted to fetch utility of medial state.") + }, + } + } +} + +/* TESTING */ + +#[cfg(test)] +mod tests { + use super::*; + use anyhow::Result; + + #[test] + fn initialize_example_tree_game() -> Result<()> { + let _ = TreeExampleGame::new(&mut vec![])?; + Ok(()) + } + + #[test] + fn initialize_example_acyclic_game() -> Result<()> { + let _ = AcyclicExampleGame::new(&mut vec![])?; + Ok(()) + } + + #[test] + fn initialize_example_cyclic_game() -> Result<()> { + let _ = CyclicExampleGame::new(&mut vec![])?; + Ok(()) + } + + #[test] + fn visualize_example_tree_game() -> Result<()> { + let _ = TreeExampleGame::new(&mut vec![])?.visualize(); + Ok(()) + } + + #[test] + fn visualize_example_acyclic_game() -> Result<()> { + let _ = AcyclicExampleGame::new(&mut vec![])?.visualize(); + Ok(()) + } + + #[test] + fn visualize_example_cyclic_game() -> Result<()> { + let _ = CyclicExampleGame::new(&mut vec![])?.visualize(); + Ok(()) + } +} diff --git a/src/game/mock/example/simple_utility/mod.rs b/src/game/mock/example/simple_utility/mod.rs new file mode 100644 index 0000000..47cf218 --- /dev/null +++ b/src/game/mock/example/simple_utility/mod.rs @@ -0,0 +1,10 @@ +//! # Example Game Module - Simple Utility +//! +//! This module contains games of type tree, acyclic, and cyclic that +//! adhere to the following definitions: +//! Simple Utility - Player utilities are defined as WIN, LOSE, TIE, or DRAW. + +/* SUBMODULES */ + +pub mod general_sum; +pub mod zero_sum; diff --git a/src/game/mock/example/simple_utility/zero_sum/mod.rs b/src/game/mock/example/simple_utility/zero_sum/mod.rs new file mode 100644 index 0000000..6c56193 --- /dev/null +++ b/src/game/mock/example/simple_utility/zero_sum/mod.rs @@ -0,0 +1,286 @@ +//! # Example Game Module - Simple Utility Zero Sum +//! +//! This module contains games of type tree, acyclic, and cyclic that +//! adhere to the following definitions: +//! Simple Utility - Player utilities are defined as WIN, LOSE, TIE, or DRAW. +//! Zero Sum - Sum of all utilities is zero. + +/* IMPORTS */ + +use crate::game::mock::example::{ + AcyclicExampleGame, CyclicExampleGame, TreeExampleGame, Visualizer, +}; +use crate::game::mock::{builder, Node}; +use crate::game::SimpleUtility; +use crate::node; +use anyhow::Result; + +/* CONSTANTS */ + +const TREE_GAME_NAME: &str = "simple-utility-zero-sum-tree-structure"; +const ACYCLIC_GAME_NAME: &str = "simple-utility-zero-sum-acyclic-structure"; +const CYCLIC_GAME_NAME: &str = "simple-utility-zero-sum-cyclic-structure"; + +/* DEFINITIONS */ + +trait ExampleGame<'a>: Sized { + fn new(nodes: &'a mut Vec) -> Result; +} + +/* IMPLEMENTATIONS */ + +impl<'a> ExampleGame<'a> for TreeExampleGame<'a> { + fn new(store: &'a mut Vec) -> Result> { + let mut nodes = vec![ + node!(0), + node!(1), + node!(1), + node!(0), + node!(0), + node!(1), + node!(1), + node!(1), + node!(1), + node![ + SimpleUtility::LOSE.into(), + SimpleUtility::WIN.into(), + ], + node![ + SimpleUtility::WIN.into(), + SimpleUtility::LOSE.into(), + ], + node![ + SimpleUtility::LOSE.into(), + SimpleUtility::WIN.into(), + ], + node![ + SimpleUtility::TIE.into(), + SimpleUtility::TIE.into(), + ], + node![ + SimpleUtility::WIN.into(), + SimpleUtility::LOSE.into(), + ], + node![ + SimpleUtility::LOSE.into(), + SimpleUtility::WIN.into(), + ], + node![ + SimpleUtility::LOSE.into(), + SimpleUtility::WIN.into(), + ], + node![ + SimpleUtility::WIN.into(), + SimpleUtility::LOSE.into(), + ], + node![ + SimpleUtility::TIE.into(), + SimpleUtility::TIE.into(), + ], + node![ + SimpleUtility::TIE.into(), + SimpleUtility::TIE.into(), + ], + ]; + + let length = store.len(); + store.append(&mut nodes); + let store = &store[length..]; + + let game = builder::SessionBuilder::new(&TREE_GAME_NAME) + .edge(&store[0], &store[1])? + .edge(&store[0], &store[2])? + .edge(&store[1], &store[3])? + .edge(&store[1], &store[4])? + .edge(&store[2], &store[9])? + .edge(&store[2], &store[10])? + .edge(&store[3], &store[5])? + .edge(&store[3], &store[6])? + .edge(&store[4], &store[7])? + .edge(&store[4], &store[8])? + .edge(&store[5], &store[11])? + .edge(&store[5], &store[12])? + .edge(&store[6], &store[13])? + .edge(&store[6], &store[14])? + .edge(&store[7], &store[15])? + .edge(&store[7], &store[16])? + .edge(&store[8], &store[17])? + .edge(&store[8], &store[18])? + .start(&store[0])? + .build()?; + + Ok(TreeExampleGame { game }) + } +} + +impl<'a> ExampleGame<'a> for AcyclicExampleGame<'a> { + fn new(store: &'a mut Vec) -> Result> { + let mut nodes = vec![ + node!(0), + node!(1), + node!(1), + node!(1), + node!(0), + node!(0), + node!(0), + node!(0), + node!(0), + node![ + SimpleUtility::LOSE.into(), + SimpleUtility::WIN.into(), + ], + node![ + SimpleUtility::WIN.into(), + SimpleUtility::LOSE.into(), + ], + node![ + SimpleUtility::WIN.into(), + SimpleUtility::LOSE.into(), + ], + node![ + SimpleUtility::WIN.into(), + SimpleUtility::LOSE.into(), + ], + node![ + SimpleUtility::LOSE.into(), + SimpleUtility::WIN.into(), + ], + ]; + + let length = store.len(); + store.append(&mut nodes); + let store = &store[length..]; + + let game = builder::SessionBuilder::new(&ACYCLIC_GAME_NAME) + .edge(&store[0], &store[1])? + .edge(&store[0], &store[2])? + .edge(&store[0], &store[3])? + .edge(&store[1], &store[4])? + .edge(&store[1], &store[5])? + .edge(&store[2], &store[4])? + .edge(&store[2], &store[6])? + .edge(&store[3], &store[4])? + .edge(&store[3], &store[7])? + .edge(&store[3], &store[8])? + .edge(&store[4], &store[9])? + .edge(&store[4], &store[10])? + .edge(&store[5], &store[11])? + .edge(&store[5], &store[12])? + .edge(&store[6], &store[12])? + .edge(&store[6], &store[13])? + .edge(&store[7], &store[10])? + .edge(&store[8], &store[11])? + .start(&store[0])? + .build()?; + + Ok(AcyclicExampleGame { game }) + } +} + +impl<'a> ExampleGame<'a> for CyclicExampleGame<'a> { + fn new(store: &'a mut Vec) -> Result> { + let mut nodes = vec![ + node!(0), + node!(1), + node!(0), + node!(1), + node!(0), + node!(1), + node!(0), + node!(1), + node!(0), + node!(0), + node!(1), + node!(0), + node!(1), + node![ + SimpleUtility::LOSE.into(), + SimpleUtility::WIN.into(), + ], + node![ + SimpleUtility::WIN.into(), + SimpleUtility::LOSE.into(), + ], + ]; + + let length = store.len(); + store.append(&mut nodes); + let store = &store[length..]; + + let game = builder::SessionBuilder::new(&CYCLIC_GAME_NAME) + .edge(&store[0], &store[1])? + .edge(&store[0], &store[3])? + .edge(&store[1], &store[2])? + .edge(&store[1], &store[4])? + .edge(&store[2], &store[5])? + .edge(&store[2], &store[7])? + .edge(&store[3], &store[4])? + .edge(&store[3], &store[6])? + .edge(&store[4], &store[7])? + .edge(&store[4], &store[9])? + .edge(&store[5], &store[6])? + .edge(&store[5], &store[8])? + .edge(&store[6], &store[9])? + .edge(&store[6], &store[11])? + .edge(&store[7], &store[8])? + .edge(&store[7], &store[10])? + .edge(&store[8], &store[11])? + .edge(&store[8], &store[13])? + .edge(&store[9], &store[12])? + .edge(&store[9], &store[14])? + .edge(&store[10], &store[11])? + .edge(&store[10], &store[13])? + .edge(&store[11], &store[14])? + .edge(&store[11], &store[1])? + .edge(&store[12], &store[0])? + .edge(&store[12], &store[13])? + .start(&store[0])? + .build()?; + + Ok(CyclicExampleGame { game }) + } +} + +/* TESTING */ + +#[cfg(test)] +mod tests { + use super::*; + use anyhow::Result; + + #[test] + fn initialize_example_tree_game() -> Result<()> { + let _ = TreeExampleGame::new(&mut vec![])?; + Ok(()) + } + + #[test] + fn initialize_example_acyclic_game() -> Result<()> { + let _ = AcyclicExampleGame::new(&mut vec![])?; + Ok(()) + } + + #[test] + fn initialize_example_cyclic_game() -> Result<()> { + let _ = CyclicExampleGame::new(&mut vec![])?; + Ok(()) + } + + #[test] + fn visualize_example_tree_game() -> Result<()> { + let _ = TreeExampleGame::new(&mut vec![])?.visualize(); + Ok(()) + } + + #[test] + fn visualize_example_acyclic_game() -> Result<()> { + let _ = AcyclicExampleGame::new(&mut vec![])?.visualize(); + Ok(()) + } + + #[test] + fn visualize_example_cyclic_game() -> Result<()> { + let _ = CyclicExampleGame::new(&mut vec![])?.visualize(); + Ok(()) + } +} diff --git a/src/game/mock/mod.rs b/src/game/mock/mod.rs index 79c43a5..13608a4 100644 --- a/src/game/mock/mod.rs +++ b/src/game/mock/mod.rs @@ -188,6 +188,7 @@ where } } +#[cfg(test)] mod tests { use super::*;