hanabi.rs/README.md
Felix Bauckholt 493631dad0 Refactor out a "public information object"
One important change is that now, when deciding which questions to ask, they can see the answer to the last question before asking the next one.

Some design choices:
- Questions now take a BoardState instead of an OwnedGameView.
- When deciding which questions to ask (in ask_questions), we get an immutable public information object
  (representing the public information before any questions were asked), and a mutable HandInfo<CardPossibilityTable>
  that gets updated as we ask questions. That HandInfo<CardPossibilityTable> was copied instead of taken.
- In ask_questions, we also get some &mut u32 representing "info_remaining" that gets updated for us.
  This will later allow for cases where "info_remaining" depends on the answers to previous questions.
- Both get_hint_sum and update_from_hint_sum change the public information object. If you want to compute the
  hint sum but aren't sure if you actually want to give the hint, you'll have to clone the public information
  object!
- Over time, in the code to decide on a move, we'll be able to build an increasingly complicated tree of
  "public information object operations" that will have to be matched exactly in the code to update on a move.
  In order to make this less scary, I moved most of the code into
  "decide_wrapped" and "update_wrapped". If the call to update_wrapped
  (for the player who just made the move) changes the public information
  object in different ways than the previous call to decide_wrapped, we
  detect this and panic.

This commit should be purely refactoring; all changes to win-rates are
due to bugs.
2019-03-07 22:04:06 +01:00

2.7 KiB

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 (auto-generated)

To reproduce:

time cargo run --release -- --results-table

To update this file:

time cargo run --release -- --write-results-table

On the first 20000 seeds, we have these average scores and win rates:

2p 3p 4p 5p
cheat 24.8594 24.9785 24.9720 24.9557
90.59 % 98.17 % 97.76 % 96.42 %
info 22.2908 24.7171 24.8875 24.8957
09.40 % 79.94 % 91.32 % 91.83 %