1

I have a game tree with an arbitrary number of possible moves for me and my opponent with an arbitrary sequence of moves. I want to get an overview of all 'sets of moves I can make' and corresponding info. In this example I narrowed my problem down. Each move I can choose max 2 moves ('1' or '2'). And my opponent can choose max 2 moves ('a' or 'b'). In this example there are 5 possible 'sets of moves I can make'. How do I produce this outcome in a way that it will work with a larger game tree as well?

input = {'1': {'a': {'1': {'a': 'some_info_1'},
                     '2': {'a': 'some_info_2'}},                          
               'b': {'1': {'a': {'1': {'a': 'some_info_3'},
                                 '2': {'a': 'some_info_4'}}
                          }
                    },
              },
         '2': {'a': 'some_info_5'}
        }


output = {
    1: {'1': {'a': {'1': {'a': 'some_info_1'}},                          
              'b': {'1': {'a': {'1': {'a': 'some_info_3'}}}}}},
    2: {'1': {'a': {'2': {'a': 'some_info_2'}},                          
              'b': {'1': {'a': {'1': {'a': 'some_info_3'}}}}}},
    3: {'1': {'a': {'1': {'a': 'some_info_1'}},                          
              'b': {'1': {'a': {'2': {'a': 'some_info_4'}}}}}},                  
    4: {'1': {'a': {'2': {'a': 'some_info_2'}},                          
              'b': {'1': {'a': {'2': {'a': 'some_info_4'}}}}}},
    5: {'2': {'a': 'some_info_5'}}
}

I searched for the answer on this and other sites. This thread comes close: Combination of nested dictionaries with arbitrary lengths in python

I also tried for loops, itertools and cartesian products. But I can't get it to work. It's really frustrating. I hope someone can help.

Hackaholic
  • 19,069
  • 5
  • 54
  • 72

1 Answers1

0

I'm confused how you're grouping your output sets, especially output[2] and output[4], but it looks like you want to implement some form of depth first search and then do grouping based on the moves:

class state_node():

    def __init__(self, states, move, prev_moves = []):
        self.states = states
        self.prev_moves = prev_moves
        self.move = move
        
    def generate_next_moves(self):
        current_state = self.states
        
        for move in self.prev_moves:
            current_state = current_state[move]
            
        next_states = current_state[self.move]
        
        if isinstance(next_states, dict):
            return [state_node(self.states, next_move, self.prev_moves + [self.move]) for next_move in next_states]
        
        else:
            return None
        
    def __repr__(self):
        all_moves = self.prev_moves + [self.move]
        
        output_str = '['
        
        for move in all_moves:
            output_str += f"'{move}', "
            
        output_str = output_str[0:-2] + ']'
        
        return output_str
    
    def __eq__(self, other):
        
        return self.prev_moves == other.prev_moves and self.move == other.move

class state_tree():
    
    def __init__(self, states):
        
        self.states = states
        
        self.visited = []
        
        self.end_nodes = []
        
    def depth_first_search(self):
        
        self.unvisited = [state_node(self.states, move) for move in self.states if state_node(self.states, move) not in self.visited]
        
        while len(self.unvisited) > 0:
            target_node = self.unvisited.pop(-1)
            
            self.visited += [target_node]
            
            next_nodes = target_node.generate_next_moves()
            
            if next_nodes is None:
                self.end_nodes += [target_node]
            
            else:
                self.unvisited += next_nodes
    
            
tree = state_tree(states)

tree.depth_first_search()

print(tree.end_nodes)
Michael Cao
  • 2,278
  • 1
  • 1
  • 13
  • Thank you for your answer. The code doesn't run because of the unknown variable states. So I can't check if this provide the wanted output. To expand on the grouping of my output set: The form of my output doesn't matter much. I want an overview of possible outcomes of the game based on my choice of moves. – Shikamaru_NL Jan 17 '23 at 07:59
  • Ah, sorry I renamed your variable "input" to "states" since input is a keyword. – Michael Cao Jan 17 '23 at 16:01
  • ok. This gives output: [['2', 'a'], ['1', 'b', '1b1', 'a', '1b1a2', 'a'], ['1', 'b', '1b1', 'a', '1b1a1', 'a'], ['1', 'a', '1a2', 'a'], ['1', 'a', '1a1', 'a']] This is a list of all endpoints. What I want is a list of a list of all possible endpoints after my moves. Output 1 is: Always playing '1' will give endpoints 1 and 3. – Shikamaru_NL Jan 18 '23 at 08:32