For a University project I am trying to follow a script I have access to which supposedly creates the game tree structure for two player Kuhn Poker - written using Python's class structure.
When run it comes across problems with the children and parents properties of its decision nodes, and I can't grasp how the code is progressing step by step. I believe this code has been based off the pycfr github library, "pokertrees" script. The error message states the list index is out of range for the children list called under the tree_structure function for each child. I can't follow when it is writing to this list, and feel this may be missing from this 'simplified version' of the pycfr code "pokertrees", available on github. I am inexperienced using parent/children system of moving from node to node, especially in python, using the node classes and the self.root instantiated with the tree.
Can anybody clear this up for me? I have spent days poring over the code and feel knowledgeable opinions will be able to spot the problem.
The code can be run in the shell as follows:
First define specifications.
Call "specs = specifications(deck ,size_of_bet, maximum_allowed_bet, ante)"
e.g. "specs = specifications([A,K,Q] ,1, 1, 1)"
Next create game tree.
Call "tree = tree(specs)"
Next, run start_game_and_deal_card.
Call "tree.start_game_and_deal_card()
Here is the relevant piece of code:
Code:
import random
from copy import deepcopy
from itertools import permutations
from itertools import combinations
J=11
Q=12
K=13
A=14
class specifications(object):
def __init__(self, deck, size_of_bet, maximum_allowed_bet, ante):
self.deck = deck
self.ante = ante
self.size_of_bet = size_of_bet
self.maximum_allowed_bet = maximum_allowed_bet
class tree(object):
def __init__(self, specifications):
self.specifications = deepcopy(specifications)
self.info = []
self.root = None
def start_game_and_deal_card(self):
in_the_pot = [True] * 2
players_contribution = [self.specifications.ante] * 2
acting_player = 0
bets = [0] * 2
minimum_moves = in_the_pot.count(True)
moves = 0
game_so_far = ""
possible_cards = permutations(combinations(self.specifications.deck,1),2)
for cards in possible_cards:
dealt_cards = ()
cards = list(cards)
for i,card in enumerate(cards):
if in_the_pot[i]:
cards[i] = card + cards[i]
for card in cards:
dealt_cards += card
deal = deal_cards_node(node, players_contribution, player_cards, self.specifications.deck, "")
self.tree_structure(deal, acting_player, in_the_pot, players_contribution, cards, self.specifications.deck, game_so_far, minimum_moves, moves, bets)
return deal
def tree_structure(self, node, acting_player, in_the_pot, players_contribution, player_cards, deck, game_so_far, minimum_moves, moves, bets):
if in_the_pot.count(True) ==1:
self.showdown(node, in_the_pot, players_contribution, player_cards, self.specifications.deck, game_so_far)
return
if moves>=minimum_moves and bets[node.player]==betlevel:
self.showdown(node, in_the_pot, players_contribution, player_cards, self.specifications.deck, game_so_far)
return
decision = decision_node(node, players_contribution, player_cards, self.specifications.deck, game_so_far, acting_player)
# update information set
self.info.append(decision.player)
acting_player = (acting_player + 1) % 2
# fold child
if players_contribution[decision.player] < max(players_contribution):
game_so_far += 'f'
in_the_pot[decision.player] = False
self.tree_structure(node, acting_player, in_the_pot, players_contribution, player_cards, deck, game_so_far, minimum_moves, moves + 1,bets)
in_the_pot[decision.player] = True
node.fold_decision = node.children[-1]
# raise child
if self.specifications.maximum_allowed_bet > max(bets):
game_so_far += 'r'
players_contribution[decision.player]=players_contribution[decision.player]+1
bets[decision.player]=bets[decision.player]+1
self.tree_structure(node, acting_player, in_the_pot, players_contribution, player_cards, deck, game_so_far, minimum_moves, moves + 1, bets)
node.raise_decision = node.children[-1]
# call child
game_so_far =+ 'c'
players_contribution[node.player]=players_contribution[(node.player+1)%2]
bets[node.player]=bets[(node.player+1)%2]
self.tree_structure(node, acting_player, in_the_pot, players_contribution, player_cards, deck, game_so_far, minimum_moves, moves + 1, bets)
node.call_decision = node.children[-1]
return decision
def showdown(self, node, in_the_pot, players_contribution, player_cards, deck, game_so_far):
if in_the_pot.count(True) == 1:
winners = in_the_pot
else:
winners = []
if player_cards[0] > player_cards[1]:
winners.append(0)
if player_cards[0] < player_cards[1]:
winners.append(1)
total = sum(players_contribution)
payoffs = winners.extend([total])
return terminal_node(node, players_contribution, player_cards, deck, game_so_far, payoffs, in_the_pot)
class node(object):
def __init__(self, parent, players_contribution, player_cards, deck, game_so_far):
self.deck = deepcopy(deck)
self.players_contribution = deepcopy(players_contribution)
self.player_cards = deepcopy(player_cards)
self.parent = parent
class terminal_node(node):
def __init__(self, parent, players_contribution, player_cards, deck, game_so_far, payoffs, in_the_pot):
node.__init__(self, parent, players_contribution, player_cards, deck, game_so_far)
self.children = []
class deal_cards_node(node):
def __init__(self, parent, players_contribution, player_cards, deck, game_so_far):
node.__init__(self, parent, players_contribution, player_cards, deck, game_so_far)
self.children = []
class decision_node(node):
def __init__(self, parent, players_contribution, player_cards, deck, game_so_far, player):
node.__init__(self, parent, players_contribution, player_cards, deck, game_so_far)
self.player = player
self.children = []
self.raise_decision = None
self.call_decision = None
self.fold_decision = None