Не подумайте, что мне нечем себя занять, но тренировалась немного переводить с русского на Питон.
Взяла для перевода мафский сет Неба
https://forum.heroesworld.ru/showpost...postcount=2087 Получилось местами не так красиво, как хотелось, некоторые вещи вообще не сделала, но в целом результатом довольна.
Так что пусть тут лежит, вдруг еще кому-то интересно.
Замечания принимаются сюда, в личку или в скайп. Предложения тоже принимаются. Вдруг кто-то знает, как сделать код попроще например или схему попонятней. А то с перенаправлениями например такая городуха получается, что даже не стала их описывать.
Делает расчет резалтов ночи и печать лога этой ночи.
данные вносятся списками:
1. players - данные по ролям: ник игрока, квента, команда, роль, статус, вес голоса на начало игры
2. priority_list - данные по всем ночным действиям (НД) сета: приоритет, исполнитель, название НД, отображение в газете, а также техническая информация для создания НД
3. operations - НД, примененные в текущую ночь: исполнитель, название НД, на кого применено, дополнительная информация
4. current_alive_dict - состояние игроков на начало текущей ночи: жив, убит, казнен, етц
по данным первого массива создаются роли - экземпляры суперкласса Role
по данным второго создаются и дописываются к ролям все НД сета. Каждое НД - подкласс класса Action.
Пример работы.
-----------------------------------------------
ночь номер 1
-----------------------------------------------
Arandor13 (роль Безумие) применил действие Смена статусов на Arandor3 (роль Холкхак),
результат ==> холодный / не человек; отображение в газете --> факт
Arandor4 (роль Хьялйот) применил действие Блок на Arandor14 (роль Смерть),
результат ==> успех; отображение в газете --> да
Arandor2 (роль Йороар) применил действие Сравнение на Arandor11 (роль Холод), на Arandor12 (роль Голод),
результат ==> статусы одинаковы; отображение в газете --> нет
Arandor3 (роль Холкхак) применил действие Проверка на Arandor11 (роль Холод),
результат ==> холодный; отображение в газете --> нет
Arandor5 (роль Глариэл) применил действие Проверка на Arandor3 (роль Холкхак),
результат ==> не человек; отображение в газете --> нет
Arandor6 (роль Флавий) применил действие Защита на Arandor2 (роль Йороар),
результат ==> успех; отображение в газете --> да
Arandor9 (роль Ральфйор) применил действие Защита от Голода на Arandor12 (роль Голод),
результат ==> успех; отображение в газете --> да
Arandor12 (роль Голод) применил действие Убийство на Arandor2 (роль Йороар),
результат ==> Квента12; отображение в газете --> да
Arandor8 (роль Стигйор) применил действие Лечение на Arandor6 (роль Флавий),
результат ==> лечение не требуется; отображение в газете --> да
Arandor7 (роль Эсбен) применил действие На цепь на Arandor6 (роль Флавий),
результат ==> успешно; отображение в газете --> да
-----------------------------------------------
{'убит': ['Arandor2'], 'на цепи': ['Arandor6'], 'жив': ['Arandor9', 'Arandor12', 'Arandor7', 'Arandor10', 'Arandor3', 'Arandor13', 'Arandor11', 'Arandor4', 'Arandor14', 'Arandor5', 'Arandor1', 'Arandor8'], 'казнен': []}
-----------------------------------------------
в игре 13 голосов и 13 игроков
голоса игроков:
{'Arandor9': 1, 'Arandor12': 1, 'Arandor7': 1, 'Arandor10': 1, 'Arandor3': 1, 'Arandor13': 1, 'Arandor11': 1, 'Arandor6': 0, 'Arandor4': 1, 'Arandor14': 1, 'Arandor5': 1, 'Arandor1': 2, 'Arandor8': 1}
-----------------------------------------------
ночь номер 2
-----------------------------------------------
Arandor13 (роль Безумие) применил действие Смена статусов на Arandor1 (роль Фритйоф),
*** цель в списке исключений
результат ==> провал; отображение в газете --> нет
Arandor4 (роль Хьялйот) применил действие Блок на Arandor10 (роль Аврелий),
результат ==> успех; отображение в газете --> да
Arandor3 (роль Холкхак) применил действие Проверка на Arandor6 (роль Флавий),
в момент применения действия цель на цепи
результат ==> теплый; отображение в газете --> нет
Arandor5 (роль Глариэл) применил действие Проверка на Arandor1 (роль Фритйоф),
результат ==> человек; отображение в газете --> нет
Arandor6 (роль Флавий) применил действие Защита на Arandor9 (роль Ральфйор),
*** исполнитель на цепи или блокирован
результат ==> провал; отображение в газете --> нет
Arandor9 (роль Ральфйор) применил действие Защита от Голода на Arandor9 (роль Ральфйор),
*** цель в списке исключений
результат ==> провал; отображение в газете --> нет
Arandor13 (роль Безумие) применил действие Убийство на Arandor6 (роль Флавий),
в момент применения действия цель на цепи
результат ==> Квента13; отображение в газете --> да
Arandor7 (роль Эсбен) применил действие На цепь на Arandor13 (роль Безумие),
результат ==> успешно; отображение в газете --> да
-----------------------------------------------
{'убит': ['Arandor2', 'Arandor6'], 'казнен': ['Arandor8'], 'жив': ['Arandor1', 'Arandor4', 'Arandor12', 'Arandor14', 'Arandor3', 'Arandor7', 'Arandor9', 'Arandor5', 'Arandor10', 'Arandor11'], 'на цепи': ['Arandor13']}
-----------------------------------------------
в игре 11 голосов и 11 игроков
голоса игроков:
{'Arandor7': 1, 'Arandor1': 2, 'Arandor4': 1, 'Arandor10': 1, 'Arandor9': 1, 'Arandor12': 1, 'Arandor5': 1, 'Arandor3': 1, 'Arandor13': 0, 'Arandor11': 1, 'Arandor14': 1}
Добавлено через 3 минуты
# "ник игрока" и "роль" должны быть уникальными - используются как ключи для поиска.
# ник игрока, квента, команда, роль, статус, голос (на начало игры)
players = [ ["Arandor1", "Квента1", "Команда", "Фритйоф", "холодный / человек" , 2],
["Arandor2", "Квента2", "Команда", "Йороар" , "теплый / человек" , 1],
["Arandor3", "Квента3", "Команда", "Холкхак", "холодный / не человек", 1],
["Arandor4", "Квента4", "Команда", "Хьялйот", "теплый / человек" , 1],
["Arandor5", "Квента5", "Команда", "Глариэл", "холодный / не человек", 1],
["Arandor6", "Квента6", "Команда", "Флавий", "теплый / не человек" , 1],
["Arandor7", "Квента7", "Команда", "Эсбен", "теплый / человек" , 1],
["Arandor8", "Квента8", "Команда", "Стигйор", "теплый / человек" , 1],
["Arandor9", "Квента9", "Команда", "Ральфйор","теплый / человек" , 1],
["Arandor10", "Квента10", "Команда", "Аврелий", "теплый / человек" , 1],
["Arandor11", "Квента11", "*", "Холод" , "холодный / не человек", 1],
["Arandor12", "Квента12", "*", "Голод" , "холодный / не человек", 1],
["Arandor13", "Квента13", "*", "Безумие", "теплый / не человек" , 1],
["Arandor14", "Квента14", "*", "Смерть" , "холодный / человек" , 1]
]
# данные на начало ночи:
# --- в первую ночь заполняется автоматически, в следующие ночи заполняется копипастой и добавлением резалтов дня ---
night_no = 2 # номер ночи
#current_alive_dict = {"жив":[], "на цепи":[], "убит":[], "казнен":[]} # на начало первой ночи все живы
current_alive_dict = {'убит': ['Arandor2'], 'на цепи': ['Arandor6'], 'жив': ['Arandor9', 'Arandor12', 'Arandor7', 'Arandor10', 'Arandor3', 'Arandor13', 'Arandor11', 'Arandor4', 'Arandor14', 'Arandor5', 'Arandor1'], 'казнен': ['Arandor8']}
class Role: # суперкласс ролей
# конструктор __init__ создает роль со свойствами: self, ник игрока, на чьей стороне, роль, статус, инфа для улик, вес голоса)
def __init__(self, nickname, team, rolename, statuses, quenta="", vote=1):
self.nickname = nickname # ник игрока
self.quenta = quenta # инфа для улик
self.team = team # на чьей стороне
self.rolename = rolename # наименование роли
self.vote = vote # вес голоса
self.actions = {} # список действий пока пуст (словарь с поиском по названию НД)
self.statuses = statuses # статус
self.alive = "жив" # жив, может принимать значения {"жив", "на цепи", "убит", "казнен"}
self.defender = None # защитник (Флавий) в спутниках
self.killer = None # убийца
self.blocked = False
self.deblocked = False
def set_block(self): # установить блокировку
self.blocked = True
return "успех"
def set_deblock(self): # деблокировать
self.deblocked = True
return "успех"
def change_alive(self, param): # смерть или воскрешение роли, посадка в тюрьму
self.alive = param # param in {"жив", "на цепи", "убит", "казнен"}
return self.alive
def set_vote(self, weight): # установить вес голоса = weight
self.vote = weight
return self.vote
def set_statuses(self, param): # установить значение статуса = param
self.statuses = param
return self.statuses
def get_status_no(self, no): # вернуть значение статуса номер no (no = 1 или 2)
replay = self.statuses.rsplit("/")
if (len(self.statuses) < no) or (no not in {1, 2}):
print ("ошибка проверки статуса для " + self.rolename)
return False
return str(replay[no-1]).strip()
def add_action(self, name_action, action): # добавить элемент с ключем name_action в список действий роли
self.actions[name_action] = action
return self.actions
class Action: # базовый суперкласс для НД
# конструктор __init__ создает действие со свойствами: исполнитель, название действия, приоритет, отображение, исключения, кол-во целей НД
def __init__(self, owner, actionname, priority, display, exceptions=[], targets_qlty=1):
self.owner = owner # исполнитель
self.actionname = actionname # название действия
self.priority = priority # приоритет
self.display = display # отображение в газете
self.targets_qlty = targets_qlty # количество целей для данного НД
self.exceptions = exceptions+[owner] # на какие роли НД не может быть применено, к списку исключений добавляется "нельзя применять НД на себя (owner)"
def add_exception (self, exception):
self.exceptions.append(exception)
return self.exceptions
def print_characters(self, targets): # информация об исполнителе, целях и примененном НД
target_string = ""
for target in targets:
target_string = target_string + " на "+target.nickname+" (роль "+target.rolename+"), "
print (self.owner.nickname+" (роль "+self.owner.rolename+") применил действие "+self.actionname + target_string)
def do(self,targets=[],params=[]): # если исполнитель мертв, напечатать ошибку "операция провалена", иначе выполнить действие "Ничего не выполнять"
self.print_characters(targets) # информация об исполнителе, цели и примененном НД
if (self.owner.blocked) and not(self.owner.deblocked):
print("*** исполнитель на цепи или блокирован")
return False # "действие провалено"
if not(self.owner.alive == "жив"):
print("*** исполнитель мёртв")
return False # "действие провалено"
for target in targets:
if target in self.exceptions:
print("*** цель в списке исключений")
return False # "действие провалено"
if (target.alive == "на цепи"):
print("в момент применения действия цель на цепи")
if (target.alive == "убит") or (target.alive == "казнен"):
print("в момент применения действия цель мертва")
return True
####### --- создание ролей, заполнение вспомогательных словарей ---
nicknames_dict = {} # вспомогательный словарь "ник игрока" -> "соответствующая роль" для доступа к ролям по никам игроков
rolenames_dict = {} # вспомогательный словарь "название роли" -> "соответствующая роль" для доступа к ролям по названию
current_votes_dict = {} # реальные, а не эталонные голоса для печати таблицы подсчета голосов
for row in players:
# создается экземпляр объекта "Роль" (ник игрока, команда, роль, статус, квента, голос) и записывается в словарь по ключу "ник игрока"
nicknames_dict[row[0]] = Role(row[0], row[2], row[3], row[4], row[1], row[5])
rolenames_dict[row[3]] = nicknames_dict[row[0]] # тот же экземпляр объекта "Роль" записывается в словарь по ключу "название роли"
if night_no > 1 and len(current_alive_dict["жив"])>0: # во все ночи кроме первой
for row in (current_alive_dict["на цепи"]):
nicknames_dict[row].change_alive("на цепи") # выставляем значения alive="на цепи" для всех посаженых на цепь
nicknames_dict[row].set_block() # выставляем значения "блокирован" для всех посаженых на цепь
nicknames_dict[row].set_vote(0) # - вес голоса = 0 для всех посаженых на цепь
for row in (current_alive_dict["убит"]):
nicknames_dict[row].change_alive("убит") # выставляем значения alive="убит" для всех убитых
for row in (current_alive_dict["казнен"]):
nicknames_dict[row].change_alive("казнен") # выставляем значения alive="казнен" для всех казненных
####### дописываем ролям НД и особенности
### Фритйоф
# Особенности:
rolenames_dict["Фритйоф"].set_vote(2) # - двойной голос
# - НД Безумия не действуют на Фритйофа - ДОБАВЛЕНО В СПИСОК ИСКЛЮЧЕНИЙ
# ДД: один раз за игру казнит выбранного игрока, закрывает день - НЕ РЕАЛИЗОВАННО
# Йороар
# Особенности: - не перенаправляется
# НД1: - сравнивает один из статусов двух игроков
class Action_compare(Action): # класс для создания НД "сравнение статуса номер no" (no = 1 или 2)
def __init__(self, owner, actionname, priority, display, exceptions=[], targets_qlty=2):
Action.__init__(self, owner, actionname, priority, display, exceptions, 2)# вызвать конструктор суперкласса
def do(self,targets,params): # сравнить цели targets по статусу номер params[0] (params[0] = 1 или 2)
if Action.do(self, targets): # вызвать метод суперкласса
if targets[0].get_status_no(params[0]) == targets[1].get_status_no(params[0]):
rec = "статусы одинаковы"
else:
rec = "статусы разные"
return rec # результат сравнения статусoв
return False
# НД2: - сообщает результат сравнения Фритйофу
class Action_message(Action): # класс для создания НД "отправка сообщения Фритйофу"
def __init__(self, owner, actionname, priority, display, exceptions=[], targets_qlty=0):
Action.__init__(self, owner, actionname, priority, display, exceptions, 0)# вызвать конструктор суперкласса
def do(self,empty,params): # отправка Фритйофy сообщения params[0]
if Action.do(self, [rolenames_dict["Фритйоф"]]): # вызвать метод суперкласса
return "отправить сообщение '"+params[0]+"' для "+rolenames_dict["Фритйоф"].nickname+" (роль Фритйоф) " # отправка сообщения
return False
### Холкхак
# НД: проверяет первый статус выбранного игрока
class Action_check_no_one(Action): # класс для создания НД "проверка статуса номер 1"
def do(self, targets, params):
if Action.do(self, targets): # вызвать метод суперкласса
return targets[0].get_status_no(1) # результат проверки статуса номер 1
return False
### Хьялйот
# НД: - блокирует выбранного игрока
class Action_block(Action): # класс для НД "блокировка цели"
def do(self, targets, params):
if Action.do(self, targets): # вызвать метод суперкласса
return targets[0].set_block() # блокировать цель
return False
### Глариэл
# НД: - проверяет второй статус выбранного игрока
class Action_check_no_two(Action): # класс для создания НД "проверка статуса номер 2"
def do(self, targets, params):
if Action.do(self, targets): # вызвать метод суперкласса
return targets[0].get_status_no(2) # результат проверки статуса номер 2
return False
### Флавий
# Особенности:
# - нельзя сменить первый статус - НЕ РЕАЛИЗОВАННО
# - не может быть убит Холодом
# НД1: - защищает выбранного игрока
class Action_defend(Action): # класс для НД "защита цели"
def do(self, targets, params):
if Action.do(self, targets): # вызвать метод суперкласса
targets[0].defender = self.owner # добавить защитника в спутники цели :)
return "успех"
return False
# НД2: - лечит выбранного игрока от Холода
class Action_heal_frozen(Action): # класс для НД "лечение цели от Холода"
def do(self, targets, params):
if Action.do(self, targets): # вызвать метод суперкласса
if targets[0].killer == rolenames_dict["Холод"]: # если убийца Холод приходил к цели успешно
targets[0].change_alive("жив") # вылечить цель
return "лечение успешно"
return "лечение от Холода не требуется"
return False
### Эсбен
# Особенности: - не перенаправляется
# НД1: - садит на цепь выбранного игрока, игрок не может совершать НД ночью, голос не засчитывается, может участвовать в обсуждении днем (после смерти все посаженные на цепь освобождаются)
class Action_put_on_fetters(Action): # класс для создания НД "посадить на цепь"
def do(self, targets, params):
if Action.do(self, targets): # вызвать метод суперкласса
if targets[0].alive == "жив":
targets[0].set_vote(0)
targets[0].change_alive("на цепи") # на цепь
return "успешно"
return False
# НД2: - снимает цепь с выбранного игрока
class Action_take_off_fetters(Action): # класс для создания НД "снять цепь"
def do(self, targets, params):
if Action.do(self, targets): # вызвать метод суперкласса
targets[0].set_vote(1)
if targets[0].rolename == "Фритйоф":
targets[0].set_vote(2)
if targets[0].alive == "на цепи":
targets[0].change_alive("жив") # с цепи
return "успешно"
return False
# в случае убийства Эсбена цепи снимаются со всех, но с рассветом
# в случае убийства и лечения Эсбена все остаются в цепях
# освобождение от блока дает право действовать посаженному на цепь
### Стигйор
# Особенности: - НД Безумия не действуют на Стигйора
# НД: - лечит выбранного игрока (нельзя лечить самого себя)
class Action_heal(Action): # класс для НД "лечение цели"
def do(self, targets, params):
if Action.do(self, targets): # вызвать метод суперкласса
if targets[0].killer != None: # если убийца приходил к цели успешно
targets[0].change_alive("жив") # вылечить цель
return "лечение успешно"
return "лечение не требуется"
return False
### Ральфйор
# Особенности: - не может быть убит Голодом
# НД1: - дает игроку возможность использовать НД дважды за ночь - НЕ РЕАЛИЗОВАННО
# НД2: - защищает выбранного игрока от Голода - (от убийства) - пишет ему в список исключений свою цель (т.е. защита не знает, пригодилась она или нет)
class Action_defend_from_Famine(Action): # класс для НД "защита цели от Голода"
def do(self, targets, params):
if Action.do(self, targets): # вызвать метод суперкласса
rolenames_dict["Голод"].actions["Убийство"].add_exception(targets[0]) # добавить цель в список исключений НД "Убийство Голода"
return "успех" # добавить цель в список исключений НД "Убийство Голода"
return False
### Аврелий
# НД1: - следит за выбранным игроком, если того убивают, узнает ник убийцы (один раз в две ночи) - НЕ РЕАЛИЗОВАННО
# НД2: - освобождает от всех блоков - НЕ РЕАЛИЗОВАННО
### Безумие
# НД1: - перенаправляет выбранного игрока - НЕ РЕАЛИЗОВАННО
# НД2: - меняет статусы выбранному игроку на одну ночь (СЧИТАЮ, ЧТО СТАТУС МЕНЯЕТСЯ НА ТЕКУЩУЮ НОЧЬ)
class Action_change_statuses(Action): # класс для НД "смена статуса"
def do(self, targets, params):
if Action.do(self, targets): # вызвать метод суперкласса
return targets[0].set_statuses(params[0]) # сменить статус
return False
# НД3: - убивает выбранного игрока
class Action_kill(Action): # класс для НД "убийство цели", возвращает квенту убийцы
def do(self, targets, params):
if Action.do(self, targets): # вызвать метод суперкласса
if targets[0].defender == None:
targets[0].change_alive("убит") # убить цель
targets[0].killer = self.owner # записать убийцу
return self.owner.quenta # квента на убийцу
print ("цель защищена Флавием")
return False
### Холод
# НД1: - ограничивает дневное голосование выбранного игрока тремя кандидатурами по выбору мафии и вариантом "ННВ". ГМ отправляет список игроку. - НЕ РЕАЛИЗОВАННО
# НД2: - убивает выбранного игрока, игнорирует лечение Стигйора - т.е. пишет ему в список исключений свою цель, если убийство состоялось.
class Action_kill_through_heal(Action_kill): # класс для НД "убийство цели с игнором лечения Стигйора"
def do(self, targets, params):
if Action_kill.do(self, targets): # вызвать метод суперкласса
rolename_dict["Стигйор"].actions["Лечение"].add_exception(targets[0]) # добавить цель в список исключений НД "Лечение Стигйора"
return self.owner.quenta # квента на убийцу
return False
### Голод
# НД1: - блокирует выбранного игрока - class Action_block(Action)
# НД2: - убивает выбранного игрока, игнорирует защиту Флавия
class Action_kill_through_protection(Action): # класс для НД "убийство цели с игнором защиты Флавия", возвращает квенту убийцы
def do(self, targets, params):
if Action.do(self, targets): # вызвать метод суперкласса
targets[0].change_alive("убит") # убить цель
targets[0].killer = self.owner # записать убийцу
return self.owner.quenta # квента на убийцу
return False
### Смерть
# НД1: - убивает выбранного игрока - см. class Action_kill
# НД2: - убивает выбранного игрока, не оставляет улик (раз в три ночи, начиная со второй)
class Action_kill_clean(Action_kill): # класс для НД "убийство цели без улик"
def do(self, targets, params):
if Action_kill.do(self, targets): # вызвать метод суперкласса
return "без улик" # квента на убийцу отсутствует
return False
####### ПОРЯДОК НД (приоритет НД зависит от номера строки в списке)
# исполнитель, наименование и отображение НД, а также техническая информация - класс для создания НД и исключения
priority_list = [
["Безумие", "Смена статусов", "факт", Action_change_statuses, ["Фритйоф", "Стигйор"]],
["Хьялйот", "Блок", "да", Action_block],
["Голод", "Блок", "да", Action_block],
["Йороар", "Сравнение", "нет", Action_compare],
["Йороар", "Сообщение", "нет", Action_message],
["Холкхак", "Проверка", "нет", Action_check_no_one],
["Глариэл", "Проверка", "нет", Action_check_no_two],
["Флавий", "Защита", "да", Action_defend],
["Ральфйор", "Защита от Голода", "да", Action_defend_from_Famine],
["Холод", "Убийство", "да", Action_kill_through_heal, ["Флавий"]],
["Голод", "Убийство", "да", Action_kill_through_protection, ["Ральфйор"]],
["Безумие", "Убийство", "да", Action_kill, ["Фритйоф", "Стигйор"]],
["Смерть", "Убийство", "да", Action_kill],
["Смерть", "Убийство без улик", "да", Action_kill_clean],
["Флавий", "Лечение от Холода", "да", Action_heal_frozen],
["Стигйор", "Лечение", "да", Action_heal],
["Эсбен", "На цепь", "да", Action_put_on_fetters],
["Эсбен", "Снять цепь", "да", Action_take_off_fetters]
]
for i in range(1,len(priority_list)+1): # приоритет НД = номер строки в списке (нумеруется с 1)
row = priority_list[i-1]
if len(row)