Example #1
0
 def __repr__(self):
     child_actions = [child.action.to_action() for child in self.children]
     return "GameTreeNode(street=%r, board=%r, actor=%r, action='%s', "  \
         "betting_line=%r, child_actions=%r, ranges_by_userid=%r, "  \
         "total_contrib=%r, winners=%r, final_pot=%r)" %  \
         (self.street, self.board, self.actor, self.action,
          line_description(self.betting_line),
          child_actions, self.ranges_by_userid, self.total_contrib,
          self.winners, self.final_pot)
Example #2
0
def display_game_tree(tree, local=False):
    """
    Display every node of tree.
    """
    for node in tree.children:
        display_game_tree(node, local)
    for userid in tree.ranges_by_userid:
        ev_map = {}
        for combo, equity in tree.all_combos_ev(userid, local).items():
            lower_card, higher_card = sorted(combo)
            desc = higher_card.to_mnemonic() + lower_card.to_mnemonic()
            ev_map[desc] = "%0.04f" % (equity,)
        print "Line '%s', userid %d:" %  \
            (line_description(tree.betting_line), userid), ev_map
Example #3
0
    def calculate_combo_ev(self, combo, userid):
        """
        Calculate EV for a combo at this point in the game tree.
        """
        if self.children:
            # intermediate node, EV is combination of children's
            # oh, each child needs a weight / probability
            # oh, it's combo specific... "it depends" ;)

            # EV of combo is:
            # weighted sum of EV of children, but only for children where the
            # combo is present (where combo isn't present, probability is zero)

            # to assess probability:
            # - if this node's children are performed by this user:
            #   - EV is the EV of the action that contains this combo
            # - otherwise:
            #   - remove combo from the children's actor's current range
            #   - consider how many combo's of children's actor's current range
            #     proceed to each child
            #   - voila
            # This conveniently works even in a multi-way pot. It's a very good
            # approximation of the true probabilities. And note that truly
            # calculating the true probabilities is not possible.
            actor = self.children[0].actor
            if actor == userid:
                # EV is the EV of the action that contains this combo
                for node in self.children:
                    if range_contains_hand(node.ranges_by_userid[userid],
                                           combo):
                        return node.combo_ev(combo, userid)
                raise InvalidComboForTree('Combo not in child ranges for userid'
                    ' %d at betting line %s.' %
                    (userid, line_description(self.betting_line)))
            else:
                # probabilistic weighting of child EVs
                # size of bucket is probability of this child
                valid_children = [child for child in self.children
                    if range_contains_hand(child.ranges_by_userid[userid],
                                           combo)]
                buckets = {child: child.ranges_by_userid[actor]  \
                    .generate_options(Card.many_from_text(child.board) +
                                      list(combo))
                    for child in valid_children}
                total = len(concatenate(buckets.values()))
                if total == 0:
                    raise InvalidComboForTree('Combo not in child ranges for'
                        ' userid %d at betting line %s. ' % (userid,
                        line_description(self.betting_line)))
                probabilities = {child: 1.0 * len(buckets[child]) / total
                                 for child in valid_children}
                ev = sum(probabilities[child] * child.combo_ev(combo, userid)
                    for child in valid_children)
                return ev
                # Invalid combos are ignored / not calculated or aggregated.
        elif userid not in self.winners:
            # they folded
            return 0.0 - self.total_contrib[userid]
        elif len(self.winners) == 1:
            # uncontested pot
            return 0.0 + self.final_pot - self.total_contrib[userid]
        else:
            # showdown
            ranges = {userid: range_
                      for userid, range_ in self.ranges_by_userid.items()}
            combos = set([combo])
            description = unweighted_options_to_description(combos)
            ranges[userid] = HandRange(description)
            equities, _iteration =  \
                showdown_equity(ranges, Card.many_from_text(self.board),
                    hard_limit=10000)  # TODO: 1: this is not good enough
            equity = equities[userid]
            return equity * self.final_pot - self.total_contrib[userid]