казино на питоне простейший код / Пишем игру на Python — Журнал «Код» программирование без снобизма

Казино На Питоне Простейший Код

казино на питоне простейший код

 

Регистрация:

Сообщений: 6

По умолчаниюНужна помощь с одноруким бандитом(казино)

Всем добрый день/вечер, нужна помощь для создания однорукого бандита. Вот собственно сам код, который я делал, мне нужна помощь в создании начальной заставки и вместо цифр, которые выпадают, нужно сделать фотографии, типа яблок, семерок и т.п(ну как в казино)

import random
import time

while True:
try:
credit = int(input('Введи нужное тебе колличество кредитов: '))
print ('И так! Игра началась. У тебя есть ' + str(credit) +
' единиц, с помощью них ты можешь делать ставки')
cash = int(input('Введи ставку: '))
except:
print ('ВВЕДИ ЦИФРЫ')
try:
while credit > 0:
print('Отлично, ставка сделана!')
goalma.org()
print('Игра началась')
goalma.org(1)

m = goalma.orgt(1, 3)
o = goalma.orgt(1, 3)
n = goalma.orgt(1, 3)
e = goalma.orgt(1, 3)

print(m, o, n, e)
credit = credit - cash
if m == 1 and o == 1 and n == 1 and e == 1 or m == 2 and o == 2 and n == 2 and e == 2 or m == 3 and o == 3 and n == 3 and e == 3 :

b = goalma.orgt(2, )
print(' ВЫ ВЫИГРАЛИ ' + str(cash * b))
credit = credit + (cash * b)
goalma.org(2)
y = input('Введи "y" если хочешь сменить ставку: ')
goalma.org(2)
if y == 'y':
cash = int(input('Введи ставку: '))
else:
continue
goalma.org(2)
print('Oсталось кредитов ' + str(credit))
input('Press enter!')
except:
print('ERROR ENTER')

В предыдущем материале был написан код для симуляции игры в блэкджек. С помощью симуляции большого количества игр можно было четко отследить, какое преимущество есть у казино. Вот что удалось обнаружить:

  • Казино получает конкурентное преимущество, заставляя игроков совершать действия до дилера (действовать в условиях неполной информации). Это создает риск получить перебор (таким образом игроки теряют все еще до того, как дилер совершает хоть какое-нибудь действие).
  • Особую опасность представляют ситуации, когда карты на руках игроков стоят от 12 до 16 очков (в таком случае вероятность получить перебор со следующей картой максимальная), а дилер показывает старшую карту. В таких случаях можно предположить, что у дилера будет более высокое значение, так что игрокам остается только брать еще или проигрывать. Это можно увидеть даже визуально на графике с шансами на победу или ничью (промежуток значений от 12 до 16 называется “долиной отчаяния”).
    Вероятность выигрыша или ничьей к сумме карт игрока
  • Наконец, простейшая «наивная» стратегия брать карты в случае нулевой вероятности получить перебор значительно увеличивает шансы на победу, ведь в таком случае растет вероятность того, что проиграет казино.

Также в том материале были описаны и правила игры.

Способно ли глубокое обучение справиться лучше?

Задача этого материала — определить, можно ли с помощью глубокого обучения получить более эффективную стратегию. Для этого:

  1. Сгенерируем данные с помощью симулятора блэкджека из прошлого материала (с некоторыми исправлениями, чтобы он лучше подходил для тренировки алгоритмов).
  2. Напишем код для тренировки нейронной сети игре в блэкджек (желательно оптимальной).

Визуальное изображение простой нейронной сети

Прежде чем переходить к самому процессу тренировки, вернемся и быстро рассмотрим достоинства и недостатки использования нейронной сети в этой ситуации. Нейронные сети — это очень эффективные алгоритмы, которые можно, грубо говоря, сравнить с глиной. Они подстраиваются под очертания доступной информации, при это минимально или вообще не изменяясь. Данные, например, с линейной регрессией запросто поддаются обработке с помощью нейронной сети. А слои и нейроны в сети способны находить заложенные глубоко внутри нелинейные отношения данных.

Тем не менее за такую гибкость приходится платить: нейронная сеть — это модель черного ящика. В отличие от регрессии, когда можно увидеть, как именно модель принимает решения, посмотрев на коэффициенты, нейронная сеть такой прозрачностью не обладает. Она также подвержена риску переобучения, при котором данные из выборки уже не обобщаются. Об этих недостатках нужно помнить и предпринимать дополнительные меры для работы с ними. Тем не менее это не повод отказываться от использования нейронных сетей.

Генерация тренировочных данных

Перед началом тренировки нейронной сети сперва нужно определить, как структурировать данные так, чтобы построенная модель была полезной.

Что нужно предсказать? Есть два кандидата на роль целевой переменной:

  1. Вероятность поражения. Но это полезно только в том случае, если бы была возможность увеличить или уменьшить ставку, однако в блэкджеке такого варианта нет.
  2. Оптимальное действие: взять еще карту или спасовать. Поэтому целевой переменной будет решение о том, какое действие идеально в конкретной ситуации: взять еще или сделать пас.

Нет необходимости в том, чтобы сеть вообще не делала ошибок. Достаточно добиться того, чтобы она в большинстве случаев предсказывала правильно. Вот какой способ для этого можно использовать:

  1. раздать карты игроку и дилеру;
  2. проверить, нет ли у одного из них 21;
  3. выполнить одно действие (взять карту или спасовать);
  4. симулировать игру до конца и записать результат.

Поскольку симулируемый игрок принимает лишь одно решение, можно оценить его качество на основе того, выиграл ли он партию или проиграл:

  • Если игрок взял карту и выиграл, тогда карта (Y=1) была правильным решением
  • Если игрок взял карту и проиграл, тогда пас (Y=0) был правильным решением
  • Если игрок спасовал и выиграл, тогда пас (Y=1) был правильным решением
  • Если игрок спасовал и проиграл, тогда карта (Y=0) была правильным решением

Это позволяет тренировать модель так, чтобы вывод представлял собой предсказание правильного действия: карта или пас. Код похож на тот, что использовался в прошлый раз. Вот основные признаки:

  1. Открытая карта лидера (вторая закрыта от игроков)
  2. Общая стоимость карт в руках игрока
  3. Проверка, есть ли у игрока туз
  4. Действие игрока (карта или пас)

Цель — выявить правильно решение на основе описанный выше логики.

Тренировка нейронной сети

ВАЖНО! Весь код статьи в этом архиве

Для нейронной сети будет использоваться библиотека Keras. Сначала добавим все необходимые импорты:

Теперь настроим переменные ввода для тренировки сети. feature_list — это переменная с колонками, представляющими перечисленные выше признаки. В dataframe model_rf хранятся данные запущенных симуляций.

Код, запускающий и тренирующий нейронную сеть, довольно простой. Первая строка создает нейронную сеть последовательного типа, которая является линейной последовательностью слоев нейронной сети. Следующие строки друг за другом добавляют слои ( — простейший тип слоя, представляющий собой набор нейронов), а числа 16, и т. д. обозначают количество нейронов в каждом слое.

Наконец, для последнего слоя нужно выбрать функцию активации. Она конвертирует сырой вывод в более осмысленный вид. Обратите внимание на две вещи: во-первых, финальный слой включает лишь один нейрон, потому что предсказание делается на основе двух возможных выводов (двухклассовая проблема). Во-вторых, используется сигмоидная функция, потому что необходимо, чтобы нейронная сеть действовала по принципу логистической регрессии и предсказывала, что является корректным действием: карта (Y=1) или пас (Y=0). Другими словами, необходимо знать вероятность того, что карта — это правильный вариант.

Последние две строчки сообщают, какую функцию потерь использовать (перекрестная функция — это функция потерь, используемая классификационными моделями, которые предсказывают вероятности) и сопоставляют данные с моделью. Если поэкспериментировать с количеством нейронов чуть дольше, то можно получить еще более эффективную сеть.

Предсказание производительности модели

Простой способ оценить, насколько эффективнее оказывается модель — использовать ROC-кривую. ROC-кривая показывает, насколько хороша модель в плане отношения между пользой (общим количеством носителей признака, верно классифицированных как несущие признак) и затратами (долей объектов от общего количества объектов, не несущих признака, ошибочно классифицированных как несущие признак). Чем больше площадь под кривой, тем лучше модель.

График показывает ROC-кривую для нейронной сети, играющей в блэкджек. Судя по всему, она все-таки дает обеспечивает полезность относительно случайного угадывания (красная пунктирная линия). Площадь под кривой, AUC, — 0,73, в то время как показатель AUC для случайного предсказывания равен 0,5.

ROC кривая для игры нейросети в блэкджек

Для составления ROC-кривой здесь использовались тренировочные данные. Обычно для этого нужны тестовые данные, но в этом случае, поскольку известно, что набор довольно большой, то он является репрезентативным (если продолжать играть по тем же правилам). И можно предположить, что модель будет хорошо обобщать данные (любые новые данные будут обладать теми же характеристиками, что и тренировочные).

Время играть!

Прежде чем нейронная сеть начнет играть, ей нужно передать правило принятия решения. Здесь нужно напомнить, что сигмоидная активация (из финального слоя нейронной сети) показывает вывод в виде вероятности того, что карта — это правильный ход. Теперь нужно задать правила, когда в соответствии с вероятностью необходимо брать карту или делать пас.

Функция принимает в качестве признаков то, что необходимо нейронной сети, делает на их основе предсказание и сравнивает его с заданным порогом, чтобы решить, брать или еще карту или пасовать. Используем значение 0,52, потому что нам известно, что перебор в блэкджеке представляет куда большую опасность. Таким образом такая вероятность слегка уменьшает вероятность действия карта и уменьшает риск перебора.

Осталось лишь добавить эту функцию в код в то место, где решается, брать ли еще карту или пасовать. Теперь нейронная сеть будет принимать решение на основе того, какую карту показывает дилер, общей стоимости карт и наличия туза в руке.

А модель хороша!

Теперь сравним показатели нейронной сети со случайной и наивной стратегиями.

  • Всего было запущено симуляций для каждой стратегии
  • При наивной стратегии карта берется только в том случае, если на руках меньше 12 очков
  • При случайной стратегии подбрасывается монетка: если орел, тогда берем карту, если решка — пас. Если карта взята и нет перебора, тогда процесс продолжается снова и снова.

Посмотрим, получилась ли стратегия нейронной сети более выгодной. Следующая таблица показывает распределение результата для каждой стратегии. Нейронная сеть проиграла чуть меньше половины сыгранных игр. В этом случае вы все еще не обыгрываете казино, но это неплохой результат для игры, где все шансы против игрока. При этом ей не удалось одержать намного больше побед, чем в случае наивной стратегии — зато получилось больше ничьих.

Распределение результатов по стратегии

Также можно взглянуть на то, как показали себя стратегии в отношении ключевых признаков (карты дилера и стоимости карт на руках). Во-первых, проверим, как карта дилера влияет на вероятность победы или ничьей в трех стратегиях. Если у дилера карта с маленьким значением, результаты нейронной сети такие же, как и у наивной стратегии. Но если у него больше 7, то она показывает себя намного лучше.

Сравнение трех стратегий игры

Также можно взглянуть на вероятность победы или ничьей в зависимости от стартовой руки игрока. Нам всем диапазоне нейронная сеть показывает себя намного эффективнее. И в отличие от наивной, которая работает даже хуже угадывания в долине отчаяния (когда на руках значения от 12 до 16), нейронная сеть выступает очень неплохо.

Сравнение трех стратегий игры 2

Следующий график показывает, насколько нейронная сеть эффективнее наивной стратегии. Последняя (из-за используемого алгоритма) даже не предпринимает попыток, когда есть хоть какая-то вероятность перебора. Нейронная сеть же регулярно берет еще карту, когда у нее 12, 13, 14 или В данном случае речь идет о принятии решений с большим количество деталей и способностью учитывать некоторые риски.

Склонность брать карту у нейронной сети и наивной стратегии

Можно взглянуть на то, что делает нейронная сеть, когда у игрока на руках между 12 и 16 очками, чтобы улучшить наивную стратегию (и не проигрывать так много денег казино).

Похоже, что сеть часто берет карту, когда дилер показывает старшую карту (8, 9 или 10). Но даже когда у него на руках что-то низкое, например 3, нейронная сеть берет карту в 60% случаев. Это связано с тем, что она учитывает все признаки. На основе этого можно было бы разработать несколько простых правил.

Частота добора карты у нейронной сети к показанной карты дилера

Выводы

Теперь вы должны чуть лучше представлять, как машинное обучение используется для помощи в принятии решений из реальной жизни. Вот что важно запомнить для тренировки моделей (будь то деревья решений, регрессии или нейронные сети):

  • Структурирована ли целевая переменная так, что если ее можно предсказать, то она решит проблему? Прежде чем переходить к сбору данных и построению модели, важно убедиться, что вы предсказываете нужные вещи.
  • Как могут новые данные отличаться от тех, на которых производилась тренировка? Если они будут отличаться значительно, тогда статистическая модель может и вовсе не подойти. И по крайней мере это нужно осознавать и встраивать проверки, такие как регуляризация или строгая валидация, а также проводить тестирование модели.
  • Если вы не можете понять, как модель принимает решения, то не поймете качество этих решений, сделанных вне тестовых данных.

Напоследок пара напутственных слов о том, как вы сможете улучшить представленный код самостоятельно:

  1. Попробуйте улучшить модель с помощью оптимизированной структуры нейронной сети, кода для разделения тузов (здесь он не использовался) или, наконец, выбора лучших признаков.
  2. Научите модель считать карты и смотрите, как это влияет на производительность в случае игры с одной колодой и шестью (стандарт Вегаса).

Возможно, вам удастся добиться более впечатляющих результатов. Удачи!

Пишем игру на Python

Прежде чем мы начнём программировать что-то полезное на Python, давайте закодим что-нибудь интересное. Например, свою игру, где нужно не дать шарику упасть, типа Арканоида. Вы, скорее всего, играли в детстве во что-то подобное, поэтому освоиться будет просто.

Логика игры

Есть игровое поле — простой прямоугольник с твёрдыми границами. Когда шарик касается стенки или потолка, он отскакивает в другую сторону. Если он упадёт на пол — вы проиграли. Чтобы этого не случилось, внизу вдоль пола летает платформа, а вы ей управляете с помощью стрелок. Ваша задача — подставлять платформу под шарик как можно дольше. За каждое удачное спасение шарика вы получаете одно очко.

Алгоритм

Чтобы реализовать такую логику игры, нужно предусмотреть такие сценарии поведения:

  • игра начинается;
  • шарик начинает двигаться;
  • если нажаты стрелки влево или вправо — двигаем платформу;
  • если шарик коснулся стенок, потолка или платформы — делаем отскок;
  • если шарик коснулся платформы — увеличиваем счёт на единицу;
  • если шарик упал на пол — выводим сообщение и заканчиваем игру.

Хитрость в том, что всё это происходит параллельно и независимо друг от друга. То есть пока шарик летает, мы вполне можем двигать платформу, а можем и оставить её на месте. И когда шарик отскакивает от стен, это тоже не мешает другим объектам двигаться и взаимодействовать между собой.

Получается, что нам нужно определить три класса — платформу, сам шарик и счёт, и определить, как они реагируют на действия друг друга. Поле нам самим определять не нужно — для этого есть уже готовая библиотека. А потом в этих классах мы пропишем методы — они как раз и будут отвечать за поведение наших объектов.

Весь кайф в том, что мы всё это задаём один раз, а потом объекты сами разбираются, как им реагировать друг на друга и что делать в разных ситуациях. Мы не прописываем жёстко весь алгоритм, а задаём правила игры — а для этого классы подходят просто идеально.

По коням, пишем на Python

Для этого проекта вам потребуется установить и запустить среду Python. Как это сделать — читайте в нашей статье.

Начало программы

Чтобы у нас появилась графика в игре, используем библиотеку Tkinter. Она входит в набор стандартных библиотек Python и позволяет рисовать простейшие объекты — линии, прямоугольники, круги и красить их в разные цвета. Такой простой Paint, только для Python.

Чтобы создать окно, где будет видна графика, используют класс Tk(). Он просто делает окно, но без содержимого. Чтобы появилось содержимое, создают холст — видимую часть окна. Именно на нём мы будем рисовать нашу игру. За холст отвечает класс Canvas(), поэтому нам нужно будет создать свой объект из этого класса и дальше уже работать с этим объектом.

Если мы принудительно не ограничим скорость платформы, то она будет перемещаться мгновенно, ведь компьютер считает очень быстро и моментально передвинет её к другому краю. Поэтому мы будем искусственно ограничивать время движения, а для этого нам понадобится модуль Time — он тоже стандартный.

Последнее, что нам глобально нужно, — задавать случайным образом начальное положение шарика и платформы, чтобы было интереснее играть. За это отвечает модуль Random — он помогает генерировать случайные числа и перемешивать данные.

Запишем всё это в виде кода на Python:

Мы подключили все нужные библиотеки, сделали и настроили игровое поле. Теперь займёмся классами.

Шарик

Сначала проговорим словами, что нам нужно от шарика. Он должен уметь:

  • задавать своё начальное положение и направление движение;
  • понимать, когда он коснулся платформы;
  • рисовать сам себя и понимать, когда нужно отрисовать себя в новом положении (например, после отскока от стены).

Этого достаточно, чтобы шарик жил своей жизнью и умел взаимодействовать с окружающей средой. При этом нужно не забыть о том, что каждый класс должен содержать конструктор — код, который отвечает за создание нового объекта. Без этого сделать шарик не получится. Запишем это на Python:

Платформа

Сделаем то же самое для платформы — сначала опишем её поведение словами, а потом переведём в код. Итак, вот что должна уметь платформа:

  • двигаться влево или вправо в зависимости от нажатой стрелки;
  • понимать, когда игра началась и можно двигаться.

А вот как это будет в виде кода:

Счёт

Можно было не выделять счёт в отдельный класс и каждый раз обрабатывать вручную. Но здесь реально проще сделать класс, задать нужные методы, чтобы они сами потом разобрались, что и когда делать.

От счёта нам нужно только одно (кроме конструктора) — чтобы он правильно реагировал на касание платформы, увеличивал число очков и выводил их на экран:

Игра

У нас всё готово для того, чтобы написать саму игру. Мы уже провели необходимую подготовку всех элементов, и нам остаётся только создать конкретные объекты шарика, платформы и счёта и сказать им, в каком порядке мы будем что делать.

Смысл игры в том, чтобы не уронить шарик. Пока этого не произошло — всё движется, но как только шарик упал — нужно показать сообщение о конце игры и остановить программу.

Посмотрите, как лаконично выглядит код непосредственно самой игры:

ПОЛНЫЙ КОД ПРОГРАММЫ

Пишем игру на Python

Что дальше

На основе этого кода вы можете сделать свою модификацию игры:

  • добавить второй шарик;
  • раскрасить элементы в другой цвет;
  • поменять размеры шарика; поменять скорость платформы;
  • сделать всё это сразу;
  • поменять логику программы на свою.

Любишь Python? Зарабатывай на нём!

Изучите самый модный язык программирования и станьте крутым бэкенд-разработчиком. Старт — бесплатно.

Начать бесплатно
Любишь Python? Зарабатывай на нём!Любишь Python? Зарабатывай на нём!Любишь Python? Зарабатывай на нём!Любишь Python? Зарабатывай на нём!

Как написать игрового бота на Python для Web

Подготовка

Этот туториал, и код в нем, требует установки нескольких дополнительных библиотек для Python. Они обеспечивают обертку Python'а в кусок низкоуровневого C-кода, который значительно упрощает создание и скорость исполнения.

Некоторые библиотеки существуют только под Windows. У них могут быть эквиваленты под Mac или linux, но мы не будем их рассматривать.

Вам нужно скачать и установить следующие библиотеки:

Все представленные библиотеки комплектуются установщиками. Запуск их автоматически установит модуль в директорию и, теоретически, добавит соответствующий . Однако, на практике это происходит не всегда. Если Вы получите сообщение об ошибке после установки, добавьте их вручную в переменные Path.

Последний инструмент это графический редактор. Я предлагаю использовать goalma.org как лучший из бесплатных, но подойдет любая программа с линейками и измерениями в пикеслях.

Мы будем использовать несколько игр в качестве примеров.

Введение

Это руководство написано с целью дать базовое понимание основы разработки ботов для браузерных игр. Подход, который мы собираемся дать, вероятно немного отличается от того, что многие ожидают услышать говоря о ботах. Вместо того, чтобы сделать программу, вставляющую код между клиентом и сервером (как боты для Quake или CS), наш бот будет находиться чисто снаружи. Мы будем опираться на методы Компьютерного зрения и вызовы Windows API для сбора необходимой информации и выполнения движений.

С этим подходом мы теряем часть деталей и контроля, но сокращаем время разработки и получим простоту в использовании. Автоматизирование специфичных игровых функций может быть создано в несколько строк кода, и полноценный бот, от начала до конца (для простой игры) может быть собран за несколько часов.

Когда вы привыкните к тому, что компьютер может видеть, начнете смотреть на игры по-другому. Хороший пример это поиск в играх-пазлах. Обычное решение основывается на ограничении скорости игрока, что заставляет принимать не оптимальные решения. Интересно (и довольно легко) "взломать" их скриптами движений которые не повторить человеку.

Эти боты могут быть также очень полезны для тестирования простых игр - в отличии от реальных игроков, боту не надоест играть один сценарий снова и снова.

Исходники примеров из курса, а также одного законченного бота можно найти здесь.

Шаг 1: Создание проекта

В папке с проектом создайте текстовый файл quickGrab, измените расширение на 'py' и откройте его в редакторе кода.

Шаг 2: Создаем приложение, которое делает скриншот экрана

Начнем работу с изучения базовой функции, которая делает скриншот экрана. Один раз создав и запустив, мы будем строчка за строчкой, как эту функцию, создавать каркас нашего кода.

Вставим в наш файл с проектом следующий код:

Запустив этот код, вы получите скриншот экрана:

screenshot

Данный код забирает всю ширину и высоту области экрана и сохраняет в PNG файл в директорию проекта.

Давайте пошагово разберем код, чтобы понять как это работает. Первые три строки:

называются 'import statements'. Они говорят Pytjon'у какие модули загружать во время выполнения. Это дает доступ к методам этих модулей через синтаксис .

Первый модуль Python Image Library мы установили ранее. Как следует из названия, он дает нам функциональность взаимодействия с экраном на которую ссылается бот.

Вторая строка импортирует модуль операционной системы (OS - operating system). Он дает возможность простой навигации по директориям в операционной системе. Это пригодится, когда мы начинаем размещать файлы в разных папках.

Последний импорт создает модуль работы со временем. Мы используем его для установки текущей даты скриншота, также он может быть очень полезным как таймер для ботов, которые выполняют действие в течение заданного количества секунд.

Следующие четыре строки определяют функцию .

Первая строка определяет имя функции. Пустые скобки означают, что она не принимает аргументов.

Строка 2, присваивает пустое значение переменной "box". Мы заполним это значение дальше.

Строка 3, создает полный скриншот экрана и возвращает RGB изображение в переменную .

Строка 4, может быть немного сложнее если вы не очень хорошо знакомы с тем как работает Time module. Первая часть вызывает метод "save". Он принимает два аргумента. Первый это директория в которую нужно сохранить файл, а второй это формат файла.

Здесь мы устанавливаем директорию вызовом метода . Функция получает текущую директорию в которой выполняется код и возвращает её как строку. Далее мы добавим "+". Сложение нужно использовать между каждым новым аргументом для соединения всех строк вместе.

Следующая часть дает нам простое описание в имени файла. Обратный слеш является экранирующим символом в Python, и мы добавили два, чтобы избежать отмены одного из символов.

Далее идет эта сложная конструкция: str(int(goalma.org())). Она использует встроенные функции Питона. Мы рассмотрим работу этого куска кода изнутри:

возвращает количество секунд с начала Эпохи, тип данных Float (число с плавающей точкой). Так как мы используем дату для именования файлов, мы не можем использовать десятичное число, поэтому мы обернем выражение в , чтобы конвертировать в целое число (Integer). Это делает нас ближе к решению, но Python не может соединить тип Integer с типом String, поэтому следующим шагом мы обернем все в функцию str(). Далее остается только добавить расширение как часть строки и добавить вторым аргументом функции снова расширение: "PNG".

Последняя часть кода определяет функцию , которая вызывает функцию screenGrab(), когда исполняется.

И, наконец, условное обозначение, которое позволяет интерпретатору определить, какую функцию запускать в случае, если файл запущен как основной (а не просто импортирован в другой скрипт). В противном случае, если он загружен как модуль другого скрипта - он только передает доступ к этому методу, вместо выполнения.

Шаг 3: Область видимости

Функция принимает один аргумент, который определяет область видимости. Это набор координат по шаблону (x,y,x,y), где

  1. Первая пара значение (x,y определяет левый верхний угол рамки;
  2. Вторая пара x,y) определяет правый нижний.

Это дает нам возможность скопировать только часть экрана, которая нам нужна.

Рассмотрим это на практике.

Для примера рассмотрим игру Sushi Go Round (Довольно увлекательная. Я Вас предупредил). Откройте игру в новой вкладке и сделайте скриншот использую существующий код screenGrab():

screenshot

Шаг 4: Задание координат

Пришло время задания координат для нашей области видимости.

Откройте скриншот в редакторе картинок.

Координаты (0,0) это всегда левый верхний угол изображения. Мы хотим заполнить X и Y таким образом, чтобы нашему новому скриншоту функция установила координаты (0,0) в крайний левый угол игровой области.

Этому есть две причины. Во-первых, это упрощает нахождение координат, когда мы должны определять координаты относительно игровой области, по сравнению со всем экраном монитора. Во-вторых, захват меньшей части экрана уменьшает нагрузку на процессор. Полноэкранные скриншоты производят довольно много данных, чтобы их можно было циклично повторять несколько раз в секунду.

координаты экрана

Если вы это еще не сделали, включите линейки в вашем графическом редакторе и приблизьте верхний угол игровой области до той степени, пока не увидите рамки пикселей.

Наведите курсор на первый пиксель игровой области и запишите координаты на линейках. Это будут первые два значения для нашей функции. У меня получились значения (, ).

Затем следуйте к нижнему краю и запишите вторую пару координат. У меня получилось (, ). Вместе эти пары дают область с координатами (,,,).

Давайте добавим координаты в код:

На строке 6 мы обновили массив для хранения координат игровой области.

Сохраните и запустите код. Откройте новое сохраненное изображение и вы увидите следующее:

Отлично! Это идеальный снимок игровой области. Нам не всегда будет требоваться эта напряженная охота за координатами. После того, как мы узнаем о win32api, мы рассмотрим более быстрые методы для установки координат, когда нам нужна идеальная точность.

Шаг 5: Перспективное планирование для гибкости

На данный момент, мы жестко прописали координаты по отношению к текущей настройке, исходя из нашего браузера и нашего разрешения монитора. Вообще, это плохая идея - жестко прописывать координаты таким образом. Если, например, мы хотим запустить код на другом компьютере, или, скажем, что-то на сайте немного сдвинет позицию игровой области - нам придется вручную скрупулезно фиксировать все наши координаты заново.

Давайте создадим две новые переменные: x_pad и y_pad. В них будет храниться расстояние между игровой областью и остальным экраном. Это поможет легко портировать код с места на место, так как каждая новая координата будет задаваться относительно двух глобальных переменных, которые мы создадим. Чтобы настроить изменения экрана нужно сбросить эти две переменные.

Так как мы уже сделали измерения, установить отступы для нашей текущей системы достаточно просто. Мы собираемся установить отступы, чтобы хранить положение первого пикселя за пределами игровой площадки. От первой пары координат нашего кортежа вычесть по 1. Получается и

Давайте добавим это в наш код:

Теперь, когда они установлены, мы скорректируем координаты игровой области относительно них.

Для второй пары значений мы собираемся сначала найти разницу между первой и второй парой координат, чтобы получить размер игрового окна, а затем использовать эти значения с нашими переменными.

Для координаты x значение стало - = , а для y стало - =

Сперва это может показаться излишним, но это дополнительный шаг к более легкому обслуживанию в будущем.

Шаг 6: Создание документации

Перед тем как перейти дальше, создадим документацию в начале нашего проекта. Так как большая часть нашего кода будет базироваться на особых координатах экрана и отношении к этим координатам, важно понимать окружение в котором всё будет работать правильно. Например, таких условия как разрешение монитора, браузер, включенная панель инструментов (так как это меняет размер окна браузера), и другие настройки необходимые для центровки игровой области на экране, все это влияет на относительные позиции координат. Документирование всего этого сильно помогает в решении проблем, когда код запускается на разных браузерах и компьютерах.

Напоследок, нужно следить за постоянно меняющимся рекламным пространством на популярных игровых сайтах. Если функция захвата экрана перестает себя вести, как ожидалось, стоит добавить координатам немного смещения.

Для примера, я обычно добавляю подобный комментарий в начало моего кода:

Добавление всей этой информации в начало файла позволяет быстро и легко перепроверить все настройки и выравнивание экрана без необходимости корпеть над кодом, пытаясь вспомнить, где вы сохранили конкретную x-координату.

Шаг 7: Делаем goalma.org удобным инструментом

Мы собираемся клонировать наш проект в этой точке, создавая два файла: один, чтобы писать код нашего бота, другой чтобы хранить функцию снимка экрана. Мы будем делать много снимков, поэтому с отдельным модулем работа пойдет быстрее.

Сохраните и закройте текущий проект.

Создайте копию проекта в этой же папке и переименуйте файл в . Теперь добавление и редактирование всех изменений мы будем производить в goalma.org, а goalma.org оставим исключительно для скриншотов. Только добавим одно финальное изменение: изменим расширение на

Это расширение сообщает Питону, что нужно запускать скрипт без открытия консоли. Двойной клик по файлу и он быстро выполнится в фоне и сохранит скриншот в рабочую директорию.

Держите игру открытой в фоне (не забудьте отключить зацикленную музыку, иначе она сведет вас с ума); мы скоро к ней вернемся. У нас еще есть несколько инструментов для внедрения, прежде чем начать контролировать вещи на экране.

Шаг 8: win32api - краткий обзор

Работать с win32api может быть немного сложно на начальном этапе. Это обертка в низкоуровневый Windows C, которых хорошо задокументирован здесь, но навигация похожа на лабиринт, так что пару раз придется пройти по кругу.

Если при выполнении Вы видите ошибку "ImportError: No module named win32api", значит не установлен этот модуль. Выполните в консоли команду

Прежде чем мы начнем писать код, давайте поближе познакомимся с некоторыми функциями API на которые далее мы будем опираться. После того как у нас появится четкое понимание каждого параметра, мы сможем легко настроить их для наших целей в игре.

Первый параметр dwFlags определяет "действия" мыши. Такие как перемещение, клик, скроллинг и т.п. Следующий список показывает распространенные параметры, используемые для программирования движений.

  • goalma.orgVENTF_LEFTDOWN
  • goalma.orgVENTF_LEFTUP
  • goalma.orgVENTF_MIDDLEDOWN
  • goalma.orgVENTF_MIDDLEUP
  • goalma.orgVENTF_RIGHTDOWN
  • goalma.orgVENTF_RIGHTUP
  • goalma.orgVENTF_WHEEL

Имена говорят сами за себя. Если вы хотите выполнить виртуальный правый клик, нужно отправить параметр в dwFlags.

Следующие два параметра, dx и dy, описывают абсолютную позицию вдоль осей x и y. Пока мы будем использовать эти параметры для программирования движения мыши, они будут использовать систему координат отличную от той, которую мы использовали до этого. Мы зададим нули и будем опираться на другую часть API для движения мыши.

Четвертый параметр это dwData. Эта функция используется тогда и только тогда, когда dwFlags содержит MOUSEEVENTF_WHEEL. В других случаях она может быть опущена или установлена в 0. dwData скорость прокрутки колеса мыши.

Простой пример для закрепления

Если мы представим игру с переключением оружия как в Half-Life 2 (где оружие может быть выбрано вращением колеса) - мы можем использовать эту функцию для выбора оружия из списка:

Здесь мы хотим симулировать скроллинг колеса мыши для навигации по нашему теоретическому списку оружия, поэтому мы вносим в dwFlag. Не нужно указывать позиционирование dx и dy, оставим эти значения 0, и нам нужен один скрол вперед для каждого оружия в списке, поэтому устанавливаем значение для dwData, что соответствует одному скролу мыши.

Как вы видите, работа с mouse_event это просто вопрос подключения правильных аргументов в правильном порядке. Давайте перейдем к более полезным функциям.

Шаг 9: Клики мыши

Мы переходим к созданию трех новых функций. Одна общая функция нажатия левой кнопки мыши, и два обработчика состояний нажатия и отпускания.

Откройте goalma.org в редакторе и добавьте следующее выражение к списку импортов

Как и ранее, это дает нам доступ к содержимому модуля через синтаксис

Далее создадим первую функцию клика мыши

Напомню, что все, что мы делаем здесь это назначаем действие первому аргументу mouse_event. Мы не должны указывать никакую информацию о позиционировании, поэтому мы опускаем параметры координат (0,0), и мы не должны указывать дополнительную информацию, такую как dwData. Функция говорит Питону приостановить выполнение на время указанное в скобках. Добавим это в наш код. Обычно это очень короткий промежуток времени. Без этого клик может получиться до того, как меню обновится.

Мы создали функцию для левого клика. Один раз нажать, один раз отпустить. Мы потратили много времени на нее, но давайте создадим еще две вариации. Это тоже самое, но теперь каждый шаг мы разобьем на отдельную функцию. Это можно использовать когда нам надо удерживать нажатой мышь в течение продолжительного времени (например, для перетаскивания предметов или стрельбы.)

Шаг Простые движения мышью

Все, что остается это движение мыши по экрану. Добавим следующие функции в файл goalma.org

Эти две функции служат совершенно разным целям. Первая будет использоваться для задания движения в программе. Благодаря соглашению об именовании, тело функции делает именно то, что обозначает название . Вызов этой функции устанавливает координаты мыши по заданным (x,y). Обратите внимание, что мы добавили поправки x_pad и y_pad к координатам; это важно делать там, где координаты объявляются.

Вторая функция это простой инструмент который мы будем использовать в интерактивном режиме. Он выводит в консоль координаты текущей позиции мыши. Это сильно ускоряет процесс навигации в меню без необходимости делать скриншот и пользоваться линейками. Мы не хотим постоянно использовать эту функцию, так как некоторая активность мыши будет требовать точного позиционирования, но там где это возможно, это хорошо сэкономит нам время.

На следующем шаге мы применим эти техники для начала навигации в игровом меню. Но сначала надо удалить текущий контент у в goalma.org и заменить его на тот, который мы написали. На следующем шаге мы будем работать с интерактивным режимом , поэтому функция нам пока не понадобиться.

Шаг Навигация в меню

В этом и в следующих нескольких этапах мы попытаемся собрать координаты для разных событий используя метод get_cords(). Используя его мы сможем быстро построить код для таких вещей как навигация по меню, очистка столов, приготовление еды. После сбора мы встроим их в логику бота.

Давайте начнем. Сохраните и запустите код в Python Shell. С тех пор как на прошлом шаге мы заменили тело функции на , вы должны увидеть пустое окно после запуска Shell.

Теперь прежде чем перейти к игровой части, нужно пройти 4 начальных меню.

  1. Кнопка "Play"
  2. Кнопка "continue"
  3. Пропустить обучение "skip"
  4. Кнопка "continue"

Мы должны получить координаты каждой кнопки и добавить их в новую функцию . Расположите на экране Shell так, чтобы была видна игровая область. Нужно поставить мышь на кнопку, координаты которой нужно получить и выполнить в Shell функцию get_cords(). Убедитесь, что активным окном является Shell. Мы получим в Shell'е координаты текущей позиции мыши. Повторите это для остальных трех окон.

Оставьте Shell открытым и настройте экран так, чтобы видеть IDLE редактор. Добавим функцию startGame() и заполним новыми координатами.

Теперь у нас есть компактная функция, которую можно вызывать на старте каждой игры. Она устанавливает курсор на каждую позицию в меню, которую мы заранее определили и кликает. говорит Питону остановить выполнение на 1/10 секунды между каждым кликом, чтобы меню успевало обновляться между кликами. Сохраните и запустите код.

У меня, как у медленного человека, прохождение меню вручную занимает больше секунды, тогда как наш бот может сделать это в течение примерно 0,4 секунд. Совсем неплохо!

Шаг Зададим координаты еды

Давайте повторим процесс для каждой кнопки.

меню с едой

С помощью get_cords(), соберите координаты еды из меню. Еще раз в Python Shell напишите get_cords(), наведите мышь на еду и выполните команду.

Как вариант, для ускорения работы, если у вас есть второй монитор или вы можете организовать расположение таким образом, чтобы видеть браузер и окно Shell, можно не вводить каждый раз get_cords(), а сделать простой цикл . Используйте метод goalma.org() чтобы успевать перемещать мышь между итерациями цикла.

Нам нужно создать новый класс , чтобы хранить в нем собранные координаты. Возможность вызова через дает большие преимущества, так как можно передававть координаты прямо в . Как вариант, можно хранить всё в словарях, но я нахожу синтаксис классов более удобным.

Мы будем хранить много наших координат в этом классе, там будет некоторое дублирование, поэтому добавив префикс 'f_' мы будем знать, что это ссылка на еду, а не, скажем, на заказ еды по телефону.

Продолжим добавлять координаты.

Шаг Координаты пустых мест

Каждый раз после еды посетители оставляют пустые тарелки, на которые нужно кликать, чтобы убрать. Поэтому нам нужно знать расположение тарелок.

Повторите действия из предыдущих шагов, чтобы получить координаты тарелок. Сохраните их пока в закомментированной строке.

Осталось всего несколько шагов до действительно интересных штук.

Шаг Координаты телефона

Итак, это будет последняя часть координат. Здесь понадобиться намного больше действий, поэтому вы можете сделать это вручную функцией , вместо цикла. Мы собираемся прокликать всё меню телефона, чтобы получить координаты каждого пункта.

Здесь есть сложности, так как нам нужно иметь достаточно денег, чтобы купить что-то. Поэтому нам нужно сделать несколько порций суши, прежде чем вбивать координаты телефонных сделок. Нам придется сделать два суши рола , чтобы купить немного риса.

Есть шесть меню, через которые нам надо пройти.

  1. Телефон
  2. Начальное меню
  3. Начинки
  4. Рис
  5. Доставка

Нам нужно получить координаты всех, кроме Саке (можете её тоже добавить, если хотите. На мой взгляд бот отлично работает и без нее).

Окей! Мы наконец собрали все необходимые координаты. Давайте создадим что-нибудь полезное!

Шаг Убираем со стола

Мы используем координаты собранные ранее для создания функции clear_tables().

Как вы можете видеть, это выглядит более менее похоже на нашу прошлую функцию startGame(). С одним небольшим отличием: нет функции между кликами. Нам не нужно ждать обновления меню, поэтому не нужно ждать задержку между кликами.

Однако, у нас есть функция в самом конце. Хотя это и не обязательно, лучше добавить паузы в выполнение кода, чтобы была возможность вручную завершить цикл, если это потребуется. В противном случае скрипт будет менять позицию мыши снова и снова и вы не будете в состоянии переместить фокус на Shell, чтобы остановить сценарий. Это прикольно первые два или три раза, но быстро теряет свое очарование.

Шаг Создание суши

Сначала нужно понять как сделать суши. Кликните на книгу рецептов, чтобы открыть инструкции. Все виды суши, встречающиеся в игре, могут быть найдены на страницах этой книги. Оставлю первые три ниже, остальные вы можете найти в книге по ходу игры.

Теперь давайте создадим функцию, которая будет принимать в виде аргумента тип суши и затем собирать требуемые ингредиенты для переданного значения.

Эта функция такая же как и все остальные, но с одним небольшим отличием: мы не передаем координаты непосредственно, а вызываем их в качестве атрибутов класса .

Функция вызывается в конце каждого приготовления. Она кликает по циновке, чтобы завернуть суши, которое мы приготовили. Давайте зададим её:

Давайте кратко пройдемся по функции . Мы обращаемся к первому значению через добавление [0] в конце атрибута. Напомню, что это координата x. Для клика по циновке нам необходимо добавить небольшое смещение по оси х, и мы прибавим 40 к значению координаты x и передадим в y. Это сдвинет нашу позицию по x достаточно, чтобы активировать циновку.

Обратите внимание, что после вызова у нас идет длинный . Циновка будет закручиваться и ингредиенты будут не доступны для клика, поэтому придется подождать конца анимации.

Шаг Навигация в телефонном меню

В этом шаге мы зададим все точки для подходящий пунктов меню, координаты которых были оставлены для этого момента. Эта часть программы которая будет обернута и контролируема логикой бота. Мы вернемся к этой функции, после того как обзаведемся несколькими новыми техниками.

Краткое введение в компьютерное зрение

Сейчас в нашем распоряжении имеются очень интересные куски кода. Давайте рассмотрим как научить компьютер "видеть" события. Это очень увлекательная часть процесса.

Еще одна сторона построения бота заключается в том, что в конечном итоге бот может предоставить нам достаточное количество информации, что дальнейшем облегчит работу. Например, в случае суши-бота, как только мы пройдем первый уровень, бот будет предоставлять нам достаточное количество данных о том, что происходит на экране, и все что нам останется сделать это объяснить ему как реагировать на эти новые данные.

Другая большая часть в написании бота это обучение игре. Понимание какие значения нужно отслеживать в игре, а какие можно игнорировать. Например, можно не отслеживать деньги в кассе. Это то, что в конечном счете не имеет отношения к боту. Все, что ему надо знать это достаточно ли еды, чтобы продолжать работать. Таким образом, вместо того, чтобы мониторить количество денег, он просто проверяет, может ли бот что-то купить независимо от цены, потому что в игре это вопрос лишь нескольких секунд. Поэтому если бот не может что-то купить, он просто ждет несколько секунд.

Это подводит нас к финальной точке. Это брутфорс против элегантного решения. Алгоритмы зрения требуют значительного процессорного времени. Проверка нескольких точек во многих разных областях игровой области могут сильно снижать производительность. Таким образом все сводится к вопросу "должен бот узнать о том что что-то случилось или нет?"

Например, посетитель может проходить через четыре состояния: отсутствует, ожидает, ест и закончил есть. Когда закончил есть, он оставляет пустую тарелку. Мы могли бы затратить ресурсы на проверку всех мест просмотрев их, а затем кликнуть напротив ожидаемой тарелки (что может приводить к ошибкам, так как тарелки мигают, давая ложный сигнал). Или можно убирать их простым перебором, прокликивая все места через каждые несколько секунд. На практике прокликивание оказывается таким же эффективным, как и элегантное решение, позволяющее определить состояние клиента. Прокликать шесть мест занимает доли секунды, в то время как захват и обработка шести изображений сравнительно медленный способ. Мы можем использовать сэкономленное время для других более важных задач, связанных с обработкой изображений.

Шаг Импорт библиотек Numpy и ImageOps

Добавим следующие выражения импорта

ImageOps это еще одна библиотека для работы с изображениями Python'а. Она используется для выполнения операций над изображениями (таких как перевод в черно-белый формат).

Я кратко поясню вторую строку для тех, кто близко не знаком с Питоном. Стандартное выражение импорта загружает пространство имен модуля (коллекцию имен переменных и функций). Таким образом, для доступа к элементам из области видимости мы используем синтаксис . Однако, используя выражение мы наследуем имена в локальную область видимости. То есть синтаксис больше не нужен. Это не верхний уровень, поэтому мы можем использовать их как встроенные функции Питона, как или . Импорт Numpy таким способом дает нам возможность просто вызвать вместо goalma.org().

Символ * означает импорт всего из модуля.

Шаг Создаем компьютерное зрение

Первый метод сравнивает значения RGB у пикселей с ожидаемым значением. Этот метод отлично подходит для статичных объектов, таких как меню. Так как нужно иметь дело с конкретными пикселями, то метод не слишком надежен для движущихся объектов. Однако, это варьируется от случая к случаю. Иногда это отличная техника, а в другой раз приходится искать другой метод.

Запустите Sushi Go Round в браузере и начните новую игру. Откройте телефонное меню. Можете пока не обращать внимание на посетителей. Вы начинаете игру без денег, поэтому все пункты меню будут серыми как показано ниже. Это и будут те значения RGB, которые мы будем проверять.

В перейдите к функции . Нужно внести следующие изменения:

Мы сделали два небольших изменения. Во—первых, мы закомментировали строку, которая сохраняет скриншот. Во—вторых, на шестой строке мы возвращаем объект с изображением после выполнения функции.

Сохраните и запустите код.

Во время того как открыто телефонное меню и все пункты серые, выполните следующий код:

Это сохранит скриншот, который мы сделали с помощью функции в переменную . Теперь мы можем вызвать функцию чтобы получить данные о заданных пикселях.

Теперь нам надо получить RGB значения для каждого серого элемента меню. Они нужны для сравнения со значениями, которые бот будет сравнивать с теми, которые он будет получать вызывая .

Мы же имеем необходимые координаты после выполнения предыдущих шагов, поэтому просто передадим их в качестве аргументов в функцию и запишем результаты.

Если мы добавим эти значения в функцию , чтобы знать доступна покупка в данный момент или нет.

Мы передаем имя ингредиента в функцию . Серия выражений if/else получает переданный параметр и дает соответствующий ответ. Каждая ветка следует одинаковой логике, поэтому мы рассмотрим только одну.

Первое, что мы должны сделать это кликнуть на телефон и открыть нужное меню. В этом случае меню с рисом.

Далее мы делаем скриншот области и вызываем , чтобы получить RGB-значение пикселя у координат . Мы сравниваем их с RGB-значением пикселя, полученного до этого на неактивном элементе. Если мы получаем в результате сравнения значение , значит кнопка больше не серая и у нас достаточно денег для покупки. Соответственно, если получаем , значит не можем себе это позволить.

Если у нас достаточно денег, мы просто проходим через оставшиеся этапы, необходимые для покупки.

Наконец, если нам не хватает денег, то мы говорим боту закрыть меню, подождать секунду и повторить все сначала. Обычно это вопрос секунд, когда нам снова становится доступна покупка. Довольно просто добавить дополнительную логику, чтобы бот мог решить, нужно ли продолжать ждать или заняться в это время чем-то полезным и вернуться позже.

Шаг Следим за ингредиентами

Окей, до этого момента мы медленно продвигались шаг за шагом. Перепишем часть нашего кода, точнее внешний объект, обеспечивающий входящие данные и принятие решений посредством логики, которая может запускаться сама.

Мы должны придумать способ хранить информацию как много ингредиентов у нас сейчас на руках. Мы будем запрашивать экран в определенной области, или усредняя каждую ячейку ингредиента (к этой технике мы вернемся позже), но в дальнейшем, простой и наиболее быстрый способ просто хранить все элементы в словаре.

Количество каждого ингредиента остается постоянным на старте каждого уровня. Всегда начинаем с 10 обычных ингредиентов (рис, нори, икра), и по 5 дефицитных ингредиентов (креветки, лосось, угорь).

Начальные ингредиенты

Давайте добавим информацию о них в массив.

Ключи массива содержат имена ингредиентов, по ним мы получаем доступ к значениям.

Шаг Добавим отслеживание продуктов в код

Каждый раз, когда мы готовим, мы расходуем ингредиенты. И также пополняем их, когда делаем покупки. Давайте немного расширим нашу функцию

Теперь каждый раз при приготовлении Суши, мы уменьшаем значения наших ингредиентов на соответствующие значения. Теперь дополним код в функции

Шаг Проверка запасов еды

Теперь когда функции и могут менять количество ингредиентов, нам нужно создать функцию, которая будет отслеживать что количество какого-то ингредиента стало ниже критического уровня.

Мы будем циклом обходить пары ключ:значение в массиве с запасами ингредиентов. Если нори, риса или икры останется меньше 4, вызывается функция buyFood(), параметром в которую передается имя ингредиента.

Шаг Перевод RGB значений - Установка

Для того, чтобы двигаться дальше, мы должны получать информацию о том, какой тип суши запрашивает клиент. Сделать это с помощью функции было бы достаточно тяжело, так как нам пришлось бы искать область с уникальным значением RGB для каждого вида суши для каждого посетителя. Кроме того, для каждого нового типа суши, вам придется вручную осмотреть его, чтобы увидеть, есть ли у него уникальный RGB, который не найден ни в одном из других типов суши. Это значит, что нам пришлось бы хранить 6 мест, по 8 типов суши. Это 48 уникальных координат.

Очевидно, нам нужен метод попроще.

Метод номер два: усреднение изображения. Этот способ работает с набором RGB-значений, вместо конкретного пикселя. Для каждого скриншота, переведенного в оттенки серого, и загруженного в массив, мы просуммируем все пиксели. Эта сумма обрабатывается также как значение RGB в методе .

Гибкость этого метода в том, что, когда он настроен, от нас больше ничего не требуется. По мере ввода новых суши, их значения RGB суммируются и выводятся для нашего использования. Нет необходимости искать конкретные координаты с помощью .

Тем не менее, для этого метода требуется настройка. Нам нужно получать скрин только той области, в которой отображается желаемое суши конкретного клиента, а не всего игрового окна.

Найдите уже написанную функцию и скопируйте ее рядом. Переименуйте копию в , и внесите следующие изменения:

На второй строке мы переводим скриншот в оттенки серого и записываем в переменную . Такой скриншот позволяет работать с ним намного быстрее, так как вместо 3 значений Красного, Зеленого и Голубого, каждый пиксель имеет только одно значение от 0 до

На третьей строчке мы создаем массив значений цветов использую PIL метод getcolors() и записываем в переменную .

На четвертой строке мы суммируем все точки и выводим их в консоль. Это число по которому мы будем сравнивать изображения.

Шаг Зададим области для скринов заказов

Начните новую игру и дождитесь когда все посетители рассядутся по своим местам. Сделайте скрин двойным кликом по .

Области с заказами

Нам нужно задать ограничивающие области внутри каждого из этих спич-баблов (белые облака с рисунком суши). Приблизьте из в редакторе так, чтобы было видно пиксели:

Области с заказами

Для каждого спич-бабла мы должны быть уверены что верхний левый край начинается в одном и том же месте. Для этого отступим два пикселя от внутреннего края спич-бабла. Первый белый пиксель на второй ступеньке будет началом отсчета.

Области с заказами

Для создания пары координат, отсчитайте 63 по оси x и 16 по оси y. Это даст подобный прямоугольник:

Области с заказами

Не беспокойтесь о том, что не весь рисунок с суши попал в прямоугольник. Когда мы просуммируем все пиксели, даже небольшие изменения в одном пикселе повлияют на сумму, и мы сможем отличить заказ посетителя.

Приступим к созданию 6 новых функций, каждая будет уточнением функции и будет передавать аргументом координаты спич-баблов. Как только закончим, создадим функцию, запускающую их все сразу для тестирования.

Отлично! Много кода, но это только вариации функции . Теперь нужно перейти в игру и протестировать. Нужно убедиться, что не зависимо от того в каком спич-бабле находится суши, один и тот же заказ отображает одну и ту же сумму.

Шаг Создаем массив с типами Суши

Как только Вы убедились, что каждый тип суши дает одинаковое значение суммы пикселей, запишите эти суммы в массив:

Здесь значение стоит на месте ключа потому, что по нему будет осуществляться поиск.

Шаг Создаем массив мест без спич-баблов

Для работы нам нужны значения сумм скриншотов мест под спич-баблами, чтобы понимать что посетитель отсутствует в данном месте.

Нужно начать игру и выполнить функцию до того как придет первый посетитель. Полученные значения запишем в массив .

Шаг Соединяем все вместе

Время окончательно передать контроль нашему боту. Напишем скрипт, который позволит ему реагировать на клиентов, готовить еду и пополнять запасы.

Основа логики будет следующая: Проверка мест > Проверка заказов > Если не хватает ингредиентов, то купить > почистить столы > Повторить сначала

Первое что мы делаем — это проверяем запасы. Далее делаем скрин позиции заказа первого посетителя и записываем в s1. После этого проверяем скрин на неравенство пустому месту. Если они не равны, значит у нас есть посетитель. Далее проверяем массив чтобы определить какой заказ сделал посетитель и передаем этот аргумент в функцию .

выполняется через проверку каждых двух мест.

Теперь надо это зациклить.

Шаг Главный цикл

Мы создаем цикл. Так как мы не задаем никакого условия выхода из цикла, то чтобы завершить игру, нужно в консоли нажать CTRL + C.

Вот и все! Обновите страницу, дождитесь загрузки игры и запустите бота!

Бот немного неуклюжий и нуждается в доработках. Но это отличный скелет для того чтобы продолжить экспериментировать!

Рейтинг: 4,8 (41 оценка)

Скриншоты

Описание приложения

Категория: Образование

Категория: Книги

О чём материал? Создание игр, программирование с нуля: для детей и подростков, а также их родителей и учителей! Материал для всех, кто волею судеб вынужден заняться программированием. Или просто по жизни творческий, увлекающийся человек, которому интересно изучать что-то новое и реализовывать себя в современности. И не забываем: изучение языков программирования и алгоритмов повышает логику и интеллект. Пишем игры: изучаем программирование на Python на примере написания простых, но демонстрирующих возможности программирования игр. Почему именно этот учебник? Я уже почти два десятка лет работаю преподавателем информатики и сталкиваюсь с одной иногда раздражающей вещью. Большинство материалов, призванных "научить программированию", на самом деле не учат, а являются своеобразными справочниками по языку: синтаксис, функции, результат. Согласитесь, даже если мы выучим весь русско-английский словарь, то на английском не заговорим. Потому что для разговора нужно знать ещё тысячу тонкостей: времена, склонения, использование местоимений и предлогов и прочее. В этом учебнике я рассказываю не только о языке Python, но и веду читателя путём рассуждений, логический умозаключений, отвечая не только вопрос "С помощью чего?", но и "Для чего?" и "Почему?" Вся теория сразу же найдёт отражение в практике. СТРУКТУРА МАТЕРИАЛА: - базовые сведения о языке Python: где скачать, как установить, каким образом пользоваться, что делать для получения результата, реализация простейших алгоритмов, некоторые хитрости и тонкости, словом, дружеские советы; - архитектура игр: на каких принципах строятся игры, что нужно предусмотреть, как выстроить систему получения и обработки данных; - игры: в этой части представлено четыре игры: 1. «Угадай число». Цель игры: развлечение и анализ числовых рядов. Подойдёт для детей, которые учатся считать. Вы, если вы родитель, можете написать игру конкретно для своего ребёнка, заложив в программу особенности и пожелания. Например, выбрать диапазон чисел или установить правила счёта. 2. «Учись считать». Цель игры: развитие навыков счёта, сложение, вычитание, умножение и деление. Работа со временем (на скорость). Подойдёт вообще всем - и даже взрослым, которые желают повысить навык и увеличить скорость правильного счёта "в уме". 3. «Казино ». Цель игры: антипропаганда азартных игр. Когда вы увидите алгоритм, на котором пусть даже приблизительно строится большинство азартных игр, различных «одноруких бандитов», казино и прочего - отобьёт надежду на получение прибыли напрочь. Когда вы своими руками напишите алгоритм и, проигрывая виртуальные деньги (которых сможете поставить себе сколько угодно!), поймёте, что выиграть попросту нельзя, сразу интерес к азартным играм пропадёт. Рекомендовано для подростков с надеждой внезапно обогатиться на как минимум «миллион долларов» и жить припеваючи. 4. «Ипподром». Цель игры: изучение влияния скрытых параметров на обработку данных, практическое умение разработать и реализовать системную взаимосвязь между изменением видимых данных и случайными значениями. Побочный эффект: антипропаганда азартных игр и просто интересно :) Все представленные алгоритмы направлены на воспитание: - понимания внутренних принципов работы процессора; - практического умения создавать и записывать алгоритмы на конкретном языке программирования; - практического умения реализовывать обработку данных с помощью инструментов Python; - и популяризацию творческого, интересного и созидательного времяпровождения. Вы найдёте: - систематизированную информацию по базовым конструкциям языка; - базовые алгоритмы обработки данных; - практические советы и замечания, выработанные на основе многолетнего опыта; - примеры рабочего кода; - взгляд на архитектуру современных игр; - основные этапы проектирования алгоритмов для игр. Пожалуйста, если вам понравилось приложение, - поставьте оценку и напишите комментарий. Это очень мотивирует на продолжение работы :)

Что нового

- критическое обновление системы подтверждения платежа. Обязательно обновите приложение, иначе что-то может работать некорректно и непредсказуемо, как вся наша жизнь :)

История версий

Оценки и отзывы

  • Константин

    1 звезда

    28 июн

Все отзывы

РазработчикViktor TrofimovЕще приложения

nest...

казино с бесплатным фрибетом Игровой автомат Won Won Rich играть бесплатно ᐈ Игровой Автомат Big Panda Играть Онлайн Бесплатно Amatic™ играть онлайн бесплатно 3 лет Игровой автомат Yamato играть бесплатно рекламе казино vulkan игровые автоматы бесплатно игры онлайн казино на деньги Treasure Island игровой автомат Quickspin казино калигула гта са фото вабанк казино отзывы казино фрэнк синатра slottica казино бездепозитный бонус отзывы мопс казино большое казино монтекарло вкладка с реклама казино вулкан в хроме биткоин казино 999 вулкан россия казино гаминатор игровые автоматы бесплатно лицензионное казино как проверить подлинность CandyLicious игровой автомат Gameplay Interactive Безкоштовний ігровий автомат Just Jewels Deluxe как использовать на 888 poker ставку на казино почему закрывают онлайн казино Игровой автомат Prohibition играть бесплатно