Главная страница

Учим Python, делая крутые игры 2018. Invent your owncomputer gameswith python


Скачать 6.56 Mb.
НазваниеInvent your owncomputer gameswith python
Дата10.12.2022
Размер6.56 Mb.
Формат файлаpdf
Имя файлаУчим Python, делая крутые игры 2018.pdf
ТипДокументы
#837554
страница29 из 39
1   ...   25   26   27   28   29   30   31   32   ...   39
297
239. print('Приветствуем в игре "Реверси"!')
240.
241. playerTile, computerTile = enterPlayerTile()
Программа начинается с приветствия игрока в строке 239 и предложения выбрать X или O. В строке 241 используется множественное присваивание, чтобы установить переменные playerTile и computerTile равными двум значе- ниям, которые возвращаются enterPlayerTile().
Цикл while в строке 243 проводит каждую игру.
243. while True:
244. finalBoard = playGame(playerTile, computerTile)
245.
246. # Отобразить итоговый счет.
247. drawBoard(finalBoard)
248. scores = getScoreOfBoard(finalBoard)
249. print('X набрал %s очков. O набрал %s очков.' % (scores['Х'], scores['О']))
250. if scores[playerTile] > scores[computerTile]:
251. print('Вы победили компьютер, обогнав его на %s очков! Поздравления!' %
(scores[playerTile] - scores[computerTile]))
252. elif scores[playerTile] < scores[computerTile]:
253. print('Вы проиграли. Компьютер победил вас, обогнав на %s очков.' %
(scores[computerTile] - scores[playerTile]))
254. else:
255. print('Ничья!')
Он начинается с вызова playGame(). Этот вызов не вернется, пока игра не будет окончена. Структура данных поля, возвращаемая функцией playGame(), будет передана функции getScoreOfBoard() для подсчета фишек X и O и опре- деления итогового результата. Код в строке 249 отображает этот результат.
Если фишек игрока на доске больше, чем фишек компьютера, код в строке
251 поздравляет игрока с победой. Если победил компьютер, код в строке 253 сообщает игроку, что он проиграл. В противном случае код в строке 255 со- общает игроку, что игра завершилась вничью.
Предложение сыграть снова
После окончания игры появляется запрос, хочет ли пользователь сыграть снова.

257. print('Хотите сыграть еще раз? (да или нет)')
258. if not input().lower().startswith('д'):
259. break
Если игрок не вводит ответ, начинающийся с буквы д, например, да или
ДА
, либо Д, тогда условие в строке 258 принимает значение True, а код в строке
259 прерывает цикл while, который начался в строке 243, что приводит к за- вершению игры. В противном случае этот цикл while запускается как обычно, и снова вызывается функция playGame(), чтобы начать следующую игру.
Заключение
Искусственный интеллект игры «Реверси» может показаться практиче- ски непобедимым. Это не потому, что компьютер умнее, чем мы, просто он намного быстрее! Стратегия, которой он следует, проста: если можете, делай- те ход в угол, а в противном случае делайте ход, который перевернет больше всего фишек. Человек мог бы это сделать, но на выяснение того, сколько фи- шек будет перевернуто каждым допустимым ходом, ушло бы много времени.
Для компьютера же такие расчеты не представляют труда.
Эта игра похожа на программу «Охотник за сокровищами», потому что использует сетку для игрового поля. Она также напоминает игру «Крестики- нолики», потому что здесь есть ИИ, планирующий лучший для компьютера ход. В этой главе вы изучили новые понятия: пустые списки, пустые строки, а также целое число 0, принимающие значение False в контексте условия. Не считая этого, в данной игре использовались только уже знакомые вам методы программирования!
В главе 16 вы узнаете, как заставить искусственные интеллекты играть в компьютерные игры друг против друга.

Искусственный интеллект игры «Реверси»
299
16
ИСКУССТВЕННЫЙ ИНТЕЛЛЕКТ
ИГРЫ «РЕВЕРСИ»
Алгоритм ИИ игры «Реверси» из гла- вы 15 прост, но он побеждает автора почти в каждой игре. Поскольку ком- пьютер способен быстро обрабатывать инструкции, он может легко проверить каждую возможную позицию на игровом поле и выбрать ход, который принесет больше всего оч- ков. Если бы автор пытался отыскать лучший ход таким способом, это отняло бы уйму времени.
Программа «Реверси» содержала две функции, getPlayerMove() и getComputerMove(), которые возвращали выбранный ход как двухэлемент- ный список в формате [x, y]. У обеих этих функций также были одинаковые параметры, структура данных игрового поля и один тип фишки, но возвра- щаемые ходы поступали из разных источников — либо от игрока, либо от алгоритма игры.
Что произойдет, если мы заменим вызов getPlayerMove() вызовом getComputerMove()
? Тогда игроку вообще не нужно будет вводить ход; этот вы- бор будет сделан за него. Компьютер будет играть против самого себя!
В этой главе мы создадим три новые программы, в которых компьютер играет против себя; каждая из этих программ будет основана на игре «Ревер- си» из главы 15:
• Модель
1: файл AISim1.py представляет собой измененную версию файла reversegam.py.
• Модель
2: файл AISim2.py представляет собой измененную версию файла AISim1.py.
• Модель
3: файл AISim3.py представляет собой измененную версию файла AISim2.py.

300
Глава 16
Небольшие изменения каждой из перечисленных программ покажут вам, как превратить игру «игрок против компьютера» в модель «компьютер против компьютера». Итоговая программа, AISim3.py, большую часть своего кода заим- ствует из файла reverseegam.py, но служит совершенно другой цели. Моделирова- ние не дает нам играть в «Реверси», но позволяет узнать больше о самой игре.
Вы можете либо ввести эти изменения самостоятельно, либо загрузить готовые файлы с веб-сайта https://eksmo.ru/files/python_games_sweigart.zip.
В ЭТОЙ ГЛАВЕ РАССМАТРИВАЮТСЯ СЛЕДУЮЩИЕ ТЕМЫ:
• Модели
• Процентные соотношения
• Целочисленное деление
• Функция round()
• Игры типа «компьютер против компьютера»
Компьютер против компьютера
Чтобы компьютер смог играть против себя, мы внесем в програм- му reversegam.py несколько простых изменений. Функции getPlayerMove() и getComputerMove() принимают структуру данных поля и фишку игрока, а затем возвращают ход, который следует сделать. Вот почему функция getComputerMove()
может заменить getPlayerMove(), и программа по-прежнему будет работать. В программе AISim1.py функция getComputerMove() вызывается и для игрока X, и для игрока O.
Мы также уберем вывод игрового поля с делающимися на нем ходами.
Поскольку человек не может считывать выводы полей так же быстро, как компьютер делает ходы, нецелесообразно выводить каждый ход — так что мы просто выводим итоговое поле.
Эти изменения минимальны, поэтому программа все равно будет выда- вать Человек ходит первым. и другие сообщения, несмотря на то, что компьютер играет за обе стороны.
Пример запуска модели 1
Вот что видит пользователь при запуске программы AISim1.py . Текст, вве- денный игроком, выделен полужирным шрифтом.
Приветствуем в игре "Реверси"!
Компьютер ходит первым.

Искусственный интеллект игры «Реверси»
301
12345678
+--------+
1|ХООООООО|1 2|ХХООХООО|2 3|ООХХОООО|3 4|ООХООООО|4 5|ООООХОХО|5 6|ООООХООО|6 7|ООХХХХХО|7 8|ОХХООООО|8
+--------+
12345678
X набрал 17 очков. O набрал 47 очков.
Вы проиграли. Компьютер победил вас, обогнав на 30 очков.
Хотите сыграть еще раз? (да или нет)
нет
Исходный код модели 1
Сохраните старый файл reverseegam.py под именем AISim1.py следующим образом:
1. Выберите команду меню File
Save as (Файл ⇒ Сохранить как).
2. Сохраните этот файл под именем AISim1.py, чтобы вы могли вносить изменения, не затрагивая программу reverseegam.py. (На данном этапе
reverseegam.py и AISim1.py все еще содержат один и тот же код.)
3. Внесите изменения в AISim1.py и сохраните этот файл, чтобы за- фиксировать любые изменения. (AISim1.py будет содержать новые изменения, а reverseegam.py будет содержать исходный, неизменен- ный код.)
Так вы создадите копию исходного кода «Реверси» в виде нового файла, в который вы можете вносить изменения, сохранив оригинальную игру (вы можете захотеть снова в нее сыграть, чтобы протестировать ее). Например, замените код в строке 216 в файле AISim1.py следующим (изменение выделе- но полужирным шрифтом):
216. move =
getComputerMove(board, playerTile)
Теперь запустите программу. Обратите внимание, что игра по-прежнему спрашивает, что вы хотите выбрать — X или O, но не попросит ввести ко- ординаты ходов. Когда вы заменяете функцию getPlayerMove() функцией getComputerMove()
, вы больше не вызываете код, который принимает инфор-

302
Глава 16
мацию, вводимую игроком. Игрок по-прежнему нажимает клавишу Enter по- сле исходных ходов компьютера (это требуется из-за кода input('Нажмите кла- вишу Enter для просмотра хода компьютера.')
в строке 232), но программа играет самостоя тельно!
Внесем в файл AISim1.py еще кое-какие из- менения. Измените указанные ниже строки кода, выделенные полужирным шрифтом. Изменения начинаются со строки 209. Большинство этих из- менений просто «отключат» строки кода, заком-
ментировав их , чтобы те не выполнялись.
Если при выполнении программы возникают ошибки, сравните код, который вы набрали, с ори- гинальным кодом с помощью онлайн-инструмента на сайте inventwithpython.com/diff/.
AISim1.py
207. elif turn == 'Человек': # Player's turn
208. if playerValidMoves != []:
209.
#if showHints:
210.
# validMovesBoard = getBoardWithValidMoves(board, playerTile)
211.
# drawBoard(validMovesBoard)
212.
#else:
213.
#drawBoard(board)
214.
#printScore(board, playerTile, computerTile)
215.
216. move =
getComputerMove(board, playerTile)
217.
#if move == 'выход':
218.
# print('Благодарим за игру!')
219.
# sys.exit() # Завершить работу программы.
220.
#elif move == 'подсказка':
221.
# showHints = not showHints
222.
# continue
223.
#else:
224.
makeMove(board, playerTile, move[0], move[1])
225. turn = 'Компьютер'
226.
227. elif turn == 'Компьютер': # Ход компьютера
228. if computerValidMoves != []:
229.
#drawBoard(board)
230.
#printScore(board, playerTile, computerTile)
Make sure you’re using Python 3, not Python 2!
УБЕ ДИТЕСЬ,
ЧТО ИСПО ЛЬЗУЕТЕ
PY THON 3,
А НЕ PY THON 2!

Искусственный интеллект игры «Реверси»
303
231.
232.
#input('Нажмите клавишу Enter для просмотра хода компьютера.')
233. move = getComputerMove(board, computerTile)
234. makeMove(board, computerTile, move[0], move[1])
235. turn = 'Человек'
236.
237.
238.
239. print('Приветствуем в игре "Реверси"!')
240.
241. playerTile, computerTile =
['Х', 'О'] #enterPlayerTile()
Удаление приглашений для игрока и добавление
игрока-компьютера
Как видно из кода, программа AISim1.py в основном тождественна ис- ходной программе «Реверси», за исключением того, что вызов getPlayerMove() был заменен вызовом getComputerMove(). Также были внесены некоторые из- менения в текст вывода на экране, чтобы за ходом игры было проще следить.
После старта программы на всю игру уходит менее секунды!
И снова большинство изменений заключается в комментировании не- которых строк кода. Поскольку компьютер играет против самого себя, про- грамме больше не нужно запускать код для получения ходов игрока или отображения состояния игрового поля. Все это пропущено, поэтому поле отображается только в самом конце игры. Код закомментирован, а не удален по той причине, что если нам будет нужно повторно использовать код позже, его будет проще восстановить, убрав символы #.
Я закомментировал строки кода с 209 по 214, поскольку больше не нужно выводить поле для игрока, уже не принимающего участие в игре. То же я про- делал со строками с 217 по 223, ведь не нужно проверять, вводит ли игрок слово выход или переключает режим подсказок. Но нужно убрать четыре про- бела перед строкой 224, так как она была частью блока else, который я только что отключил. Строки 229–232 также выводят игровое поле, поэтому я за- комментировал и эти строки.
Единственный новый код — в строках 216 и 241. В строке 216 мы просто заменяем вызов getPlayerMove() вызовом функции getComputerMove(), как гово- рилось ранее. В строке 241 вместо того, чтобы спрашивать игрока, желает он играть за X или O, мы просто присваиваем значение 'X' переменной playerTile и 'O' переменной computerTile. (Учитывая, что за обоих этих игроков будет играть компьютер, вы можете переименовать playerTile в computerTile2 или secondComputerTile
.) Теперь, когда у нас есть программа, в которой компьютер

304
Глава 16
играет против самого себя, можно продолжить изменять ее код, чтобы реали- зовать дополнительные интересные возможности.
Компьютер против компьютера —
несколько партий
Если бы мы создали новый алгоритм, то могли бы противопоставить его
ИИ, реализованному с помощью функции getComputerMove(), и посмотреть, какой из них лучше. Однако прежде чем мы сделаем это, нам нужен способ оценивать игроков. Мы не можем оценить, какой ИИ лучше, основываясь только на результатах одной партии, поэтому необходимо, чтобы ИИ сы- грали друг против друга более одного раза. Для этого мы внесем некоторые изменения в исходный код. Выполните следующие шаги, чтобы создать про- грамму AISim2.py :
1. Выберите команду меню File
Save as (Файл ⇒ Сохранить как).
2. Сохраните этот файл под именем AISim2.py, чтобы вы могли вносить изменения, не затрагивая программу AISim1.py. (На данном этапе
AISim1.py и AISim2.py все еще содержат один и тот же код.)
Пример запуска модели 2
Вот что видит пользователь, когда запускает программу AISim2.py:
Приветствуем в игре "Реверси"!
#1: X набрал 38 очков. O набрал 26 очков.
#2: X набрал 26 очков. O набрал 38 очков.
#3: X набрал 25 очков. O набрал 39 очков.
#4: X набрал 33 очков. O набрал 31 очков.
#5: X набрал 23 очков. O набрал 41 очков.
#6: X набрал 33 очков. O набрал 31 очков.
--
пропуск--
#249: X набрал 30 очков. O набрал 34 очков.
#250: X набрал 26 очков. O набрал 38 очков.
Количество выигрышей X: 115 (46.0%)
Количество выигрышей O: 129 (51.6%)
Количество ничьих: 6 (2.4%)
Поскольку алгоритмы предполагают случайность, ваш запуск не будет содержать точно такие же числа.

Искусственный интеллект игры «Реверси»
305
Исходный код модели 2
Измените код в AISim2.py, чтобы он соответствовал приведенному ниже коду. Убедитесь, что меняете код строка за строкой в порядке очереди. Если при выполнении программы возникают ошибки, сравните код, который вы набрали, с оригинальным кодом с помощью онлайн-инструмента на сайте
inventwithpython.com/diff/.
AISim2.py
235. turn = 'Человек'
236.
237. NUM_GAMES = 250
238. xWins = oWins = ties = 0
239. print('Приветствуем в игре "Реверси"!')
240.
241. playerTile, computerTile = ['Х', 'О'] #enterPlayerTile()
242.
243. for i in range(NUM_GAMES): #while True:
244. finalBoard = playGame(playerTile, computerTile)
245.
246. # Отобразить итоговый счет.
247. #drawBoard(finalBoard)
248. scores = getScoreOfBoard(finalBoard)
249. print('
#%s: X набрал %s очков. O набрал %s очков.' % (i + 1, scores['Х'], scores['О']))
250. if scores[playerTile] > scores[computerTile]:
251. xWins += 1 #print('Вы победили компьютер, обогнав его на %s очков! Поздравления!' % (scores[playerTile] - scores[computerTile]))
252. elif scores[playerTile] < scores[computerTile]:
253. oWins += 1 #print('Вы проиграли. Компьютер победил вас, обогнав на %s очков.' % (scores[computerTile] - scores[playerTile]))
254. else:
255. ties += 1 #print('Ничья!')
256.
257. #print('Хотите сыграть еще раз? (да или нет)')
258. #if not input().lower().startswith('д'):
259. # break
260.
261. print('Количество выигрышей X: %s (%s%%)' % (xWins, round(xWins / NUM_GAMES * 100, 1)))
262. print('Количество выигрышей O: %s (%s%%)' % (oWins, round(oWins / NUM_GAMES * 100, 1)))
263. print('Количество ничьих: %s (%s%%)' % (ties, round(ties / NUM_GAMES * 100, 1)))
Если у вас возникают проблемы с внесением изменений, можно загру- зить готовый файл AISim2.py с веб-сайта https://eksmo.ru/files/python_games_
sweigart.zip.

306
Глава 16
Отслеживание результатов партий
Основная информация, которую мы хотим получить в процессе моде- лирования, — это то, сколько побед одержал игрок X, сколько побед игрок
O, и сколько ничьих состоялось за определенное количество партий. Все это можно отслеживать с помощью четырех переменных, которые создаются в строках 237 и 238.
237. NUM_GAMES = 250 238. xWins = oWins = ties = 0
Константа NUM_GAMES определяет, сколько партий будет сыграно. Были до- бавлены переменные xWins, oWins и ties, чтобы отслеживать победы X, побе- ды O и ничьи. Вы можете связать воедино инструкции присваивания, чтобы присвоить переменной ties значение 0, переменной oWins — значение ties, и переменной xWins — значение oWins. Эта инструкция присваивает всем трем переменным значение 0.
Константа NUM_GAMES используется в цикле for, который заменяет игровой цикл в строке 243.
243. for i in range(NUM_GAMES): #while True:
Цикл for запускает игру столько раз, сколько указано в константе NUM_
GAMES
. Код заменяет цикл while, который выполнялся до тех пор, пока игрок не сообщал, что не хочет играть еще раз.
В строке 250 инструкция if сравнивает счет двух игроков, а строки с 251 по 255 в блоках if-elif-else инкрементируют значения переменных xWins, oWins и ties в конце каждой партии, прежде чем вернуться назад для начала новой партии.
250. if scores[playerTile] > scores[computerTile]:
251. xWins += 1 #print('Вы победили компьютер, обогнав его на %s очков! Поздравления!' %
(scores[playerTile] - scores[computerTile]))
252. elif scores[playerTile] < scores[computerTile]:
253. oWins += 1 #print('Вы проиграли. Компьютер победил вас, обогнав на %s очков.' %
(scores[computerTile] - scores[playerTile]))
254. else:
255. ties += 1 #print('Ничья!')

Искусственный интеллект игры «Реверси»
1   ...   25   26   27   28   29   30   31   32   ...   39


написать администратору сайта