Я пишу текстовую игру на Python: доработанный прототип
В новом выпуске блога о программировании я привожу в порядок прототип, созданный в предыдущем выпуске.
Предыдущий выпуск
В прошлый раз мы довели текстовую игру LAM-40 до первого рабочего прототипа, который, правда, ещё далёк от финальной версии. В конце материала я обозначил главные недостатки этого прототипа, и сегодня мы справимся с некоторыми из них. Во-первых, сейчас весь код содержится в одном файле. Это непорядок: реплики бюрократов лучше хранить в другом месте, как и основную логику игры. Во-вторых, нынешний прототип плохо выглядит: ориентироваться в тексте, который выводит игра, неудобно. Сегодня мы не будем кардинально менять функционал, а просто доведём до ума то, что делали в предыдущий раз.
ПРИМЕЧАНИЕ: весь код приводится для Python версии 3.0 и старше, а потому может не работать на более старых версиях.
Для начала давайте посмотрим, какой код остался с прошлого раза.
Я сделал упор на реструктуризацию кода и внешний вид игры: первое ни в коем случае нельзя откладывать на потом, когда кода станет больше, а за вторым лучше начать следить как можно раньше. В итоге вместо одного файла стало три файла. В одном из них, text.py, сейчас хранится текстовая информация: в частности, реплики бюрократов. Разбирать там особо нечего: это просто набор списков, который не изменился с предыдущего раза, но если хотите на него посмотреть, то вот он. А мы же пока перейдём в другой новый файл, game.py, где содержится класс Game — основная логика игры.
Строка 1: в начале файла я добавил комментарий между тройными кавычками, также известный как docstring. Это очень полезная практика, которой всегда нужно следовать: она не только облегчает чтение кода другим людям, но и помогает тестировать программу с помощью doctest (этим мы займёмся на последних стадиях разработки, хотя многие советуют прописывать тесты с самого начала). Кроме того, когда вы пользуетесь функцией help(), выводящей описание того, как работает тот или иной объект языка, она берёт описание как раз из docstring.
Строки 3–9: новые модули! Во-первых, модуль os, который даёт доступ к возможностям операционной системы. Мы воспользуемся им для написания функции очистки экрана. Во-вторых, с помощью конструкции from — import мы импортируем в текущий файл один класс из другого модуля или файла. В нашем случае это класс Bureaucrat из файла bureaucrat.py и класс Terminal из модуля blessings, предназначенного для форматирования текста. Мы создаём образец класса Terminal и присваиваем его переменной с коротким названием t — её будет удобно вставлять в код.
Строки 12–15: инициализация класса — это основная логика игры, которая в предыдущей версии находилась внизу файла bureaucrat.py. В неё добавилась функция clear_screen(), очищающая экран (не забываем о ключевом слове self внутри класса). Определение функции находится на строках 25–29. Функция смотрит на то, в какой операционной системе находится пользователь. Если в Windows, обозначенной как 'nt', то выполняется специфичная для неё команда 'cls', которая становится атрибутом функции os.system(). Ветка else и команда 'clear' предназначены для Mac и Linux.
Строка 16: выводим в начале игры её название и версию. Для того чтобы название было подчёркнутым, пользуемся функцией underline(), которая входит в класс Terminal модуля blessings. Её атрибутом становится string, внутри которого есть символ новой строки \n, принятый во многих языках программирования. Он даёт интерпретатору знать, что следующие за \n символы нужно выводить с новой строки.
Строки 31–38: функции act() и react() переехали из bureaucrat.py в game.py, потому что не относятся напрямую к действиям бюрократа. Внутрь неё я поместил все доступные на сегодня действия, включая проигнорированные в предыдущей версии ожидание и выход.
Далее мы используем цикл for — in, о котором я до этого, если я правильно помню, не рассказывал. Цикл for — in проходит столько итераций, сколько элементов находится в объекте, который размещается после ключевого слова in. В нашем случае это список действий actions. Функция enumerate() используется для того, чтобы на каждом этапе цикла в памяти компьютера был не только элемент списка (я назвал временную переменную с ним action, но вообще имя можно задавать более-менее свободным образом), но и его порядковый номер (number). Иначе говоря, цикл for — in означает следующее: «для каждого элемента element в объекте elements выполни блок кода, находящийся после двоеточия».
Мы используем цикл с функцией enumerate для того, чтобы вывести перечисление всех доступных действий, которые находятся в переменной actions, ставшей со времён предыдущей версии не одним string'ом, а списком string'ов.
В программировании отсчёт начинается с нуля (то есть порядковый номер '[A]sk' — 0, '[B]ribe' — 1 и так далее), а потому, чтобы первым порядковым номером не был 0, с самого начала отсчёта к number нужно прибавлять единицу. Также number нужно превратить из типа данных integer в тип данных string с помощью функции str(). Мы уверены на 100%, что каждая переменная number будет сначала принадлежать типу integer, а потому никаких дополнительных проверок не делаем. Наконец, мы выводим каждый элемент списка actions как пункт меню, используя функцию print(). Внутри неё мы соединяем переменные типа string с помощью символа +. Именно для этого мы и переводили на каждой итерации цикла переменную number в тип данных string.
Строки 39–79: мы используем на символе, который вводит игрок, функцию lower(), чтобы строчные буквы становились прописными, — так вводить команды проще. Соответственно, во всём остальном файле я поменял в условиях строчные буквы на прописные, везде проставил одинарные кавычки, чтобы соблюдать единство стиля, а также добавил возможность ввода не только первых букв слов-действий, но и номеров, под которыми они стоят в меню. Внутри ветки выхода из игры я использую функцию clear_screen(), чтобы на выводимом после игры экране было только сообщение с благодарностью — без всякого мусора. Завершает файл создание образца класса Game, благодаря чему игра начнётся сразу после того, как мы запустим интерпретатор.
Файл bureaucrat.py стал значительно меньше после того, как я разнёс его составляющие по другим двум файлам, но без изменений не обошлось.
Строки 1–8: помимо модуля blessings, уже описанного в комментариях к файлу game.py, я также импортировал содержимое файла text.py — иначе бюрократы не будут знать, что им говорить.
Строки 13–23: в инициализацию класса Bureaucrat я добавил атрибут gender. Для выбора атрибута используется функция random() из модуля random, случайным образом дающая число типа float (то есть со множеством знаков после запятой) от 0 до 1. Из условной конструкции выходит, что с вероятностью 49,5% бюрократ окажется женщиной, с вероятностью 49,5% — мужчиной, а в каждом сотом случае бюрократ будет входить в число людей, объединённых под термином intersex. Ранги и действия я поместил прямо как аргументы функции random.choice(), чтобы код был лаконичнее.
Строки 25–43: наконец, я сделал с помощью соединения стрингов, функций из модуля blessings и специальных символов так, чтобы основные действия бюрократа отображались красивее. Важные характеристики ранга и настроения выделяются жирным, а где надо, используется символ новой строки \n.
К сожалению, курсив и некоторые другие виды форматирования текста из blessings не заработали в «Терминале» Mac OS X. Ну а ещё в этих строках вы можете найти отсылки к угадайте какой игре!
Вот как выглядит наша игра в окне терминала сейчас. Намного лучше того скопища нагромождённого текста, что был там раньше.
Хотя мы решили лишь малую часть стоящих перед нами проблем, на текущей стадии этот прототип уже годится для уровня proof of concept. А значит, в следующий раз я не только продолжу решать задачи, обозначенные в предыдущем выпуске, но и напишу ёмкий дизайн-документ, по которому можно будет ориентироваться на предстоящих этапах разработки. Если вам что-то непонятно, пишите комментарии под материалом и в социальных сетях — буду рад и любым другим отзывам. Если вы более опытный в программировании человек, чем я, то с удовольствием выслушаю содержательную критику. Спасибо и до следующего раза!
Смотрите также:
Документация модуля Blessings
Полные курсы Python на Codeacademy и Treehouse*
* — платные курсы, но есть пробный период
Развитие программистского мышления на Udacity
Учебники по Python на LearnPython.org и Python Course
Комментарии
Подписаться