Imports


In [0]:
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import sys
assert sys.version_info.major == 3
import os

add_paths = True
if add_paths:
  sys.path.insert(0, os.path.join(os.path.abspath(os.getcwd()), '..', '..'))
  sys.path.insert(
      0,
      os.path.join(os.path.abspath(os.getcwd()), '..', '..', 'build', 'python'))
  import pyspiel


from open_spiel.python.algorithms import cfr
from open_spiel.python.algorithms import exploitability
from open_spiel.python.algorithms import expected_game_score
from open_spiel.python.bots import uniform_random
from open_spiel.python.visualizations import treeviz

In [0]:
games_list = pyspiel.registered_names()

print("Registered games:")
print(games_list)

game = pyspiel.load_game("universal_poker")

In [0]:
"""Test that Python and C++ bots can be called by a C++ algorithm."""

from absl.testing import absltest
import numpy as np

from open_spiel.python.bots import uniform_random

game = pyspiel.load_game("leduc_poker")
bots = [
    pyspiel.make_uniform_random_bot(0, 1234),
    uniform_random.UniformRandomBot(1, np.random.RandomState(4321)),
]
results = np.array([
    pyspiel.evaluate_bots(game.new_initial_state(), bots, iteration)
    for iteration in range(10000)
])
leduc_average_results = np.mean(results, axis=0)
print(leduc_average_results)

game = pyspiel.load_game("universal_poker")
bots = [
    pyspiel.make_uniform_random_bot(0, 1234),
    uniform_random.UniformRandomBot(1, np.random.RandomState(4321)),
]
results = np.array([
    pyspiel.evaluate_bots(game.new_initial_state(), bots, iteration)
    for iteration in range(10000)
])
universal_poker_average_results = np.mean(results, axis=0)
print(universal_poker_average_results)

#np.testing.assert_allclose(universal_poker_average_results, leduc_average_results, atol=0.1)

In [0]:
universal_poker_kuhn_limit_3p = """\
GAMEDEF
limit
numPlayers = 3
numRounds = 1
blind = 1 1 1
raiseSize = 1
firstPlayer = 1
maxRaises = 1
numSuits = 1
numRanks = 4
numHoleCards = 1
numBoardCards = 0
END GAMEDEF
"""

game = pyspiel.load_game(
    "universal_poker",
    {"gamedef": pyspiel.GameParameter(universal_poker_kuhn_limit_3p)})
str(game)

In [0]:
# Compare exloitability for two games
players = 2
iterations = 10
print_freq = 1

def compare_exploitability(game_1, game_2):
  cfr_solver_1 = cfr.CFRSolver(game_1)
  cfr_solver_2 = cfr.CFRSolver(game_2)
  for i in range(iterations):
    cfr_solver_1.evaluate_and_update_policy()
    cfr_solver_2.evaluate_and_update_policy()
    if i % print_freq == 0:
      conv_1 = exploitability.exploitability(game_1,
                                             cfr_solver_1.average_policy())
      conv_2 = exploitability.exploitability(game_2,
                                             cfr_solver_2.average_policy())

      print("Iteration {} exploitability of the  {} vs: {}".format(
          i, conv_1, conv_2))

  print("Final exploitability is {} vs {}".format(conv_1, conv_2))


game_1 = pyspiel.load_game("kuhn_poker",
                           {"players": pyspiel.GameParameter(2)})

universal_poker_kuhn_limit_2p = """\
GAMEDEF
limit
numPlayers = 2
numRounds = 1
blind = 1 1
raiseSize = 1
firstPlayer = 1
maxRaises = 1
numSuits = 1
numRanks = 3
numHoleCards = 1
numBoardCards = 0
END GAMEDEF
"""
game_2 = pyspiel.load_game(
    "universal_poker",
    {"gamedef": pyspiel.GameParameter(universal_poker_kuhn_limit_2p)})
compare_exploitability(game_1, game_2)

In [0]:
game_1 = pyspiel.load_game("leduc_poker",
                           {"players": pyspiel.GameParameter(2)})
# Taken verbatim from the linked paper above: "In Leduc hold'em, the deck
# consists of two suits with three cards in each suit. There are two rounds.
# In the first round a single private card is dealt to each player. In the
# second round a single board card is revealed. There is a two-bet maximum,
# with raise amounts of 2 and 4 in the first and second round, respectively.
# Both players start the first round with 1 already in the pot.

universal_poker_leduc_limit_2p = """\
GAMEDEF
limit
numPlayers = 2
numRounds = 2
blind = 1 1
raiseSize = 1 1
firstPlayer = 1 1
maxRaises = 2 2
raiseSize = 2 4
numSuits = 2
numRanks = 3
numHoleCards = 1 0
numBoardCards = 0 1
END GAMEDEF
"""
game_2 = pyspiel.load_game(
    "universal_poker",
    {"gamedef": pyspiel.GameParameter(universal_poker_leduc_limit_2p)})
compare_exploitability(game_1, game_2)

In [0]:
game = "universal_poker"
out = "/tmp/gametree.png"
prog = "dot"
group_infosets = False
group_terminal = False
verbose = False


def _zero_sum_node_decorator(state):
  """Custom node decorator that only shows the return of the first player."""
  attrs = treeviz.default_node_decorator(state)  # get default attributes
  if state.is_terminal():
    attrs["label"] = str(int(state.returns()[0]))
  return attrs


game = pyspiel.load_game(
    game, {"gamedef": pyspiel.GameParameter(universal_poker_kuhn_limit_2p)})
game_type = game.get_type()

if game_type.dynamics != pyspiel.GameType.Dynamics.SEQUENTIAL:
  raise ValueError("Game must be sequential, not {}".format(game_type.dynamics))

if (game_type.utility == pyspiel.GameType.Utility.ZERO_SUM and
    game.num_players() == 2):
  gametree = treeviz.GameTree(
      game,
      node_decorator=_zero_sum_node_decorator,
      group_infosets=group_infosets,
      group_terminal=group_terminal)
else:
  gametree = treeviz.GameTree(game)  # use default decorators

if verbose:
  logging.info("Game tree:\n%s", gametree.to_string())

gametree.draw(out, prog=prog)

In [0]: