Сводный текст домашних заданий

План

  1. Зарегистрируйте свой репозиторий для решения задач по практикуму так, как это было в прошлом семестре ( /!\ это не репозитория для Д/З по лекциям)

  2. <!> Задача_1: напишите программу-просмотрщик git-репозитория, оформите её функциональность в виде нескольких (минимум четырёх) коммитов. Коммиты должны соответствовать добавлению к программе следующих возможностей: (примеры показывают формат вывода)

    1. Первый параметр (sys.argv[1]) — путь к каталогу с репозиторием. Без других параметров программа выводит имена всех веток; дальнейшие требования относятся к запуску программы со вторым параметром — именем ветки.

      master
      lomaster
    2. Вывести объект-последний коммит (последний коммит указанной ветки).
      tree 3182cbd0e8b2baecbdc693008ed832b25546e225
      parent f97190bd4dea21041d1cd7fcf822cd4ac6e7716b
      author Ivan Samovarov <isamovarov@mail.ru>
      committer Elec Tropoezd <elec@tropoe.zd>
      
      Added a very important feature.
    3. Вывести объект-дерево, на который указывает последний коммит ветки (поддеревья обрабатывать не нужно).
      blob cf1ab25da0349f84a3fdd40032f0ce99db813b8b    LICENSE
      blob f99151731324e7ac98281272c68f2b599dbf868d    Makefile
      tree b6e86ab64d77628cff4cfcaaf9133533733f8553    Tests
    4. Пройти по истории от последнего к начальному коммиту ветки, для каждого коммита вывести объект-дерево
      • В случае нескольких родительских коммитов выбирать первый, топологией не заморачиваться.
      • "TREE" большими буквами выделяет строку, где сказано, дерево для какого коммита выводится.
        TREE for commit f5980e79c7f010f38d249390248936dd0ae58a3a
        blob cf1ab25da0349f84a3fdd40032f0ce99db813b8b    LICENSE
        blob f99151731324e7ac98281272c68f2b599dbf868d    Makefile
        tree b6e86ab64d77628cff4cfcaaf9133533733f8553    Tests
        TREE for commit f97190bd4dea21041d1cd7fcf822cd4ac6e7716b
        blob cf1ab25da0349f84a3fdd40032f0ce99db813b8b    LICENSE
        blob 2cb7f6e3ff1a5d1ab379d953dbc7b5738d1dfed3    Makefile
        tree b6e86ab64d77628cff4cfcaaf9133533733f8553    Tests

При публикации следовать рекомендациям оформления commit message

План

  • <!> Задача_1: напишите программу, реализующую простейший Multi-user dungeon (по ходу практикума MUD будет усложняться)

    • имеется поле 10х10 клеток; рисовать поле и его наполнение - не нужно
      • по каждой оси нумерация с 0 по 9
      • первая координата задает координату по горизонтали, вторая - по вертикали
      • клетка (0, 0) находится в левом верхнем углу поля (важно для навигации)
    • в каждой клетке может либо быть пусто, либо находиться один монстр
    • по полю ходит игрок; когда он попадает на клетку с монстром, случается "происшествие" (encounter)
    • в начале игры игрок появляется в клетке (0, 0)
    • настройка поля и игровой процесс организованы при помощи командной строки
    • должен поддерживаться не только интерактивный режим (с консольным вводом), но и режим с получением команд из текстового файла (перенаправление ввода при помощи "<") - это нужно для автотестирования

    • начальная версия командного языка:
      • up, down, left, right

        • перемещение по полю на одну клетку в выбранном направлении
        • если игрок переходит через границу поля, он появляется у противоположной границы (например, left в позиции (0, 5) переводит в позицию (9, 5))

        • при выполнении команды выводится: "Moved to (<x>, <y>)", где <x>, <y> - координаты клетки, куда попал игрок

        • если игрок попал в клетку с монстром, случается "происшествие", логика которого описана ниже
      • addmon <x> <y> <hello>

        • добавление в клетку (x, y) монстра, при встрече говорящего слово-приветствие, заданное в <hello> (достаточно поддерживать слова без пробелов)

        • если в этой клетке уже есть монстр, новый монстр его заменяет (пока это сводится к замене слова-приветствия)
        • если в этой клетке находится игрок, происшествие при добавлении монстра не случается
        • при выполнении команды выводится: "Added monster to (<x>, <y>) saying <hello>"; если монстр заменяется, также выводится, с новой строки, "Replaced the old monster"

      • при вводе неверной команды должно выводиться "Invalid command"
      • при вводе команды с неверными аргументами должно выводиться "Invalid arguments", фанатично проверять корректность аргументов НЕ нужно
    • отработка происшествия (т.е. попадания игрока на клетку с монстром):
      • происшествие должно отрабатываться в функции encounter(x,y), вызываемой после вывода "Moved to ..."

      • вывести текстового монстра, произносящего слово-приветствие
      • для формирования монстра, говорящего текст, используется функция cowsay(text) из модуля python-cowsay

        • этот модуль можно поставить в локальное окружение pip install-ом, или завести venv, которые не попадёт в репозиторий

        • для начала все монстры будут выглядеть как default'ная корова из cowsay
  • <!> Задача_2: добавьте в MUD (на параллельной ветке в git) поддержку именованных монстров, при этом пользуйтесь редактированием истории на ветке. Решение это задачи надо делать на ветке named_monsters.

    • Скопируйте решение Задачи_1. Добавьте его в основную ветку, и после этого заведите ветку named_monsters (создание ветки: git checkout -b)

    • новая функциональность (её нужно разбить на коммиты, как сказано ниже!):
      • поддержка команды addmon <name> <x> <y> <hello> , где <name> это имя монстра (строка без пробелов)

        • старый (без имени) формат команды больше не должен поддерживаться
      • для клетки (x, y) должно запоминаться имя монстра, в дополнение к строке-приветствию
      • строка, выводимая при успешном добавлении монстра, должна выглядеть так: "Added monster <name> to (<x>, <y>) saying <hello>"

      • когда игрок попадает на клетку с монстром, в функции encounter() должно выводиться существо из коллекции модуля python-cowsay, произносящее приветствие (использовать функцию cowsay(message, cow=name))

      • при выполнении команды addmon должно проверяться, что <name> это имя одного из "штатных" существ, доступных в python-cowsay (список имен см. list_cows). Если проверка неуспешна, добавление монстра не выполняется, и выводится "Cannot add unknown monster".

    • занесите новую функциональность на ветку named_monsters в виде следующих коммитов, именно в таком порядке:

      • а) доработка разбора и обработки команды addmon <x> <y> <name> <hello>, кроме проверки того, что <name> - имя "штатного" существа

        • <!> порядок аргументов перепутан специально, чтобы потом редактировать историю

      • б) добавление передачи имени монстра в вызов cowsay() из функции encounter()

      • в) добавление в обработку команды addmon проверки того, что <name> - имя "штатного" существа

    • каждый коммит нужно выполнять после отладки соответствующей функциональности, удалив отладочный код; разработали+отладили а) => занесли а), потом переходим к б), и т.п.

    • отредактируйте историю (git rebase -i) на ветке named_monsters:

      • в коммите а) замените в разборе addmon порядок аргументов команды на правильный (опция edit)

      • переставьте местами коммиты б) и в)
      • содержание коммитов в истории удобно контролировать при помощи команды git log --patch

    • ещё раз отредактируйте историю на ветке named_monsters:

      • объедините коммиты а) и в)

План

<!> Задача_1: работа с ветками в git при разработке программы

  • В решении Задачи_2 с предыдущего занятия сделайте merge ветки named_monsters на ветку work

  • Скопируйте решение Задачи_2 с предыдущего занятия. Сделайте коммит. Далее этот коммит будет обозначаться как {1}

  • Продолжите историю на ветке work:

    • Реализуйте вывод, при старте программы, строки-приветствия "<<< Welcome to Python-MUD 0.1 >>>"

    • Сохраните вывод строки-приветствия в виде одного коммита
  • Создайте ветку shlex_parse на базе коммита {1} и переключитесь на неё (проверьте!)

  • Реализуйте на ветке shlex_parse:

    • разбор команд MUD при помощи shlex вместо ранее реализованного разбора

    • поддержку команды addmon с синтаксисом (взамен прежнего синтаксиса): addmon <monster_name> hello <hello_string> hp <hitpoints> coords <x> <y>, где:

      • hello, hp, coords - имена параметров команды, все параметры обязательные

      • <hello_string> - строка приветствия, которую "произносит" монстр при встрече; может быть строкой с пробелами, заключенной в кавычки

      • <hitpoints> - положительное целое, задающее количество очков здоровья монстра (должно запоминаться вместе с именем монстра и строкой приветствия)

      • <x>, <y> - координаты монстра

      • порядок следования именованных параметров произвольный, например: addmon dragon hp 999 coords 6 9 hello "Who goes there?"

    • разбиение на коммиты - на ваше усмотрение, но коммитов на ветке должно быть не менее двух
  • Посмотрите структуру веток в qgit

  • Сделайте merge ветки shlex_parse на ветку work

  • Посмотрите структуру веток в qgit; обратите внимание на merge-коммит и на порядок следования коммитов в "суммарной" истории до merge-коммита

  • Создайте ветку custom_monster на базе коммита {1} и переключитесь на неё (проверьте!)

  • Реализуйте на ветке custom_monster поддержку нового монстра

    • монстр выглядит так: (пожалуйста, не удаляйте инициалы jgs - это условие использования, заданное автором Joan G. Stark)

          ,_                    _,
          ) '-._  ,_    _,  _.-' (
          )  _.-'.|\\--//|.'-._  (
           )'   .'\/o\/o\/'.   `(
            ) .' . \====/ . '. (
             )  / <<    >> \  (
              '-._/``  ``\_.-'
        jgs     __\\'--'//__
               (((""`  `"")))
    • поддержка монстра реализуется при помощи read_dot_cow(), см. пример на https://pypi.org/project/python-cowsay/

    • имя монстра "jgsbat"

    • должна быть реализована поддержка добавления этого монстра на игровое поле по команде addmon, с указанием имени монстра (наравне со "стандартными" персонажами python-cowsay)

  • Сделайте rebase ветки work (где к этому шагу будет merge-коммит) на ветку custom_monster

  • Внимание! в результате именно ветка work должна вобрать в себя все коммиты (т.е. команда должна быть git rebase custom_monster work)

  • посмотрите структуру веток в qgit

План

<!> Задача_1: переход на cmd, разработка на ветке с конфликтом объединения

  • Скопируйте решение Задачи_1 с предыдущего занятия. Сделайте коммит.

  • Продолжите историю на ветке work:

  • Реорганизуйте уже имеющиеся команды с помощью cmd и do_команда()

    • При этом "из коробки" приедет автодополнение частично введенного имени команды по нажатию TAB
    • Решение оформить в виде серии коммитов
  • ВНИМАНИЕ: поскольку в дальнейшем нужно будет реализовать в MUD поддержку пакетного режима выполнения команд со считыванием их из командного файла (*.mood), разделяйте в коде работу с командной строкой (т.е. ввод команд) и разбор/выполнение команд. Так чтобы без существенной переделки кода можно было добавить альтернативный источник команд - файл, а не командную строку.

  • Реализуйте поддержку базовой команды attack (без параметров). Обработка команды:

    • Если в позиции, где находится игрок, нет монстра, вывести "No monster here" и завершить обработку команды

    • Атака наносит урон монстру в 10 очков здоровья, если у монстра не менее 10 о.з., в противном случае урон равен количеству о.з. монстра
    • Вывести: "Attacked <имя монстра>,  damage <урон> hp", где <имя монстра> - имя монстра в одной позиции с игроком (таких монстров ровно один), <урон> - число списанных о.з.

    • После корректировки здоровья монстра (как принято говорить, "отрицательного выздоровления") вывести:
      • если о.з. монстра равны 0: "<имя монстра> died"

      • в противном случае: "<имя монстра> now has <очки здоровья>", где <очки здоровья> - количество оставшихся о.з. у монстра

    • Если у монстра 0 о.з., удалить монстра с позиции
  • Далее последний коммит в реализации базовой команды attack обозначен как {1}

  • Создайте ветку weapon_name на базе коммита {1} и переключитесь на неё (проверьте!)

  • Реализуйте на ветке weapon_name атаку разными видами оружия, с указанием оружия в параметре with команды attack

    • синтаксис команды: attack with <имя оружия>

    • варианты для <имя оружия>: sword, spear, axe; наносимый урон, соответственно: 10, 15, 20

      • при указании неизвестного оружия выводить: "Unknown weapon", и завершать обработку команды

    • параметр with необязательный, значение по умолчанию: sword

    • для имени оружия должно работать автодополнение имен через TAB (используйте complete_команда())

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

  • Создайте ветку attack_by_name на базе коммита {1} и переключитесь на неё (проверьте!)

  • Реализуйте на ветке attack_by_name атаку с обязательным указанием имени монстра

    • синтаксис команды: attack <имя монстра>

    • если монстра с данным именем нет в позиции, где находится игрок, вывести "No <имя монстра> here" и завершить обработку команды

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

    • для имени монстра должно работать автодополнение, а также пролистывание имен через TAB (используйте complete_команда()); пролистываться должны имена ДОСТУПНЫХ В ИГРЕ монстров, т.е. тех, которые могут быть добавлены через команду addmon

  • сделайте merge ветки weapon_name на ветку work, он будет бесконфликтным (т.к. на work история не продвинулась дальше {1} )

  • сделайте merge ветки attack_by_name на ветку work, при этом разрешите конфликты из-за разных доработок команды attack

    • в результате должна появиться поддержка команды с синтаксисом "attack <имя монстра> with <имя оружия>", с поддержкой автодополнения и пролистывания как по имени монстра, так и по имени оружия

План

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

<!> Задача_1. MUD в формате клиент-сервер (однопользовательский), оформление изменений в виде патчсета.

  • Скопируйте решение Задачи_1 с предыдущего занятия. Сделайте коммит. Далее этот коммит будет обозначаться {1}

  • Продолжите историю на ветке work

  • Переведите монолитную реализацию MUD на схему "клиент+сервер" (однопользовательскую)
    • клиент отвечает за:
      • получение команд от пользователя, их разбор, проверку корректности (включая вывод сообщений о некорректных командах)
      • вывод информации, полученной от сервера
      • т.е. по сути клиент не имеет состояния
    • сервер работает по принципу echo-сервера, воспринимающего строки вида команда параметры

    • сервер отвечает за хранение и модификацию состояния игры, включая:
      • позицию игрока
      • расположение монстров, их типы и количество очков здоровья (о.з.)
    • организация протокола клиент->сервер:

      • по протоколу передаются только команды с гарантированно корректными параметрами; сервер не занимается их перепроверкой (в жизни - не так :) )

      • набор команд протокола следует сделать более простым, чем набор пользовательских команд:
        • не нужны опциональные параметры; если пользователь опустил опциональный параметр, клиентом в команду для сервера подставляется значение по умолчанию
        • можно все параметры сделать позиционными
        • однотипные команды можно объединять в одну, с различением по параметрам: например, единственная команда перемещения с указанием приращения по каждой координате (вместо up: move 0 -1, вместо right: move 1 0)

        • в целом, клиент выполняет "частичное переваривание" пользовательского ввода и передает серверу упрощенный и гарантированно корректный результат
    • организация протокола сервер->клиент:

      • сервер возвращает только те данные, которые нужны клиенту для вывода
      • сервер отвечает на каждую команду клиента без каких-либо задержек
      • клиент вправе ждать ответа сервера на отправленную команду, и возвращаться к приёму пользовательских команд только после получения ответа
    • по сути, параллелизма в работе клиента и сервера НЕТ
    • важные частные случаи:
      • "энкаунтер" (т.е. перемещение игрока в позицию с монстром): на сервер поступает команда перемещения, в ответ сервер шлёт имя монстра и его приветственный текст; рендерингом с помощью cowsay занимается клиент

      • атака: на сервер шлётся имя монстра и количество о.з., соответствующее выбранному оружию; сервер отвечает - либо что монстра с таким именем в позиции нет; либо (если монстр есть), то количеством списанных о.з. и количеством оставшихся о.з. (если второе равно 0, значит монстр убит)
    • ДИСКЛЕЙМЕР: вышесказанное - не готовый проект протокола, а намёки на то, как его имеет смысл построить!
  • оформите реализацию в виде набора коммитов на ветке work, желательно не менее 3 коммитов

  • сформируйте по этому набору коммитов патчсет:
    • создайте подкаталог patchdir

    • при помощи команды git format-patch с ключом --output-directory создайте в подкаталоге patchdir патчсет, включающий все коммиты, реализующие клиент-серверную схему

    • закоммитьте файлы патчсета
  • примените патчсет:
    • скопируйте каталог patchdir в место, находящееся вне git-репозитория (далее путь к этому месту обозначен как path_to_patchdir)

    • создайте ветку apply_patch от коммита {1} , переключитесь на неё (проверьте!)

    • при помощи команды git am path_to_patchdir/patchdir/* примените патчсет

  • проверка: посмотрите структуру веток при помощи gitk/qgit/аналогов; на ветках work и apply_patch должны быть одинаковые наборы коммитов, за вычетом коммита с патчсетами

План

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

  • <!> Задача_1. Многопользовательский MUD (multiuser multiuser dungeon)

    • Скопируйте решение Задачи_1 с предыдущего занятия. Сделайте коммит. Работайте на ветке work.

    • Сделайте (наконец-то!) MUD многопользовательским. Подробности ниже.
    • Многосессионность (поддержку работы с одним сервером одновременно нескольких клиентов) реализуйте по схеме "коровьего чата" из лекций.
    • Именованные сеансы:
      • При подключении клиента к серверу, клиент передаёт серверу имя пользователя (строка без пробелов, поступает клиенту при запуске - python mymud.py username).

      • Сервер проверяет, что подключенного пользователя с таким именем ещё нет; если есть - отказывает в подключении; если нет, то создает подключение (сообщая об этом клиенту) и запоминает имя пользователя.
    • Асинхронность работы клиента с сервером:
      • после отправки сообщения серверу, клиент НЕ ждёт ответа от сервера
      • все сообщения от сервера клиенту после успешного подключения - "асинхронные", т.е. принимаются параллельно работе пользователя с командной строкой

      • все сообщения от сервера клиенту предназначены для вывода "as is", никакого разбора в духе "набор параметров от сервера к клиенту" теперь не нужно; т.е. клиент отправляет команды на сервер без ожидания ответа и без "понимания", что сообщения от сервера приходят в ответ на конкретные команды

      • схема параллельного ожидания сообщений и обработки пользовательского ввода - см. лекцию (раздел "Cmd и асинхронные сообщения")

      • важно: после получения от сервера (и вывода) сообщения, клиент должен показать командную строку с набранным (но не введённым) пользователем текстом, чтобы результат ввода не исчезал (опять см. лекцию)
    • Частичная неделимость обработки пользовательской команды на сервере (для ограничения гонок):
      • помним, что сервер последовательный
      • получив команду от клиента, сервер обрабатывает её сразу (а не планирует обработку через async)
      • отправку сообщения клиенту (клиентам) сервер осуществляет асинхронно
    • Широковещательные сообщения от сервера клиентам:
      • сообщения о "знаковых событиях" сервер рассылает всем клиентам, в духе коровьего чата (где он транслирует всем клиентам полученное от клиента сообщение)
      • знаковые события:
        • атака на монстра (сообщать: кто атаковал (имя пользователя), чем, какого монстра, сколько очков здоровья снёс, сколько о.з. осталось; если монстр убит, то сообщить об этом [чтобы клиентам не пришлось выпарсивать число о.з.]) сколько включая результат)
        • установка монстра (кто поставил, имя монстра, кол-во о.з.)
        • заход пользователя (в т.ч. сообщить имя) в MUD
        • прекращения сеанса пользователя в MUD (тоже с указанием имени)
      • есть и не-широковещательные сообщения, например приветствие от встреченного монстра поступает одному конкретному пользователю
    • Прямого взаимодействия между пользователями нет
    • Возможны логические гонки: например, два пользователя более-менее одновременно отправили команду атаки на одного и того же монстра, "первый" убил монстра, а второму пришло индивидуальное сообщение о том, что монстра нет. Это терпимо.

План

TODO Сделать условие немного более конкретным для удобства автоматической проверки (например, фиксировать имена подпакетов и наличие .flake8)

  1. <!> Задача_1: MUD messaging

    • Скопируйте решение Задачи_1 с предыдущего занятия. Сделайте коммит. Работайте на ветке work.

    • Задайтесь вопросом: если MUD теперь многопользовательский, как пользователи (приключенцы) будут кооперироваться, чтобы вынести особо крутого монстра?
      • Спойлер: нужен чат
    • Реализуйте команду для передачи сообщения всем игрокам
      • Синтаксис: sayall <строка>, где <строка> - либо одно слово (без пробельных символов), либо строка в кавычках

      • Примеры:
        • sayall PREVED

        • sayall "Let's attack dragon at 5 9"

      • Сервер транслирует строку всем с указанием имени пользователя-источника. Пример: kobold702: Let's attack dragon at 5 9

  2. <!> Задача_2: MUDуляризация, применение flake8 и pydocstyle

    • Скопируйте решение Задачи_1. Сделайте коммит. Работайте на ветке work.

    • Оформите MUD в виде пакета с минимум двумя подпакетами: клиент (client), сервер (server); возможно, понадобится ещё третий: библиотека общих классов/констант/функций (common). Вот предположительная структура всего пакета:

      mood
      ├── client
      │   ├── …
      │   └── __main__.py
      ├── common
      │   ├── __init__.py
      │   └── …
      └── server
          ├── …
          └── __main__.py
      • В силу cowsay-ориентированности, наш MUD обрёл официальное название - MOOD
    • Запуск для каждого подпакета — в __main__.py

      • Соответственно, запуск клиента — это python3 -m mood.client параметры, а сервера — python3 -m mood.server параметры

    • Добейтесь полного отсутствия претензий со стороны flake8 и pydocstyle к содержимому пакетов

      • Разрешается настраивать ☺

План

<!> Задача_1. Бродячие монстры и Сфинкс

  • Скопировать решение Задачи_2 (где выделяются два модуля) с предыдущего занятия. Сделать коммит. Работать на ветке work.

  • Добавить на сервере MUD поддержку бродячих монстров:
    • один раз в 30 секунд (первый раз - по истечении 30 секунд от старта) выбирается случайный монстр, и он перемещается на одну клетку в случайно выбранном направлении (вправо/влево/вверх/вниз; помним, что поле "закольцовано")
    • если в результате перемещения монстр попал бы на клетку, где уже есть монстр, то перемещение НЕ ПРОИСХОДИТ, и проводится повторный выбор монстра и направления; и так пока не будет выполнено успешное перемещение монстра
    • при перемещении сервер выдаёт всем игрокам сообщение "<имя_монстра> moved one cell <направление>", где <направление> это right, left, up, down. Например: "manticore moved one cell right"

    • если монстр попадает на клетку, где есть игрок (или игроки), происходит "энкаунтер" - как если бы игрок(и) сам зашел(ли) на клетку с монстром
      • в т.ч. монстр отрисовывается у столкнувшихся с ним игроков, с произнесением приветственной фразы
  • Для модуля-сервера задокументировать все функции, классы и модуль в формате autodoc
  • Добиться выгонки технической документации по этим классам/функциям/модулю
    • Следить за тем, чтобы генераты (html-документация) не хранились в git (.gitignore), а настойки sphinx — хранились

  • Оформить титульный лист документации (как минимум, скопипастить туда формулировку задачи)
  • Сделать в титульном листе ссылку на техническую документацию

<!> Задача_2. MUD-скриптование.

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

  • Скопировать решение Задачи_1. Сделать коммит. Работать на ветке work.

  • реализовать (см. последнее упражнение) получение команд из командного файла, если при запуске передан параметр "--file <имя_файла>"

    • командные файлы рекомендуется снабжать расширением ".mood"

  • при получении команд из файла, ввод команд через cmd не должен работать

  • чтобы не "зафлудить" сервер, интервал между последовательными отправками команд с клиента на сервер должен быть не менее 1 секунды
  • примечание: скриптование нацелено на автоматическое тестирование MUD-ов, но при таком тестировании (когда дело до него дойдёт) "бродячих монстров" будет необходимо отключать

План

<!> Задача_0. Доделать упражнения по русификации, т.к. они будут использоваться в упражнениях на занятии по автоматизации.

<!> Задача_1. Реализовать для MUD-а поддержку команды включения/выключения режима бродячих монстров

  • Скопировать решение Задачи_2 с предыдущего занятия. Сделать коммит. Работать на ветке work.

  • реализовать команду:
    • формат: "movemonsters on" / "movemonsters off" (включить / выключить режим бродячих монстров)
    • состояние сервера по умолчанию: режим бродячих монстров включен

    • сообщение от сервера в ответ на команду: "Moving monsters: on" / "Moving monsters: off"
  • выключение режима Б.М. нужно для автоматического тестирования через скрипты. Сложно тестировать атаку на монстра, если нет уверенности, что он всё ещё там, куда его поставили...

<!> Задача_2. Локализация сообщений на стороне сервера.

  • Почему на стороне сервера?
    • на сервере формируются сообщения, включающие числовые значения и соответствующие им слова в множественном числе
    • протокол от сервера к клиенту строится на сообщениях, не подлежащих интерпретации клиентом (т.е. они только выводятся клиентом в терминал), а значит числовые значения как отдельные параметры в нём передать невозможно

    • поскольку вариантов множественного числа в русском языке больше, чем в английском, полноценная русификация множественного числа на клиенте без знания числового значения тоже невозможна (нельзя просто взять и перевести "points" как "очков", потому что "два очка")

  • Скопировать решение Задачи_1. Сделать коммит. Работать на ветке work.

  • добавить в клиент поддержку команды locale <имя_локали> (просто распознавание и передача на сервер)

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

    • поддержка через babel перевода сообщений для единственной (у нас учебная задача) локали ru_RU.UTF8

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

  • какие сообщения сервера нужно локализовывать:
    • реакция сервера на установку локали (сообщение только тому клиенту, который подал команду locale):

      • исходное: "Set up locale: <имя_локали>"

      • рус. локаль: "Установлена локаль: <имя_локали>"

    • сообщения о знаковых событиях: атака на монстра, установка монстра, заход пользователя, прекращение сеанса пользователя
      • подробности о знаковых событиях см. ../06_SocialProject

      • количество очков здоровья у монстра (имеющихся при установке, снятых при атаке, оставшихся после атаки) должно локализовываться с правильным применением множественного числа (1 очко / 2 очка / ... 5 очков / ... 21 очко и т.п.), то есть в файле локализации нужно задействовать формулу выбора множественного числа.
  • добавьте файлы локализации сервера в его модуль, проверьте что после установки модуля локализация "подхватывается" (при выставлении клиентом локали ru_RU.UTF8 этому клиенту выдаются русифицированные сообщения)

План

<!> Задача_1. Тестирование отработки сервером команд от клиента (проверяется связка клиент+сервер)

  • Скопировать решение Задачи_2 с предыдущего занятия. Сделать коммит. Работать на ветке work.

  • модифицировать архитектуру проекта таким образом, чтобы в нём была отдельная функция для запуска сервера

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

    • запуск сервера на локальном хосте
      • пример запуска: proc = multiprocessing.Process(target=функция_для_запуска_сервера([её, параметры]))

    • подключение к этому серверу
  • teardown: закрытие соединения и прерывание работы сервера (proc.terminate())

  • каждый тест запускается на клиенте и имеет вид: <отправка команды; ожидание и проверка ответа>; команда - фиксированное сообщение в формате протокола клиент->сервер

  • проверяются команды:
    • установка монстра (недалеко от начального положения игрока)
    • подход к монстру; ожидаемый ответ: "появление" монстра и произнесение им приветствия
    • атака на монстра

<!> Задача_2. Тестирование клиента с использованем мокеров

  • Скопировать решение Задачи_2 с предыдущего занятия. Сделать коммит. Работать на ветке work.

  • написать набор тестов для преобразования клиентом команд из формата пользовательского ввода в формат протокола клиент->сервер

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

  • для каждой из этих команд протестировать преобразование правильной команды в формат протокола клиент->сервер (для двух разных значений параметров команды; если команда - движение, то для двух разных направлений)

  • хотя бы для одной команды протестировать обработку неправильно заданных параметров

План

<!> Задача_1. Автоматизация сборки для MUD.

  • Скопировать решение Задачи_1 с предыдущего занятия. Сделать коммит. Работать на ветке work.

  • реализовать цель i18n для полной генерации перевода

    • реализовать цели-шаги генерации перевода, как в описанном выше упражнении
    • цель i18n должна зависеть от этих целей-шагов

  • реализовать цель html для генерации html-документации

  • реализовать цель test для прогона тестов связки клиент+сервер (зависит от цели i18n, потому что проверяет русифицированные ответы сервера)

  • для каждой цели реализовать удаление генератов (использовать атрибут clean и функцию clean_targets; для удаления каталога с документацией использовать функцию shutil.rmtree)

  • цель по умолчанию: html

План

<!> Задача_1. Пакетирование для MUD (частично сделано в классе, но рекомендуется не торопиться и переделать аккуратно)

  • Скопировать решение Задачи_1 с предыдущего занятия. Сделать коммит. Работать на ветке work.

  • Реализовать в клиенте команду documentation с вызовом браузера посредством webbrowser.open(), которая показывает сгенерированную документацию

  • сделать pyproject.toml, содержащий описание общего пакета с клиентом и сервером

    • описание эксплуатационных зависимостей (cowsay-python и др. используемых пакетов)

    • описание собственно содержимого пакета:
      • файл(ы) *.py

      • скомпилированный перевод
      • .cow-файл с дополнительным монстром

      • сгенерированная документация
      • если в состав конкретной реализации входят ещё какие-то файлы, нужные для запуска, то и они
    • указание точек входа для генерации двух сценариев — запуск сервера и запуск клиента
  • Предусмотреть описание сборочных зависимостей (например, в секции [dev-packages] Pipfile-а или в requirements-dev.txt)

  • TODO (нет в 2026) предусмотреть doit-цели

    • wheel — собирает колесо (с зависимостями на документацию и перевод)

    • sdist — собирает архив исходников (с зависимостью на clean или erase)

  • проверить установку пакета и запуск клиента и сервера:
    • в двух отдельных окружениях
    • в едином окружении
    • (в обоих случаях окружение создаётся заново)

План

ВЫЖИТЬ

LecturesCMC/PythonDevelopment2026/Prac/MOOD (последним исправлял пользователь FrBrGeorge 2026-05-16 13:21:04)