Find a file
Felix Bauckholt 7ace892f40 Make better decisions between hinting and discarding
I think most of the gains of this change come from the fact
that now we don't discard any potentially useful cards if we have more
than 4 hints remaining.
2019-02-26 22:51:04 -08:00
src Make better decisions between hinting and discarding 2019-02-26 22:51:04 -08:00
.gitignore smart hinting, silencing/configuring of progress output 2016-04-02 13:51:18 -07:00
Cargo.lock compiled with new rustc 2018-03-24 09:36:25 -07:00
Cargo.toml add nthreads option, histogram 2016-03-17 23:10:38 -07:00
README.md Make better decisions between hinting and discarding 2019-02-26 22:51:04 -08:00

Simulations of Hanabi strategies

Hanabi is a cooperative card game of incomplete information. Despite relatively simple rules, the space of Hanabi strategies is quite interesting. This project provides a framework for implementing Hanabi strategies in Rust. It also explores some implementations, based on ideas from this paper. In particular, it contains an improved version of their "information strategy", which achieves the best results I'm aware of for games with more than 2 players (see below).

Please feel free to contact me about Hanabi strategies, or this framework.

Most similar projects I am aware of:

Setup

Install rust (rustc and cargo), and clone this git repo.

Then, in the repo root, run cargo run -- -h to see usage details.

For example, to simulate a 5 player game using the cheating strategy, for seeds 0-99:

cargo run -- -n 100 -s 0 -p 5 -g cheat

Or, if the simulation is slow, build with --release and use more threads:

time cargo run --release -- -n 10000 -o 1000 -s 0 -t 4 -p 5 -g info

Or, to see a transcript of the game with seed 222:

cargo run -- -s 222 -p 5 -g info -l debug | less

Strategies

To write a strategy, you simply implement a few traits.

The framework is designed to take advantage of Rust's ownership system so that you can't cheat, without using stuff like Cell or Arc or Mutex.

Generally, your strategy will be passed something of type &BorrowedGameView. This game view contains many useful helper functions (see here). If you want to mutate a view, you'll want to do something like let mut self.view = OwnedGameView::clone_from(borrowed_view);. An OwnedGameView will have the same API as a borrowed one.

Some examples:

Results

On seeds 0-9999, we have these average scores and win rates:

2p 3p 4p 5p
cheat 24.8600 24.9781 24.9715 24.9570
90.52 % 98.12 % 97.74 % 96.57 %
info 21.9455 24.7136 24.8868 24.8976
07.01 % 79.46 % 91.26 % 91.91 %

To reproduce:

n=10000   # number of rounds to simulate
t=4       # number of threads
for strategy in info cheat; do
  for p in $(seq 2 5); do
    time cargo run --release -- -n $n -s 0 -t $t -p $p -g $strategy;
  done
done