PyToe является крупной системой, для знакомства с которой предполагается наличие некоторой подготовки в области ИИ, но в отношении графического интерфейса, в сущности, не демонстрирует ничего ново-
![]() |
|
Рис. 11.27. Альтернативный вариант настройки
го. Кроме того, она была написана для выполнения под управлением Python 2.X более десяти лет тому назад, и хотя она и была перенесена на Python 3.X для этого издания, некоторые ее части было бы лучше реализовать заново. Отчасти по этой причине, но в основном из-за того, что я уже исчерпал объем страниц, отведенных на эту главу, я не привожу здесь исходный программный код, а отсылаю вас к пакету с примерами. За деталями реализации PyToe обращайтесь к следующим двум файлам из пакета примеров:
PP4E\Ai\TicTacToe\tictactoe.py
Сценарий оболочки верхнего уровня
PP4E\Ai\TicTacToe\tictactoe_lists.py
Основная реализация
Если вы решитесь заглянуть в эти сценарии, могу посоветовать обратить внимание на структуру данных, используемую для представления состояния игрового поля, которая составляет наибольшую сложность. Если вы разберетесь, каким образом моделируется игровое поле, то остальная часть реализации станет вполне понятна.
Например, в варианте, основанном на списках, для представления состояния игрового поля используется список списков, а также простой словарь из виджетов полей ввода для графического интерфейса, индексируемый координатами игрового поля. Очистка игрового поля после игры заключается в простой очистке исходных структур данных, как показано в следующем фрагменте программного кода из указанных выше примеров:
def clearBoard(self):
for row, col in self.label.keys(): self.board[row][col] = Empty self.label[(row, col)].config(text=’ ‘)
Аналогично выбор хода, по крайней мере, в случайном режиме, заключается в том, чтобы найти пустую ячейку в массиве, представляющем игровое поле, и записать метку компьютера в нее и передать в графический интерфейс (атрибут degree хранит размер игрового поля):
def machineMove(self):
row, col = self.pickMove()
self.board[row][col] = self.machineMark
self.label[(row, col)].config(text=self.machineMark)
def pickMove(self): empties = [] for row in self.degree: for col in self.degree:
if self.board[row][col] == Empty: empties.append((row, col)) return random.choice(empties)
Наконец, проверка состояния конца игры сводится к просмотру строк, колонок и диагоналей по следующей схеме:
def checkDraw(self, board=None): board = board or self.board for row in board:
if Empty in row: return 0 return 1 # не пусто: ничья или победа
def checkWin(self, mark, board=None): board = board or self.board for row in board:
if row.count(mark) == self.degree: # проверка горизонтали return 1
for col in range(self.degree):
for row in board: # проверка вертикали
if row[col] != mark: break
else: return 1 for row in range(self.degree): # проверка первой диагонали
col = row # row == col
if board[row][col] != mark: break else:
return 1
for row in range(self.degree):
col = (self.degree-1) — row
if board[row][col] != mark: break else:
return 1
def checkFinish(self):
if self.checkWin(self.userMark):
outcome = “You’ve won!”
elif self.checkWin(self.machineMark):
outcome = ‘I win again :-)’
elif self.checkDraw():
outcome = ‘Looks like a draw’
Другой программный код, связанный с выбором хода, в основном просто проводит другие виды анализа структуры данных игрового поля или генерирует новые состояния для поиска в дереве ходов и контрхо- дов.
В том же каталоге находятся родственные файлы, реализующие альтернативные схемы поиска и оценки ходов, различные представления игрового поля и так далее. За дополнительными сведениями об оценке ходов в игре и о поиске в целом обращайтесь к учебникам по ИИ. Это интересный материал, но слишком сложный, чтобы его можно было достаточным образом осветить в данной книге.
Использованная литература:
Марк Лутц — Программирование на Python, 4-е издание, I том, 2011