Как сделать игру города на python

от admin

Игра в города на python

Учу python "с нуля" на примере создания игры "В города".
Берутся пока только города России.
Застрял на нескольких проблемах:

# 1) В списке все города начинаются с заглавных букв.
При вводе игроком города с прописной буквы выдаёт ответ, что такого города не существует;

# 2) На букву "Й" есть всего один город — Йошкар-Ола. то есть если в игре первый раз город заканчивается на "Й", то соперник пишет "Йошкар-Ола" (при этом если написать "Йошкар-ола", "йошкар-ола", "йошкар-Ола" или "ЙОШКАР-ОЛА" , то такого города не существует).
А когда второй раз какой-либо город заканчивается на "Й", то ничего уже ввести нельзя, так как единственный город на "Й" — Йошкар-Ола — уже использовался в игре.
Надо сделать так, чтобы после использования города "Йошкар-Ола" далее в игре допускалось использование городов на букву "И" при необходимости писать город на "Й";

# 3) Нет городов на "Ё". Необходимо допустить, чтобы при необходимости написания города на "Ё" можно было писать города на "Е";

# 4) Нет городов на "Ы", "Ь" и "Ъ". Необходимо реализовать правило, при котором если город заканчивается на "Ы", "Ь" и "Ъ", то следующий город должен начинаться не на последнюю букву предыдущего города, а на предпоследнюю.

Строим города по клику мыши с Houdini и Python

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

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

В этом материале я разберу базовую настройку инструмента City Builder в Houdini, который может строить города простыми кликами мышью. Обратите внимание, что он работает только внутри Houdini с использованием Python Viewer States.

Референс

Самым большим вдохновением для меня был Оскар Штольберг. Его работа впечатлила, и заставила задуматься, возможно ли повторить такое в Houdini. Мою попытку также можно считать за доказательство того, что какую-либо идею вполне реально воспроизвести и в другом софте.

Начальный сетап

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

Начните с circle node и разместите под ним instant mesh node (он из инструментов Labs, поэтому убедитесь, что они у вас установлены).

После этого разместите extrude node — позже он будет использоваться для выдавливания примитивов, выбранных мышью.

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

Python Viewer States

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

Создайте новый viewer state и начните с пустого шаблона. Это сгенерирует только тот фрагмент кода, который действительно нужен.

Есть несколько вещей, которые нужно добавить. Можно разделить их на 2 части:

  • Получение геометрии для просмотра при щелчках мыши.
  • Получение примитива при щелчке мышью.

Здесь хранится текущая геометрия в самом self.geometry. Делается с помощью node.geometry().

Теперь есть связь с геометрией.

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

В начале события мыши создайте переменные для работы. Затем получите пересечение с геометрией с помощью функции GeometryIntersector и используйте self.geometry.

С этого пересечения вы получите нужную информацию, узнайте и напечатайте примитивное число.

Если все сделано правильно, то получится это:

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

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

Детализация

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

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

Граница, которая скошена и развернута с UV.

Здесь очень важна производительность. Чтобы инструмент работал быстро и при нажатии дом мгновенно появлялся — придется заняться оптимизацией. Для этого вы можете попытаться использовать минимальное количество loop nodes и boolean nodes в сети.

Будущее инструмента

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

Python. Игра в города

Это просто, открываем Вики. Остается сделать следующее:

  1. скачать страницу
  2. спарсить города из таблицы
  3. сохранить в файл

Парсим города в файл

Теперь у нас есть cities.txt в котором 1117 городов.

Читать:
Как скопировать проект в intellij idea

Что будем делать?

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

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

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

Также нужно произвести некоторую оптимизацию имен городов: перевести все имена в нижний регистр и заменить “ё” на “е”.

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

Кодируем

Для начала реализуем метод, который будет приводить имя города в общий вид

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

Загружаем список городов

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

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

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

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

  1. Получаем ввод от пользователя. char or “any” потому что char изначально будет None, когда игра только началась.
  2. нормализуем строку
  3. создаем словарь который будет передан как **kwargs в методы проверки
  4. производим все проверки и ожидаем что все будут True
  5. если не все проверки были пройдены, то повторяем все еще раз

check_list — это список содержащий ссылки на функции которые принимают первым аргументом город и что-то что им нужно для выполнения проверки. Таких метода у нас 3

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

Декоратор check_point позволяет зарегистрировать любой метод как метод проверки города от пользователя, для его работы нужно объявить список, в котором будут все проверки и обернуть требуемые функции в декоратор.

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

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

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

И затем выбрать букву на которую должен начинаться следующий город

city[::-1] — позволяет проитерировать название города в обратном порядке, то же самое делает функция reversed(). Блок else у for выполнится только в том случае если не сработает break, что невозможно.

Теперь можно реализовать функцию которая будет описывать ход компьютера

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

И осталось реализовать точку входа

Функция cycle из модуля itertools принимает в качестве аргумента итерируемый объект и позволяет бесконечно его итерировать. Таким образом мы на каждую итерацию меняем функцию *_point, описывающую кто делает ход, так мы реализуем пошаговую логику игры. Сначала будет выполнен метод user_point, потом ai_point и так по кругу.

Игра Города¶

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

Задание¶

Реализовать версию, в которой будет возможность вводить любые слова и будет проверка на совпадение первой и последней буквы

Сделать так чтобы можно было вводить слова в любом регистре

Добавить проверку на существование города, который введёт пользователь

Сделать чтобы города не могли повторяться

Добавить графический интерфейс с помощью библиотеки easygui

Добавить возможность играть с компьютером. Для этого потребуется библиотека random и функция choice

Похожие статьи