Game

Struct Game 

Source
pub struct Game<Infoset, Action> { /* private fields */ }
Expand description

A compact game representation

This structure allows computing approximate equilibria, and evaluating the regret and utility of strategy profiles.

Implementations§

Source§

impl<I: Hash + Eq, A: Hash + Eq> Game<I, A>

Source

pub fn from_root<T>(root: T) -> Result<Self, GameError>
where T: IntoGameNode<PlayerInfo = I, Action = A>, T::ChanceInfo: Hash + Eq,

Create a game from the root node of an arbitrary game tree

For more information on how to create a game, see the necessary trait IntoGameNode for details on how to structure the input data.

Examples found in repository?
examples/kuhn_poker.rs (line 120)
119fn create_kuhn(num_cards: usize) -> Game<(usize, bool), Action> {
120    Game::from_root(create_kuhn_one(num_cards)).unwrap()
121}
Source§

impl<I, A> Game<I, A>

Source

pub fn solve( &self, method: SolveMethod, max_iter: u64, max_reg: f64, num_threads: usize, params: Option<RegretParams>, ) -> Result<(Strategies<'_, I, A>, RegretBound), SolveError>

Find an approximate Nash equilibrium of the current game

Often you’ll either want to run with max_iter as usize::MAX and max_reg as a meaningful regret, or max_iter as a number set based off of the time you have and max_reg set to 0.0, although setting both as a tradeoff also reasonable.

§Arguments
  • method - The method of solving to use. When in doubt prefer External. See SolveMethod for details on the distinctions.
  • max_iter - The maximum number of iterations to run. The maximum regret of the found strategy is bounded by the square-root of the number of iterations.
  • max_reg - Terminate early if the regret of the returned strategy is going to be less than this value. With this current implementation this is only valid when the method is Full and the params are vanilla. If using other parameters, this should be set lower than the desired regret.
  • num_threads - The number of threads to use for solving. Zero selects based off of thread::available_parallelism. One uses a single threaded variant that’s more efficient when not in a threaded environment.
  • param - Advanced parameters that govern the behavior of the regret and strategy updates. See RegretParams for more details, or set to None to use the default.
§Errors

If num_threads is too large, and this tries to spawn too many threads, or if there are problems spawning threads. This will not error when num_threads is 1.

Examples found in repository?
examples/kuhn_poker.rs (lines 176-182)
172fn main() {
173    let args = Args::parse();
174    let game = create_kuhn(args.num_cards);
175    let (mut strats, _) = game
176        .solve(
177            SolveMethod::External,
178            args.iterations,
179            0.0,
180            args.parallel,
181            None,
182        )
183        .unwrap();
184    strats.truncate(5e-3); // not visible
185    let [player_one_strat, player_two_strat] = strats.as_named();
186    println!("Player One");
187    println!("==========");
188    let mut init = Vec::with_capacity(3);
189    let mut raised = Vec::with_capacity(3);
190    for (&(card, raise), actions) in player_one_strat {
191        if raise { &mut raised } else { &mut init }.push((card, actions));
192    }
193    println!("Initial Action");
194    println!("--------------");
195    print_card_strat(init, args.num_cards);
196    println!("If Player Two Raised");
197    println!("--------------------");
198    print_card_strat(raised, args.num_cards);
199    println!("Player Two");
200    println!("==========");
201    let mut called = Vec::with_capacity(3);
202    let mut raised = Vec::with_capacity(3);
203    for (&(card, raise), actions) in player_two_strat {
204        if raise { &mut raised } else { &mut called }.push((card, actions));
205    }
206    println!("If Player One Called");
207    println!("--------------------");
208    print_card_strat(called, args.num_cards);
209    println!("If Player One Raised");
210    println!("--------------------");
211    print_card_strat(raised, args.num_cards);
212}
Source

pub fn num_infosets(&self) -> usize

The total number of information sets for each player

Source§

impl<I: Hash + Eq + Clone, A: Hash + Eq + Clone> Game<I, A>

Source

pub fn from_named( &self, strats: [impl IntoIterator<Item = (impl Borrow<I>, impl IntoIterator<Item = (impl Borrow<A>, impl Borrow<f64>)>)>; 2], ) -> Result<Strategies<'_, I, A>, StratError>

Convert a named strategy into Strategies

The input can be any set of types that vaguelly iterates over pairs of information sets and then actions paired to weights. Weights can be any non-negative f64, which will be normalized in the final strategy. There are no restrictions on iteration order.

§Example
use std::collections::HashMap;

let game = // ...
let one: HashMap<&'static str, HashMap<&'static str, f64>> = [
    ("info", [("A", 0.2), ("B", 0.8)].into())
].into();
let two: HashMap<&'static str, HashMap<&'static str, f64>> = [
    ("info", [("1", 0.5), ("2", 0.5)].into())
].into();
let strat = game.from_named([one, two]).unwrap();
let info = strat.get_info();
info.regret();
§Errors

This will error if a valid strategy wasn’t specified for every infoset, or it received invalid infosets or actions for the current Game.

Source§

impl<I: Eq, A: Eq> Game<I, A>

Source

pub fn from_named_eq( &self, strats: [impl IntoIterator<Item = (impl Borrow<I>, impl IntoIterator<Item = (impl Borrow<A>, impl Borrow<f64>)>)>; 2], ) -> Result<Strategies<'_, I, A>, StratError>

Convert a named strategy into Strategies

In case cloning is very expensive, this version doesn’t require cloning or hashing, but otherwise runs in time quadratic in the number of infosets and actions, which is almost certaintly going to be worse than the cost of cloning.

Also note that currently constructing the Game requires hashing so that relaxation is meaningless.

This is otherwise the same as Game::from_named, so see that method for examples.

Trait Implementations§

Source§

impl<Infoset: Debug, Action: Debug> Debug for Game<Infoset, Action>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<I, A> PartialEq for Game<I, A>

Two games are equal if and only if they are the same game

Source§

fn eq(&self, other: &Self) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl<I, A> Eq for Game<I, A>

Auto Trait Implementations§

§

impl<Infoset, Action> Freeze for Game<Infoset, Action>

§

impl<Infoset, Action> RefUnwindSafe for Game<Infoset, Action>
where Infoset: RefUnwindSafe, Action: RefUnwindSafe,

§

impl<Infoset, Action> Send for Game<Infoset, Action>
where Infoset: Send, Action: Send,

§

impl<Infoset, Action> Sync for Game<Infoset, Action>
where Infoset: Sync, Action: Sync,

§

impl<Infoset, Action> Unpin for Game<Infoset, Action>

§

impl<Infoset, Action> UnwindSafe for Game<Infoset, Action>
where Infoset: UnwindSafe, Action: UnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<Q, K> Equivalent<K> for Q
where Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,

Source§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
Source§

impl<Q, K> Equivalent<K> for Q
where Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,

Source§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V