(self, node)
return json_table
Tree print format for this field is (note, in each state only one player acts): 
        pi_p(a1, h1) pi_p(a2, h1) ... pi_p(an, h1) ... || pi_p(a1, h2) pi_p(a2, h2) ... pi_p(an, h2) || ...
Tree print format for this field is (note, in each state only one player acts): 
        pi_p(a1, h1) pi_p(a2, h1) ... pi_p(an, h1) ... || pi_p(a1, h2) pi_p(a2, h2) ... pi_p(an, h2) || ...
Tree print format for this field is ( note in each state only one player acts ) : pi_p ( a1 h1 ) pi_p ( a2 h1 ) ... pi_p ( an h1 ) ... || pi_p ( a1 h2 ) pi_p ( a2 h2 ) ... pi_p ( an h2 ) || ...
def _export_for_node_strategy_tree(self, node):

        def _2darr_to_str(arr):
            _str = ""
            if arr is None:
                return "Not Computed"

            for i in range(arr.shape[0]):
                for j in range(arr.shape[1]):
                    _str += str("{:10.4f}".format(arr[i, j])) + " "
                if i < arr.shape[0] - 1:
                    _str += " || "

            return _str

        if node.parent is None:
            title = "ROOT"
        elif isinstance(node, ChanceNode):
            title = self._env.cards2str(cards_2d=node.env_state[EnvDictIdxs.board_2d])
        else:
            title = "Player acted last " + str(node.p_id_acted_last) + " :: Action: " + self._get_action_as_str(
                node.action) + " :: Board: " + self._env.cards2str(cards_2d=node.env_state[EnvDictIdxs.board_2d])

        """
        Tree print format for this field is (note, in each state only one player acts): 
        pi_p(a1, h1) pi_p(a2, h1) ... pi_p(an, h1) ... || pi_p(a1, h2) pi_p(a2, h2) ... pi_p(an, h2) || ...
        """
        strat_str = _2darr_to_str(node.strategy)

        """
        Tree print format for this field is: 
        reach(p1, h1) reach(p1, h2) ... reach(p1, hn) || reach(p2, h1) reach(p2, h2) ... reach(p2, hn)
        """
        reach_probs_str = _2darr_to_str(node.reach_probs)

        """
        Tree print format for this field is: 
        ev(p1, h1) ev(p1, h2) ... ev(p1, hn) || ev(p2, h1) ev(p2, h2) ... ev(p2, hn)
        """
        ev_str = _2darr_to_str(node.ev)

        """
        Tree print format for this field is: 
        ev_br(p1, h1) ev_br(p1, h2) ... ev_br(p1, hn) || ev_br(p2, h1) ev_br(p2, h2) ... ev_br(p2, hn)
        """
        ev_br_str = _2darr_to_str(node.ev_br)

        if isinstance(node, np.ndarray) and len(node.shape) == 2:
            """ Since the data field is general, it is impossible to know how/what to format. The code below is capable
                of processing 2d numpy arrays. For anything else, we will set an empty string. """
            data_str = _2darr_to_str(node.data)
        else:
            data_str = ""

        json_table = {
            'text': {
                # for header
                'title': title,
                'round': "Round : " + Poker.INT2STRING_ROUND[node.env_state[EnvDictIdxs.current_round]],

                # for body
                'main_pot': "Pot : " + json.dumps(int(node.env_state[EnvDictIdxs.main_pot])),

                'terminal': ("TERM" if str(node.is_terminal) else "") + " " + str(node.allowed_actions),

                'side_pots': "SP: " + json.dumps(
                    [int(i) for i in node.env_state[EnvDictIdxs.side_pots]]),

                'stack_sizes': "Stacks: " + json.dumps(
                    [int(s[PlayerDictIdxs.stack]) for s in node.env_state[EnvDictIdxs.seats]]),

                'current_bets': "Bets: " + json.dumps(
                    [int(s[PlayerDictIdxs.current_bet]) for s in node.env_state[EnvDictIdxs.seats]]),

                'not_folded': "Playing: " + json.dumps(
                    [not s[PlayerDictIdxs.folded_this_episode] for s in node.env_state[EnvDictIdxs.seats]]).replace(
                    "true", "1").replace("false", "0") + "  Next: " + str(node.p_id_acting_next),

                "exploitability": "Exploitability: " + (str(
                    node.exploitability) if node.exploitability is not None else "Exploitability not computed")
                                  + "   ||   BR Action per hand "
                                  + ("" if node.br_a_idx_in_child_arr_for_each_hand is None else
                                     str([self._get_action_as_str(a)
                                          for a in
                                          np.array(node.allowed_actions)[node.br_a_idx_in_child_arr_for_each_hand]])),

                'strategy': "STRAT: " + strat_str,

                'reach_probs': "REACH: " + reach_probs_str,

                'ev': "EV: " + ev_str,

                'ev_br': "EV-BR: " + ev_br_str,

                'data': "DATA: " + data_str
            },

            # tree nodes are all collapsed by default
            'collapsed': True,

            'children': []
        }

        # recurse over all children
        for child in node.children:
            json_table['children'].append(self._export_for_node_strategy_tree(child))

        return json_table
def _export_for_node_strategy_tree ( self , node ) : def _2darr_to_str ( arr ) : _str = "" if arr is None : return "Not Computed" for i in range ( arr . shape [ 0 ] ) : for j in range ( arr . shape [ 1 ] ) : _str += str ( "{:10.4f}" . format ( arr [ i , j ] ) ) + " " if i < arr . shape [ 0 ] - 1 : _str += " || " return _str if node . parent is None : title = "ROOT" elif isinstance ( node , ChanceNode ) : title = self . _env . cards2str ( cards_2d = node . env_state [ EnvDictIdxs . board_2d ] ) else : title = "Player acted last " + str ( node . p_id_acted_last ) + " :: Action: " + self . _get_action_as_str ( node . action ) + " :: Board: " + self . _env . cards2str ( cards_2d = node . env_state [ EnvDictIdxs . board_2d ] ) strat_str = _2darr_to_str ( node . strategy ) """
        Tree print format for this field is: 
        reach(p1, h1) reach(p1, h2) ... reach(p1, hn) || reach(p2, h1) reach(p2, h2) ... reach(p2, hn)
        """ reach_probs_str = _2darr_to_str ( node . reach_probs ) """
        Tree print format for this field is: 
        ev(p1, h1) ev(p1, h2) ... ev(p1, hn) || ev(p2, h1) ev(p2, h2) ... ev(p2, hn)
        """ ev_str = _2darr_to_str ( node . ev ) """
        Tree print format for this field is: 
        ev_br(p1, h1) ev_br(p1, h2) ... ev_br(p1, hn) || ev_br(p2, h1) ev_br(p2, h2) ... ev_br(p2, hn)
        """ ev_br_str = _2darr_to_str ( node . ev_br ) if isinstance ( node , np . ndarray ) and len ( node . shape ) == 2 : """ Since the data field is general, it is impossible to know how/what to format. The code below is capable
                of processing 2d numpy arrays. For anything else, we will set an empty string. """ data_str = _2darr_to_str ( node . data ) else : data_str = "" json_table = { 'text' : { # for header 'title' : title , 'round' : "Round : " + Poker . INT2STRING_ROUND [ node . env_state [ EnvDictIdxs . current_round ] ] , # for body 'main_pot' : "Pot : " + json . dumps ( int ( node . env_state [ EnvDictIdxs . main_pot ] ) ) , 'terminal' : ( "TERM" if str ( node . is_terminal ) else "" ) + " " + str ( node . allowed_actions ) , 'side_pots' : "SP: " + json . dumps ( [ int ( i ) for i in node . env_state [ EnvDictIdxs . side_pots ] ] ) , 'stack_sizes' : "Stacks: " + json . dumps ( [ int ( s [ PlayerDictIdxs . stack ] ) for s in node . env_state [ EnvDictIdxs . seats ] ] ) , 'current_bets' : "Bets: " + json . dumps ( [ int ( s [ PlayerDictIdxs . current_bet ] ) for s in node . env_state [ EnvDictIdxs . seats ] ] ) , 'not_folded' : "Playing: " + json . dumps ( [ not s [ PlayerDictIdxs . folded_this_episode ] for s in node . env_state [ EnvDictIdxs . seats ] ] ) . replace ( "true" , "1" ) . replace ( "false" , "0" ) + "  Next: " + str ( node . p_id_acting_next ) , "exploitability" : "Exploitability: " + ( str ( node . exploitability ) if node . exploitability is not None else "Exploitability not computed" ) + "   ||   BR Action per hand " + ( "" if node . br_a_idx_in_child_arr_for_each_hand is None else str ( [ self . _get_action_as_str ( a ) for a in np . array ( node . allowed_actions ) [ node . br_a_idx_in_child_arr_for_each_hand ] ] ) ) , 'strategy' : "STRAT: " + strat_str , 'reach_probs' : "REACH: " + reach_probs_str , 'ev' : "EV: " + ev_str , 'ev_br' : "EV-BR: " + ev_br_str , 'data' : "DATA: " + data_str } , # tree nodes are all collapsed by default 'collapsed' : True , 'children' : [ ] } # recurse over all children for child in node . children : json_table [ 'children' ] . append ( self . _export_for_node_strategy_tree ( child ) ) return json_table