Другой вариант: создать таблицу с кодом. До симметрии, есть только три способа выиграть: крайний ряд, средний ряд или диагональ. Возьми эти три и разверни их всеми возможными способами:
def spin(g): return set([g, turn(g), turn(turn(g)), turn(turn(turn(g)))])
def turn(g): return tuple(tuple(g[y][x] for y in (0,1,2)) for x in (2,1,0))
X,s = 'X.'
XXX = X, X, X
sss = s, s, s
ways_to_win = ( spin((XXX, sss, sss))
| spin((sss, XXX, sss))
| spin(((X,s,s),
(s,X,s),
(s,s,X))))
Эти симметрии могут найти более широкое применение в игровом коде: если вы попадаете на доску, на которой вы уже видели повернутую версию, вы можете просто взять кэшированное значение или лучший кэшированный ход из этого (и развернуть его назад). Это обычно намного быстрее, чем оценка игрового поддерева.
(Переключение влево и вправо может помочь одинаково; здесь это не нужно, поскольку набор поворотов выигрышных комбинаций зеркально симметричен.)