diff --git a/src/game/mock/example.rs b/src/game/mock/example.rs deleted file mode 100644 index 076fca4..0000000 --- a/src/game/mock/example.rs +++ /dev/null @@ -1,8 +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 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 0ad08e0..13608a4 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,13 +172,16 @@ 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, }