В качестве тестового задания необходимо реализовать процесс Турнира между игроками:
- Входные данные:
- 200 игроков:
- id = uuid4()
- name = any
- power = random.randint(1, 1000)
- medals = 1000
- money = 0
- Турнир
- Продолжительность турнира 2 минуты
- Максимальное количество игроков в турнирной группе: 50
- Игроки формируются в группы по параметру 'power'
- Процесс турнира:
- Все игроки делятся на группы по 50 человек (сортируем пользователей по параметру power и объединяем в группы)
- Между пользователями происходит соревнование кто больше всего соберет медалей за турнир
- Игроки выигрывают медали нападая на других игроков
- результат нападения высчитывается по формуле random.randint(-10, 10)
- если результат отрицательный нападающий отдает это количество оппоненту
- если результат положительный нападающий забирает медали у оппонента
- Требования
- игрок может нападать на любых игроков
- игрок должен сделать хотя бы одно нападение за турнир
- победитель определяется по количеству медалей на конец турнира
- Ограничения
- игрок не может нападать чаще чем раз в 5 секунды
- 2 игрока не могут напасть одновременно на одного игрока
- 1 пользователь не может напасть дважды на одного и того же игрока
- игрок не может нападать сам на себя
- По завершении турнира победителям начисляются награды в зависимости от их места в группе
- 1 место 300 money
- 2 место 200 money
- 3 место 100 money
- Backend должен предоставлять API (Может быть дополнено или изменено по вашему усмотрению):
- Admin:
- POST player (name, power, medals, money) - добавляет пользователя
- GET player (id) - возвращает данные игрока
- POST tournament (start_timestamp) - начинает турнир
- GET tournament (id) - возвращает состояние турнирных групп
- Game:
- GET opponent(player_id) - находит пользователя для нападения
- POST attack(from_player_id, to_player_id) - атака
- В результате должно быть:
- скрипт backend.py
- Запускает сервер турнира
- скрипт tournament.py (должен запускаться локально, работает с backend.py)
- генерирует 200 игроков
- начинает турнир
- совершает атаки
- по завершении турнира выводит список турнирных групп и победителей
- В качестве фреймворка для этой задачи был взят aiohttp (пишу на нем в полуторный раз).
- Для хранения данных, частый доступ к которым не нужен, выбран PostgreSQL.
- Для кэширования данных турнира и таймеров -- Redis.
Слежение за тем, что турнир идет происходит через while True вотчер за переменной в Redis, у которой указано время жизни. Через такие же переменные реализованы таймеры на тайм-аут нападений (5 секунд). Чтобы два игрока не напали на одновременно на одного и того же создан контекстный менеджер, который при входе создает специальную переменную в Redis, а при выходе -- удаляет. Перед входом в менеджер эта переменная проверяется. Валидные для нападения игроки генерируются списками для каждого игрока и кладутся в Redis по принципу -- все, кто есть в группе, кроме самого себя. При каждои нападении из этого списка удаляется id игрока, на которого оно было совершено, чтобы не напасть на него дважды.
Подготовка и запуск основного бэкенда
pipenv install cp .env_example .env cp config/config_example config/config
Теперь надо посмотерть и поправить config и .env. Затем следующее:
pipenv run alembic upgrade head pipenv run python app.py
Теперь можно запустить скрипт, который сымитирует запросы пользователей.
pipenv run python tournament.py
Пример вывода результатов работы tournament.py:
Tournament ended
RESULTS
Place | Group | Name
1 | 0 | player-103 | Medals: 1018 | Money: 300
2 | 0 | player-107 | Medals: 1018 | Money: 200
3 | 0 | player-151 | Medals: 1013 | Money: 100
1 | 1 | player-185 | Medals: 1031 | Money: 300
2 | 1 | player-179 | Medals: 1019 | Money: 200
3 | 1 | player-148 | Medals: 1017 | Money: 100
1 | 2 | player-45 | Medals: 1023 | Money: 300
2 | 2 | player-78 | Medals: 1022 | Money: 200
3 | 2 | player-29 | Medals: 1018 | Money: 100
1 | 3 | player-94 | Medals: 1016 | Money: 300
2 | 3 | player-100 | Medals: 1014 | Money: 200
3 | 3 | player-186 | Medals: 1014 | Money: 100