Главная страница
Навигация по странице:

  • Отключение вызовов функции print()

  • Оценка искусственных интеллектов в процентном соотношении

  • Деление приводит к получению числа с плавающей запятой

  • Функция round() Функция round() округляет число с плавающей запятой до ближайшего целого числа. В интерактивной оболочке введите следующие команды:>>> round(10.0)

  • Сравнение различных алгоритмов ИИ

  • Принципы работы искусственных интеллектов в модели 3

  • ИИ лучшего углового хода

  • Проверка на граничные ходы

  • ИИ лучшего углового-граничного хода

  • Таблица 16.1. Функции, используемые для искусственных интеллектов игры «Реверси»Функция Описание

  • Сравнение искусственных интеллектов

  • ИИ худшего хода против ИИ лучшего углового хода

  • Учим 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
    страница30 из 39
    1   ...   26   27   28   29   30   31   32   33   ...   39
    307
    Мы убираем сообщения, первоначально выводящиеся внутри блока, поэ- тому теперь выводится лишь однострочный итог результатов каждой партии.
    Позже в коде мы будем использовать переменные xWins, oWins и ties, чтобы проанализировать, как компьютер выступил против самого себя.
    Отключение вызовов функции print()
    Я также закомментировал код в строках 247 и 257–259. Благодаря этому я убрал из программы бóльшую часть вызовов функций print() и drawBoard().
    Нам не нужно наблюдать за каждой из партий, поскольку их очень много.
    Программа по-прежнему запускает каждую партию целиком с использова- нием написанного нами ИИ, но показывает только итоговый счет. После за- вершения всех партий программа показывает, сколько партий выиграла каж- дая сторона, а код в строках с 251 по 253 выводят некоторую информацию об проведенных партиях.
    Вывод данных на экран замедляет работу компьютера, но теперь, когда вы удалили соответствующий код, компьютер может отыграть целую партию
    «Реверси» примерно за одну-две секунды. Каждый раз, когда программа вы- водила одну из тех строк с итоговым счетом, она обрабатывала всю игру (по отдельности проверяя около 50 или 60 ходов, чтобы выбрать тот, который приносит наибольшее количество очков). Теперь, когда компьютеру не нуж- но делать столько работы, он может работать намного быстрее.
    Числа, которые программа выводит в конце, являются статистически-
    ми данными , которые используются для обобщения итоговых результатов партий. В этом случае мы показали итоговые очки игроков в каждой партии, а также процентное соотношение побед игроков и ничьих между ними.
    Оценка искусственных интеллектов
    в процентном соотношении
    Процентное соотношение — это часть от общего количества. Значение процентного соотношения может варьироваться в диапазоне от 0 до 100%.
    Представьте, что у вас есть пирог: 100% — это весь пирог, 50% — его полови- на, а 0% — пирога вообще нет.
    Мы можем рассчитывать процентные соотношения с помощью деления.
    Чтобы получить процентное соотношение, разделите часть, которая у вас есть, на общее количество, а затем умножьте результат на 100. Например, если X выиграл 50 партий из 100, можно составить выражение 50 / 100, рав- няющееся 0.5. Умножьте это на 100, чтобы получить процентное соотношение
    (в данном случае 50 процентов).
    Если X выиграл 100 партий из 200, можно составить выражение 100 / 200, что также равно 0.5. Когда вы умножите 0.5 на 100, чтобы узнать процентное

    308
    Глава 16
    соотношение, получите 50 процентов. Выигрыш 100 партий из 200 — это то же процентное соотношение, что и выигрыш 50 партий из 100.
    В строках с 261 по 263 мы используем процентные соотношения для вы- вода информации об итогах партий.
    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)))
    Каждая инструкция print() имеет метку, которая сообщает пользова- телю, относятся выводимые данные к победам X, победам O или ничьим.
    Я применил метод интерполяции строк для вставки количества выигранных партий и ничьих, а также вычисленного процентного соотношения выигры- шей и ничьих в общем количестве партий. Но, как видите, здесь не просто де- лятся значения переменных xWins, oWins или ties на общее количество партий и умножаются на 100. Это потому что для каждого процентного соотношения нужно вывести только один дробный символ после запятой, что нельзя осу- ществить путем обычного деления.
    Деление приводит к получению числа с плавающей запятой
    Когда вы используете оператор деления (/), выражение всегда будет вы- числяться в число с плавающей запятой. Например, выражение 10 / 2 вычис- ляется как число с плавающей запятой 5.0, а не целочисленное значение 5.
    Важно помнить об этом, поскольку прибавление целого числа к числу с плавающей запятой с помощью оператора сложения + также всегда будет приводить к получению числа с плавающей запятой. Например, выраже- ние 3 + 4.0 равно числу с плавающей запятой 7.0, а не целому числу 7.
    Введите следующий код в интерактивной оболочке:
    >>>
    spam = 100 / 4
    >>>
    spam
    25.0
    >>>
    spam = spam + 20
    >>>
    spam
    45.0
    В этом примере тип данных значения переменной spam всегда является числом с плавающей запятой. Вы можете передать значение с плавающей

    Искусственный интеллект игры «Реверси»
    309
    запятой функции int(), которая возвращает целочисленную форму значе- ния с плавающей запятой. Но эта функция всегда будет округлять значе- ние в меньшую сторону. Например, каждое из выражений int(4.0), int(4.2) и int(4.9) принимает значение 4, но не 5. Но в программе AISim2.py нам нуж- но округлить каждую процентную долю до десятых. Поскольку для этого мы не можем просто выполнить деление, нужно воспользоваться функцией round()
    Функция round()
    Функция round() округляет число с плавающей запятой до ближайшего целого числа. В интерактивной оболочке введите следующие команды:
    >>>
    round(10.0)
    10
    >>>
    round(10.2)
    10
    >>>
    round(8.7)
    9
    >>>
    round(3.4999)
    3
    >>>
    round(2.5422, 2)
    2.54
    Функция round() также имеет необязательный второй параметр, с помо- щью которого вы можете указать, до какого знака требуется округлить число.
    Благодаря этому округленное число может быть числом с плавающей запя- той, а не целым. Например, выражение round(2.5422, 2) вычисляется в значе- ние 2.54, а round(2.5422, 3) — в значение 2.542. В строках 261–263 программы
    AISim2.py мы используем эту функцию с параметром 1, чтобы округлить со- отношение выигранных или сыгранных вничью партий до одного знака по- сле запятой, что позволяет нам получить точные процентные соотношения.
    Сравнение различных алгоритмов ИИ
    Внеся лишь несколько изменений, мы можем заставить компьютер играть против себя сотни раз. Прямо сейчас каждый игрок побеждает примерно в половине партий, так как они оба используют один и тот же алгоритм вы- бора ходов. Но если мы добавим разные алгоритмы, то увидим, какой ИИ чаще будет выигрывать чаще.

    310
    Глава 16
    Давайте добавим функции с новыми алгоритмами. Но сначала в окне с файлом AISim2.py выберите команду меню File
    Save as (Файл ⇒ Сохра- нить как), чтобы сохранить сценарий под именем AISim3.py .
    Мы переименуем функцию getComputerMove() в getCornerBestMove(), так как этот алгоритм сначала пытается осуществлять угловые ходы, а затем выбира- ет ход, который переворачивает больше всего фишек. Мы назовем эту стра- тегию алгоритмом лучшего углового хода. Также добавим несколько других функций, реализующих различные стратегии, включая алгоритм худшего
    хода, который ищет ход с худшим по счету результатом; алгоритм случайно-
    го хода, который ищет любой допустимый ход; и алгоритм лучшего углового-
    граничного хода, работающий так же, как и алгоритм лучшего углового хода, за исключением того, что после углового хода и перед ходом, переворачиваю- щим больше всего фишек, он ищет граничный ход.
    В файле AISim3.py вызов getComputerMove()в строке 257 будет заменен на функцию getCornerBestMove(), а функция getComputerMove() в строке 274 ста- нет getWorstMove() — функцией, которую мы напишем для алгоритма худшего хода. Таким образом, мы заставим соревноваться обычный алгоритм лучше- го углового хода и алгоритм, который целенаправленно выбирает ход, пере- ворачивающий меньше всего фишек.
    Исходный код модели 3
    Измените код в файле AISim3.py, чтобы он соответствовал приведенному ниже коду. Убедитесь, что меняете код строка за строкой в порядке очереди.
    Если при выполнении программы возникают ошибки, сравните код, который вы набрали, с оригинальным кодом с помощью онлайн-инструмента на сайте
    inventwithpython.com/diff/.
    AISim3.py
    162. def
    getCornerBestMove(board, computerTile):
    --
    пропуск
    1 184. def getWorstMove(board, tile):
    185. # Вернуть ход, который переворачивает меньше всего фишек.
    186. possibleMoves = getValidMoves(board, tile)
    187. random.shuffle(possibleMoves) # Сделать случайным порядок ходов.
    188.
    189. # Найти ход с наименьшим возможным количеством очков.
    190. worstScore = 64

    Искусственный интеллект игры «Реверси»
    311
    191. for x, y in possibleMoves:
    192. boardCopy = getBoardCopy(board)
    193. makeMove(boardCopy, tile, x, y)
    194. score = getScoreOfBoard(boardCopy)[tile]
    195. if score < worstScore:
    196. worstMove = [x, y]
    197. worstScore = score
    198.
    199. return worstMove
    200.
    201. def getRandomMove(board, tile):
    202. possibleMoves = getValidMoves(board, tile)
    203. return random.choice(possibleMoves)
    204.
    205. def isOnSide(x, y):
    206. return x == 0 or x == WIDTH - 1 or y == 0 or y == HEIGHT — 1 207.
    208. def getCornerSideBestMove(board, tile):
    209. # Вернуть угловой ход, граничный ход или лучший ход.
    210. possibleMoves = getValidMoves(board, tile)
    211. random.shuffle(possibleMoves) # Сделать случайным порядок ходов.
    212.
    213. # Всегда делать ход в угол, если это возможно.
    214. for x, y in possibleMoves:
    215. if isOnCorner(x, y):
    216. return [x, y]
    217.
    218. # Если сделать ход в угол нельзя, вернуть граничный ход.
    219. for x, y in possibleMoves:
    220. if isOnSide(x, y):
    221. return [x, y]
    222.
    223. return getCornerBestMove(board, tile) # Делать то, что делал бы обычный ИИ.
    224.
    225. def printScore(board, playerTile, computerTile):
    --
    пропуск--
    257. move =
    getCornerBestMove(board, playerTile)
    --
    пропуск--
    274. move =
    getWorstMove(board, computerTile)

    312
    Глава 16
    Запуск файла AISim3.py выводит то же самое, что и AISim2.py, за исключе- нием того, что теперь будут использоваться разные алгоритмы.
    Принципы работы искусственных интеллектов в модели 3
    Функции getCornerBestMove()
    , getWorstMove()
    , getRandomMove()
    и getCornerSideBestMove() похожи друг на друга, но используют несколько отличающиеся игровые стратегии. Одна из них применяет новую функцию isOnSide()
    . Она аналогична нашей функции isOnCorner(), но проверяет клетки вдоль сторон поля, прежде чем выбрать самый результативный ход.
    ИИ лучшего углового хода
    У нас уже есть код для ИИ, который выбирает угловой ход, а затем вы- бирает лучший ход из возможных, ведь это именно то, что делает функция getComputerMove()
    . Мы можем просто изменить имя getComputerMove() на что-то более описательное, так что измените строку 162 и переименуйте нашу функ- цию в getCornerBestMove().
    162. def getCornerBestMove(board, computerTile):
    Поскольку функции getComputerMove() больше не существует, нам необхо- димо обновить код в строке 257, указав там имя getCornerBestMove().
    257. move = getCornerBestMove(board, playerTile)
    Это все, что нам нужно было сделать для данного ИИ, поэтому давайте двигаться дальше.
    ИИ худшего хода
    ИИ худшего хода просто находит ход с наименьшим количеством очков и возвращает его. Его код очень похож на тот, который мы использовали для поиска хода с наибольшим количеством очков в нашем исходном алгоритме getComputerMove()
    184. def getWorstMove(board, tile):
    185. # Вернуть ход, который переворачивает меньше всего фишек.
    186. possibleMoves = getValidMoves(board, tile)
    187. random.shuffle(possibleMoves) # Сделать случайным порядок ходов.
    188.
    189. # Найти ход с наименьшим возможным количеством очков.

    Искусственный интеллект игры «Реверси»
    313
    190. worstScore = 64 191. for x, y in possibleMoves:
    192. boardCopy = getBoardCopy(board)
    193. makeMove(boardCopy, tile, x, y)
    194. score = getScoreOfBoard(boardCopy)[tile]
    195. if score < worstScore:
    196. worstMove = [x, y]
    197. worstScore = score
    198.
    199. return worstMove
    Алгоритм getWorstMove() начинается аналогичным кодом в строках 186 и 187, но затем со строки 190 появляются отличия. Мы назначили пере- менную worstScore (худший результат) вместо bestScore (лучший результат) и присвоили ей значение 64, так как это общее число позиций на поле и наи- большее количество очков, которые можно было бы заработать, если бы все поле было заполнено. Строки с 191 по 194 такие же, как и исходный алгоритм, но затем код в строке 195 проверяет, меньше ли значение переменной score чем worstScore, вместо того, чтобы проверять, больше ли значение перемен- ной score. Если значение переменной score меньше, тогда worstMove заменяет- ся ходом на поле, который в настоящее время тестирует алгоритм, и значение переменной worstScore также обновляется. Потом функция возвращает зна- чение переменной worstMove.
    Наконец, функция getComputerMove() в строке 274 должна быть заменена функцией getWorstMove().
    274. move = getWorstMove(board, computerTile)
    Внесите эти изменения и запустите программу, и getCornerBestMove() и getWorstMove() будут играть друг против друга.
    ИИ случайного хода
    ИИ случайного хода просто находит все возможные допустимые ходы, а затем случайным образом выбирает один из них.
    201. def getRandomMove(board, tile):
    202. possibleMoves = getValidMoves(board, tile)
    203. return random.choice(possibleMoves)

    314
    Глава 16
    Здесь используется функция getValidMoves(), как и во всех остальных ИИ, а затем применяется функция choice(), чтобы в списке вернуть один из воз- можных ходов.
    Проверка на граничные ходы
    Прежде чем перейти к алгоритмам, давайте рассмотрим одну новую вспомогательную функцию, добавленную нами. Вспомогательная функция isOnSide()
    подобна функции isOnCorner(), только она проверяет, приходится ли ход на стороны игрового поля.
    205. def isOnSide(x, y):
    206. return x == 0 or x == WIDTH - 1 or y == 0 or y == HEIGHT — 1
    Она содержит одно логическое выражение, которое проверяет, равны ли значения координат x или y, переданных ей в качестве аргументов, 0 или 7.
    Любая координата со значением 0 или 7 находится на краю поля.
    Мы будем использовать эту функцию далее в ИИ лучшего углового- граничного хода.
    ИИ лучшего углового-граничного хода
    Этот ИИ работает во многом так же, как ИИ лучшего углового хода, поэтому мы можем повторно использовать часть уже введенного кода. Мы определяем этот ИИ в функции getCornerSideBestMove().
    208. def getCornerSideBestMove(board, tile):
    209. # Вернуть угловой ход, граничный ход или лучший ход.
    210. possibleMoves = getValidMoves(board, tile)
    211. random.shuffle(possibleMoves) # Сделать случайным порядок ходов.
    212.
    213. # Всегда делать ход в угол, если это возможно.
    214. for x, y in possibleMoves:
    215. if isOnCorner(x, y):
    216. return [x, y]
    217.
    218. # Если сделать ход в угол нельзя, вернуть граничный ход.
    219. for x, y in possibleMoves:
    220. if isOnSide(x, y):
    221. return [x, y]
    222.
    223. return getCornerBestMove(board, tile) # Делать то, что делал бы обычный ИИ.

    Искусственный интеллект игры «Реверси»
    315
    Строки 210 и 211 такие же, как и в ИИ лучшего углового хода, а стро- ки 214–216 идентичны нашему алгоритму, проверяющему наличие углового хода в исходном ИИ getComputerMove(). Если угловой ход недоступен, тогда код в строках 219–221 проверяют наличие граничного хода с помощью вспомога- тельной функции isOnSide(). В случае если было проверено наличие всех угло- вых и граничных ходов, а хода еще нет, мы повторно используем нашу функ- цию getCornerBestMove(). Поскольку ранее угловые ходы найдены не были, их все еще не будет, когда код достигнет функции getCornerBestMove(), так что эта функция просто найдет ход с наибольшим количеством очков и вернет его.
    В таблице 16.1 рассматриваются созданные нами новые алгоритмы.
    Таблица 16.1.
    Функции, используемые для искусственных интеллектов игры «Реверси»
    Функция
    Описание
    getCornerBestMove()
    Сделать угловой ход, если возможно. Если нет, найти ход с наиболь- шим количеством очков getCornerSideBestMove()
    Сделать угловой ход, если возможно. Если нет, выбрать граничную клетку. Если граничных ходов нет, использовать обычный алгоритм getCornerBestMove()
    getRandomMove()
    Случайным образом выбрать допустимый ход getWorstMove()
    Выбрать позицию, ход на которую перевернет меньше всего фишек
    Теперь, когда у нас есть все алгоритмы, мы можем «натравить» их друг на друга.
    Сравнение искусственных интеллектов
    В нашей программе ИИ лучшего углового хода играет против ИИ худ- шего хода. Мы можем запустить программу для моделирования, насколько хорошо ИИ действуют друг против друга, и проанализировать результаты с помощью статистики.
    В дополнение к этим двум ИИ мы создали несколько других, которые не вызвали. Эти ИИ содержатся в коде, но не используются, поэтому, если мы хотим увидеть, как они выступят в матче друг с другом, нужно будет отре- дактировать код для их вызова. Так как у нас уже настроено одно сравнение, давайте посмотрим, как ИИ худшего хода будет справляться с ИИ лучшего углового хода.
    ИИ худшего хода против ИИ лучшего углового хода
    Запустите программу, чтобы выставить функцию getCornerBestMove() против getWorstMove(). Неудивительно, что стратегия переворачивания наи- меньшего количества фишек за ход привела к поражению в большинстве партий.

    316
    Глава 16
    Количество выигрышей X: 206 (82.4%)
    Количество выигрышей O: 41 (16.4%)
    Количество ничьих: 3 (1.2%)
    А вот что удивительно, так это то, что порой стратегия худшего хода все же работает! Вместо выигрыша в 100% случаев, алгоритм функции getCornerBestMove()
    побеждает лишь примерно в 80% случаев. Примерно 1 раз в 5 партий он уступает!
    В этом сила моделирования: вы можете найти новые идеи, на осознание которых ушло бы гораздо больше времени, если бы вы играли самостоятель- но. Компьютер намного быстрее!
    1   ...   26   27   28   29   30   31   32   33   ...   39


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