Hello! There is a task to generate a full tree for N-dimensional noughts and crosses. While this problem solves this code:

class GameTree: evaled = 0 # ΠΊΠΎΠ»-Π²ΠΎ просчитанных Π»ΠΈΡΡ‚ΡŒΠ΅Π² def __init__(self, players, points, cp=0, level=0): # players - list(list(list(int))) - список ΠΈΠ³Ρ€ΠΎΠΊΠΎΠ², # ΠΊΠ°ΠΆΠ΄Ρ‹ΠΉ ΠΈΠ³Ρ€ΠΎΠΊ - список Π΅Π³ΠΎ Ρ…ΠΎΠ΄ΠΎΠ², # ΠΊΠ°ΠΆΠ΄Ρ‹ΠΉ Ρ…ΠΎΠ΄ - список Π΅Π³ΠΎ ΠΊΠΎΠΎΡ€Π΄ΠΈΠ½Π°Ρ‚ # points - list(list(int)) - список Ρ…ΠΎΠ΄ΠΎΠ², # ΠΊΠ°ΠΆΠ΄Ρ‹ΠΉ Ρ…ΠΎΠ΄ - список Π΅Π³ΠΎ ΠΊΠΎΠΎΡ€Π΄ΠΈΠ½Π°Ρ‚ # cp - int - индСкс ΠΈΠ³Ρ€ΠΎΠΊΠ°, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ сСйчас Ρ…ΠΎΠ΄ΠΈΡ‚ # level - int - Π½ΠΎΠΌΠ΅Ρ€ Ρ…ΠΎΠ΄Π° Π² ΠΏΠ°Ρ€Ρ‚ΠΈΠΈ (ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ для Π²Ρ‹Π²ΠΎΠ΄Π°) GameTree.evaled += 1 players = slist(deepcopy(players)) # Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π½Π΅ Π΄Π°Ρ‚ΡŒ ΠΈΠ·ΠΌΠ΅Π½ΡΡ‚ΡŒ исходный список points = slist(deepcopy(points)) if cp == len(players): # Ссли сходил послСдний cp = 0 self.children = [] for i in players: # Ссли ΠΊΡ‚ΠΎ-Ρ‚ΠΎ ΡƒΠΆΠ΅ Π²Ρ‹ΠΈΠ³Ρ€Π°Π» if won(i): self.children = None return if points == []: # Ссли Π½Π΅Ρ‚ Ρ…ΠΎΠ΄ΠΎΠ² self.children = None return me = players[cp] enemies = players.without(players[cp]) if len(me)>=2: # Ссли ΡƒΠΆΠ΅ ΠΌΠΎΠΆΠ½ΠΎ Π²Ρ‹ΠΈΠ³Ρ€Π°Ρ‚ΡŒ for i in points: me_ = me + [i] if won(me_): # Ссли ΠΌΠΎΠΆΠ½ΠΎ Π²Ρ‹ΠΈΠ³Ρ€Π°Ρ‚ΡŒ, сдСлав Ρ…ΠΎΠ΄ i players[cp].append(i) self.children = GameTree(n, players, points.without(i), cp+1, level=level+1) # Π½ΡƒΠΆΠ½ΠΎ ΡΠΎΠ²Π΅Ρ€ΡˆΠΈΡ‚ΡŒ Ρ…ΠΎΠ΄ i return blocked = False for i in points: for en in enemies: en_ = en + [i] if won(en_): # Ссли ΠΊΡ‚ΠΎ-Ρ‚ΠΎ ΠΈΠ· ΠΏΡ€ΠΎΡ‚ΠΈΠ²Π½ΠΈΠΊΠΎΠ² ΠΌΠΎΠΆΠ΅Ρ‚ Π²Ρ‹ΠΈΠ³Ρ€Π°Ρ‚ΡŒ, ΡΠΎΠ²Π΅Ρ€ΡˆΠΈΠ² Ρ…ΠΎΠ΄ i buff = deepcopy(players) players[cp].append(i) self.children.append(GameTree(players, points.without(i), cp+1, level=level+1)) # Π½ΡƒΠΆΠ½ΠΎ ΠΏΠΎΠΏΡ€ΠΎΠ±ΠΎΠ²Π°Ρ‚ΡŒ Π΅ΠΌΡƒ ΠΏΠΎΠΌΠ΅ΡˆΠ°Ρ‚ΡŒ players = buff blocked = True if blocked: # Ссли ΠΊΡ‚ΠΎ-Ρ‚ΠΎ ΠΌΠΎΠ³ Π²Ρ‹ΠΈΠ³Ρ€Π°Ρ‚ΡŒ return for i in points: # для ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΠ³ΠΎ Ρ…ΠΎΠ΄Π° buff = deepcopy(players) players[cp].append(i) self.children.append(GameTree(n, players, points.without(i), cp+1, level=level+1)) # ΠΏΠΎΠΏΡ€ΠΎΠ±ΠΎΠ²Π°Ρ‚ΡŒ, Ρ‡Ρ‚ΠΎ получится players = buff 

And everything seems to be fine, but for three dimensions and two players, a tree is generated indecently long. But, since it is possible to come to the same state of the field in many different ways, now the tree looks like in fig. 1. It would be great to turn it into rice. 2. (sorry, I can't explain it with words) enter image description here

For this was born such a monster:

 if str(players) in list(GameTree.nodes.keys()): # Ссли Π΅ΡΡ‚ΡŒ Π² ΡƒΠΆΠ΅ рассчитанных Π»ΠΈΡΡ‚ΡŒΡΡ…, Π΅ΡΡ‚ΡŒ Ρ‚Π°ΠΊΠΎΠ΅ состояниС поля self.children.append(GameTree.node[players]) # 'ΡΠΎΠ΅Π΄ΠΈΠ½ΠΈΡ‚ΡŒ' Π΅Π³ΠΎ с Ρ‚Π΅ΠΊΡƒΡ‰ΠΈΠΌ return else: new = GameTree(players, points.without(i), cp+1, level=level+1) # Ρ€Π°ΡΡΡ‡ΠΈΡ‚Π°Ρ‚ΡŒ GameTree.nodes[str(players)] = new # Π·Π°ΠΏΠΎΠΌΠ½ΠΈΡ‚ΡŒ self.children.append(new) 

With it, the code takes the form:

 class GameTree: evaled = 0 nodes = {} def __init__(self, players, points, cp=0, level=0): GameTree.evaled += 1 players = slist(deepcopy(players)) points = slist(deepcopy(points)) if cp == len(players): cp = 0 self.children = [] for i in players: if won(i): self.children = None return if points == []: self.children = None return me = players[cp] enemies = players.without(players[cp]) if len(me)>=2: for i in points: me_ = me + [i] if won(me_): players[cp].append(i) if str(players) in list(GameTree.nodes.keys()): self.children.append(GameTree.node[players]) else: new = GameTree(players, points.without(i), cp+1, level=level+1) GameTree.nodes[str(players)] = new self.children.append(new) return blocked = False for i in points: for en in enemies: en_ = en + [i] if won(en_): buff = deepcopy(players) players[cp].append(i) if str(players) in list(GameTree.nodes.keys()): self.children.append(GameTree.node[players]) return else: new = GameTree(players, points.without(i), cp+1, level=level+1) GameTree.nodes[str(players)] = new self.children.append(new) players = buff blocked = True if blocked: return for i in points: buff = deepcopy(players) players[cp].append(i) if str(players) in list(GameTree.nodes.keys()): self.children.append(GameTree.node[str(players)]) return else: new = GameTree(players, points.without(i), cp+1, level=level+1) GameTree.nodes[str(players)] = new self.children.append(new) players = buff 

Not only is the code terrible, it still does not work. Could you help me? Here is the whole code, if you need it (there are still a lot of ugly places, if someone tells you how to improve it in terms of style (and maybe even performance), I will be very grateful):

 from copy import deepcopy from time import time from threading import Thread from math import factorial point_class = lambda a: a.count(0) class slist(list): def without(self, x): b = self[:] b.remove(x) return b def to_ter_arr(i): if i<3: return [i] return to_ter_arr(i // 3) + [i%3] def gen(n): ret = slist() for i in range(pow(3, n)): buff = to_ter_arr(i) buff = [0]*(n-len(buff))+buff buff = list(map(lambda a: a-1, buff)) ret.append(buff) return ret def three(a, b, c): if a == [] or b == [] or c== []: return False for i in range(len(a)): s = [a[i], b[i], c[i]] if not s in [[1,1,1], [-1,-1,-1], [0,0,0], [1,0,-1], [-1,0,1]]: return False return True and a!=b and a!=c and b!=c def won(pl): for a in pl: for b in pl: for c in pl: if three(a, b, c): return True return False def output(s): f.write(s+'\n') class GameTree: evaled = 0 def __init__(self, players, points, cp=0, level=0): GameTree.evaled += 1 players = slist(deepcopy(players)) points = slist(deepcopy(points)) if cp == len(players): cp = 0 self.children = [] for i in players: if won(i): output('{}{} won {}'.format(' '*level, level, players.index(i))) self.children = None return if points == []: output('{}{} draw'.format(' '*level, level, 'draw')) self.children = None return me = players[cp] enemies = players.without(players[cp]) if len(me)>=2: for i in points: me_ = me + [i] if won(me_): players[cp].append(i) output('{}{} {} {} next - win'.format(' '*level, level, cp, i)) self.children = GameTree(players, points.without(i), cp+1, level=level+1) return blocked = False for i in points: for en in enemies: en_ = en + [i] if won(en_): buff = deepcopy(players) players[cp].append(i) output('{}{} {} {} blocking {}'.format(' '*level, level, cp, i, players.index(en))) self.children.append(GameTree(players, points.without(i), cp+1, level=level+1)) players = buff blocked = True if blocked: return for i in points: buff = deepcopy(players) players[cp].append(i) output('{}{} {} {} try'.format(' '*level, level, cp, i)) self.children.append(GameTree(players, points.without(i), cp+1, level=level+1)) players = buff def progress(): global aprox, game, start while game.is_alive(): print('\r{} / {}, {} s'.format(GameTree.evaled, aprox, time()-start), end='') n = int(input('N = ')) points = gen(n) aprox = factorial(len(points)) pc = int(input('ΠšΠΎΠ»ΠΈΡ‡Π΅ΡΡ‚Π²ΠΎ ΠΈΠ³Ρ€ΠΎΠΊΠΎΠ²: ')) center = slist([0 for i in range(n)]) players = slist([[center]]+[[] for i in range(pc-1)]) file_name = input('Имя Ρ„Π°ΠΉΠ»Π°: ') f = open(file_name, 'w') show = input('ΠŸΠΎΠΊΠ°Π·Ρ‹Π²Π°Ρ‚ΡŒ прогрСсс (Π”\Н, Π” ΠΏΠΎ ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ)') if show == 'H' or show == 'Π½': show = False elif show == 'Π”' or show == 'Π΄' or show == '': show = True else: print('Ошибка!!!') exit(1) print('\nCenter =', center) print('Players =', players) print('Points =', points) print('Aproximate number of leaves:', aprox) start = time() output('0 0 [0, 0] root') game = Thread(target = GameTree, kwargs = {'players': players, 'points': points.without(center), 'cp': 1, 'level': 1}) prog = Thread(target = progress) game.start() if show: prog.start() else: game.join() print(time()-start, 's') 

    0