From 4291446cf2f6fc85e72bd5f84cc5f0aa53568bd5 Mon Sep 17 00:00:00 2001 From: aeirya Date: Wed, 16 Sep 2020 12:59:57 +0430 Subject: [PATCH 01/15] added role and team classes --- Role.py | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 Role.py diff --git a/Role.py b/Role.py new file mode 100644 index 0000000..df28404 --- /dev/null +++ b/Role.py @@ -0,0 +1,30 @@ +from dataclasses import dataclass +import mafia_params + +@dataclass +class Team: + name : str + + def __repr__(self) -> str: + return self.name.capitalize() + +@dataclass(frozen= True) +class Role: + name : str + team : Team + + def get_description(self, is_english : bool = True) -> str: + if (is_english): + return mafia_params.descriptions.get(self.name) + return mafia_params.descriptions_fa.get(self.name) + + def is_mafia(self) -> bool: + return self.team == MAFIA + +# Teams initiation +MAFIA = Team("mafia") +CITY = Team("city") + +#Roles initiation +RESIDENT = Role("Resident", CITY) +MAFIA = Role("Mafia", MAFIA) From 3d21fde8dd9157362a1449e8b1ea4b1cbf0fc9ea Mon Sep 17 00:00:00 2001 From: aeirya Date: Wed, 16 Sep 2020 13:58:28 +0430 Subject: [PATCH 02/15] replaced duplicate render_template("404.html") code with the function not_found_page() --- mafia.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/mafia.py b/mafia.py index abc8b12..6cb2a62 100644 --- a/mafia.py +++ b/mafia.py @@ -1,5 +1,6 @@ from sys import argv from random import randrange, shuffle +from typing import Text from flask import Flask, render_template, url_for, request from flask_httpauth import HTTPBasicAuth from mafia_params import ordered_roles, nRoles, role2team, descriptions, descriptions_fa, role2fa @@ -35,7 +36,7 @@ def index(): return render_template("Player.html", player=ip2player[ip]) else: if player_id > nPlayers: - return render_template("404.html", is_farsi=True) + return not_found_page() role = roles[player_id] image_name = role + "_" + str(randrange(1, nRoles[role] + 1)) ip2player[ip] = Player(ip, username, role, image_name) @@ -70,7 +71,7 @@ def GOD_PAGE(): else: ip2player[ip].set_state("alive") else: - return render_template("404.html", is_farsi=True) + return not_found_page() if request.args.get("Ban") is not None: ip = request.args.get("Ban") if ip in ip2player.keys(): @@ -79,7 +80,7 @@ def GOD_PAGE(): elif ip2player[ip].get_state() == "banned": ip2player[ip].set_state("alive") else: - return render_template("404.html", is_farsi=True) + return not_found_page() if request.args.get("Comment") is not None: ip = request.args.get("Comment") if ip in ip2player.keys(): @@ -95,7 +96,7 @@ def GOD_PAGE(): nComments -= 1 comments_ordered.remove(ip) else: - return render_template("404.html", is_farsi=True) + return not_found_page() return render_template("GOD.html", ip2player=ip2player, prompt_message=msg, roles={role:roles.count(role) for role in set(roles)}, comments=comments_ordered, role2team=role2team) @@ -103,8 +104,10 @@ def GOD_PAGE(): @app.errorhandler(404) def invalid_route(e): - return render_template("404.html", is_farsi=True) + return not_found_page() +def not_found_page() -> Text: + return render_template("404.html", is_farsi=True) def help_me(): usage = "-" * 70 + "\n" From e25b00a4f3e8092f0610cb76a6c8237b767d2f06 Mon Sep 17 00:00:00 2001 From: aeirya Date: Wed, 16 Sep 2020 14:56:21 +0430 Subject: [PATCH 03/15] trying to reduce cognitive complexity of god_page function --- mafia.py | 76 +++++++++++++++++++++++++++++++++----------------------- 1 file changed, 45 insertions(+), 31 deletions(-) diff --git a/mafia.py b/mafia.py index 6cb2a62..56d3779 100644 --- a/mafia.py +++ b/mafia.py @@ -1,6 +1,6 @@ from sys import argv from random import randrange, shuffle -from typing import Text +from typing import Callable, Dict, Text from flask import Flask, render_template, url_for, request from flask_httpauth import HTTPBasicAuth from mafia_params import ordered_roles, nRoles, role2team, descriptions, descriptions_fa, role2fa @@ -61,42 +61,56 @@ def verify_password_god(username, password): @app.route('/GOD') @auth_GOD.login_required def GOD_PAGE(): - global ip2player, nComments, comments_ordered + global ip2player + + #get ip or throw 404 + ip = None + req = None + for key in ["Kill", "Ban", "Comment"]: + ip = request.args.get(key) + if ip is not None and ip in ip2player.keys(): + req = key + break + else: return not_found_page() + msg = "" - if request.args.get("Kill") is not None: - ip = request.args.get("Kill") - if ip in ip2player.keys(): - if ip2player[ip].get_state() == "alive": + + def kill() -> None: + if ip2player[ip].get_state() == "alive": ip2player[ip].set_state("dead") - else: - ip2player[ip].set_state("alive") else: - return not_found_page() - if request.args.get("Ban") is not None: - ip = request.args.get("Ban") - if ip in ip2player.keys(): - if ip2player[ip].get_state() == "alive": + ip2player[ip].set_state("alive") + + def ban() -> None: + + if ip2player[ip].get_state() == "alive": ip2player[ip].set_state("banned") - elif ip2player[ip].get_state() == "banned": - ip2player[ip].set_state("alive") - else: - return not_found_page() - if request.args.get("Comment") is not None: - ip = request.args.get("Comment") - if ip in ip2player.keys(): - if ip2player[ip].get_comment() is False: - if nComments <= nPlayers // 3: - ip2player[ip].set_comment(True) - nComments += 1 - comments_ordered.append(ip) - else: - msg = "Error: Out of Comments." + elif ip2player[ip].get_state() == "banned": + ip2player[ip].set_state("alive") + + def comment() -> None: + if ip2player[ip].get_comment() is False: + global nComments, comments_ordered + if nComments <= nPlayers // 3: + ip2player[ip].set_comment(True) + nComments += 1 + comments_ordered.append(ip) else: - ip2player[ip].set_comment(False) - nComments -= 1 - comments_ordered.remove(ip) + nonlocal msg + msg = "Error: Out of Comments." else: - return not_found_page() + ip2player[ip].set_comment(False) + nComments -= 1 + comments_ordered.remove(ip) + + request_mapper : Dict[Callable] = { + "Kill", kill, + "Ban", ban, + "Comment", comment + } + + request_mapper[req]() + return render_template("GOD.html", ip2player=ip2player, prompt_message=msg, roles={role:roles.count(role) for role in set(roles)}, comments=comments_ordered, role2team=role2team) From ee94608120711019054ea6a7b06a8deb25c0850c Mon Sep 17 00:00:00 2001 From: aeirya Date: Wed, 16 Sep 2020 15:46:43 +0430 Subject: [PATCH 04/15] cleaning god_page: .using player var instead of direct access to array . moved request filtering to a function --- mafia.py | 70 +++++++++++++++++++++++++++++--------------------------- 1 file changed, 36 insertions(+), 34 deletions(-) diff --git a/mafia.py b/mafia.py index 56d3779..7febea6 100644 --- a/mafia.py +++ b/mafia.py @@ -1,6 +1,6 @@ from sys import argv from random import randrange, shuffle -from typing import Callable, Dict, Text +from typing import Callable, Dict, List, Text, Tuple from flask import Flask, render_template, url_for, request from flask_httpauth import HTTPBasicAuth from mafia_params import ordered_roles, nRoles, role2team, descriptions, descriptions_fa, role2fa @@ -60,48 +60,33 @@ def verify_password_god(username, password): @app.route('/GOD') @auth_GOD.login_required -def GOD_PAGE(): - global ip2player - - #get ip or throw 404 - ip = None - req = None - for key in ["Kill", "Ban", "Comment"]: - ip = request.args.get(key) - if ip is not None and ip in ip2player.keys(): - req = key - break - else: return not_found_page() - - msg = "" - - def kill() -> None: - if ip2player[ip].get_state() == "alive": - ip2player[ip].set_state("dead") +def god_page(): + def kill(player : Player) -> None: + if player.get_state() == "alive": + player.set_state("dead") else: - ip2player[ip].set_state("alive") + player.set_state("alive") - def ban() -> None: - - if ip2player[ip].get_state() == "alive": - ip2player[ip].set_state("banned") - elif ip2player[ip].get_state() == "banned": - ip2player[ip].set_state("alive") + def ban(player : Player) -> None: + if player.get_state() == "alive": + player.set_state("banned") + elif player.get_state() == "banned": + player.set_state("alive") - def comment() -> None: - if ip2player[ip].get_comment() is False: + def comment(player : Player) -> None: + if player.get_comment() is False: global nComments, comments_ordered if nComments <= nPlayers // 3: - ip2player[ip].set_comment(True) + player.set_comment(True) nComments += 1 - comments_ordered.append(ip) + comments_ordered.append(player.get_ip()) else: nonlocal msg msg = "Error: Out of Comments." else: - ip2player[ip].set_comment(False) + player.set_comment(False) nComments -= 1 - comments_ordered.remove(ip) + comments_ordered.remove(player.get_ip()) request_mapper : Dict[Callable] = { "Kill", kill, @@ -109,8 +94,25 @@ def comment() -> None: "Comment", comment } - request_mapper[req]() - + def get_requests() -> List[Tuple[str, Player]]: + requests = [] + for key in request_mapper.keys(): + ip = request.args.get(key) + if ip is not None and ip in ip2player.keys(): + player = ip2player[ip] + requests.append((key, player)) + else: print("invalid ip / request: ", ip, f"({key})") + return requests + + msg = "" + + request_list = get_requests() + if len(request_list) == 0: + return not_found_page() + + for req, player in request_list: + request_mapper[req](player) + return render_template("GOD.html", ip2player=ip2player, prompt_message=msg, roles={role:roles.count(role) for role in set(roles)}, comments=comments_ordered, role2team=role2team) From ffe5eb1b803ca6b6f1b03861c3c4c83d917cad25 Mon Sep 17 00:00:00 2001 From: aeirya Date: Wed, 16 Sep 2020 16:38:24 +0430 Subject: [PATCH 05/15] . reduced complexity of god_page function . edited player class converted to a data class added functions die, is_alive, ban, unban, switch_ban . added max_comments function --- mafia.py | 48 +++++++++++++++++++++++++----------------------- mafia_params.py | 2 ++ player.py | 48 +++++++++++++++++++++++++++++++++++++----------- 3 files changed, 64 insertions(+), 34 deletions(-) diff --git a/mafia.py b/mafia.py index 7febea6..a8cc234 100644 --- a/mafia.py +++ b/mafia.py @@ -3,7 +3,7 @@ from typing import Callable, Dict, List, Text, Tuple from flask import Flask, render_template, url_for, request from flask_httpauth import HTTPBasicAuth -from mafia_params import ordered_roles, nRoles, role2team, descriptions, descriptions_fa, role2fa +from mafia_params import ordered_roles, nRoles, role2team, descriptions, descriptions_fa, role2fa, max_comments from player import Player app = Flask(__name__) @@ -62,27 +62,24 @@ def verify_password_god(username, password): @auth_GOD.login_required def god_page(): def kill(player : Player) -> None: - if player.get_state() == "alive": - player.set_state("dead") - else: - player.set_state("alive") + # notice banned players cannot be killed + if player.is_alive(): + player.die() - def ban(player : Player) -> None: - if player.get_state() == "alive": - player.set_state("banned") - elif player.get_state() == "banned": - player.set_state("alive") + def switch_ban(player : Player) -> None: + player.switch_ban() def comment(player : Player) -> None: + if nComments > max_comments(nPlayers): + nonlocal msg + msg = "Error: Out of Comments." + return + if player.get_comment() is False: global nComments, comments_ordered - if nComments <= nPlayers // 3: - player.set_comment(True) - nComments += 1 - comments_ordered.append(player.get_ip()) - else: - nonlocal msg - msg = "Error: Out of Comments." + player.set_comment(True) + nComments += 1 + comments_ordered.append(player.get_ip()) else: player.set_comment(False) nComments -= 1 @@ -90,18 +87,23 @@ def comment(player : Player) -> None: request_mapper : Dict[Callable] = { "Kill", kill, - "Ban", ban, + "Ban", switch_ban, "Comment", comment } + # filters out invalid requests def get_requests() -> List[Tuple[str, Player]]: requests = [] for key in request_mapper.keys(): ip = request.args.get(key) - if ip is not None and ip in ip2player.keys(): - player = ip2player[ip] - requests.append((key, player)) - else: print("invalid ip / request: ", ip, f"({key})") + + if ip is None or ip not in ip2player.keys(): + print("invalid ip / request: ", ip, f"({key})") + continue + + player = ip2player[ip] + requests.append((key, player)) + return requests msg = "" @@ -110,6 +112,7 @@ def get_requests() -> List[Tuple[str, Player]]: if len(request_list) == 0: return not_found_page() + # handle requests for req, player in request_list: request_mapper[req](player) @@ -117,7 +120,6 @@ def get_requests() -> List[Tuple[str, Player]]: prompt_message=msg, roles={role:roles.count(role) for role in set(roles)}, comments=comments_ordered, role2team=role2team) - @app.errorhandler(404) def invalid_route(e): return not_found_page() diff --git a/mafia_params.py b/mafia_params.py index 7cb27b0..2e7a020 100644 --- a/mafia_params.py +++ b/mafia_params.py @@ -1,3 +1,5 @@ +max_comments : int = lambda nPlayers : nPlayers // 3 + ordered_roles = ["Resident", "Don", "Resident", diff --git a/player.py b/player.py index 9550bea..f9ba8a9 100644 --- a/player.py +++ b/player.py @@ -1,12 +1,39 @@ +from dataclasses import dataclass +from typing import List + +class PlayerState: + ALIVE : str = "alive" + DEAD: str = "dead" + BANNED: str = "banned" + all: List[str] = [ALIVE, DEAD, BANNED] + +"""A player in mafia game""" +@dataclass class Player: - """A player in mafia game""" - def __init__(self, ip, username, role, image_name): - self.ip = ip - self.username = username - self.state = "alive" - self.role = role - self.image_name = image_name - self.comment = False + ip : str + username : str + role : str + image_name : str + state : PlayerState = PlayerState.ALIVE + comment : bool = False + + def is_alive(self) -> bool: + return self.state == PlayerState.ALIVE + + def die(self) -> None: + self.state = PlayerState.DEAD + + def switch_ban(self): + self.unban() if self.is_banned() else self.ban() + + def is_banned(self) -> bool: + return self.state == PlayerState.BANNED + + def ban(self): + self.state = PlayerState.BANNED + + def unban(self): + self.state = PlayerState.ALIVE def get_state(self): return self.state @@ -26,11 +53,10 @@ def get_image_name(self): def get_comment(self): return self.comment - def set_state(self, state): - if state in ["alive", "dead", "banned"]: + if state in PlayerState.all: self.state = state - + def set_comment(self, comment): self.comment = comment \ No newline at end of file From 6cc39447676847a0c1cadb9ff1872a2eef0e4296 Mon Sep 17 00:00:00 2001 From: aeirya Date: Wed, 16 Sep 2020 16:56:20 +0430 Subject: [PATCH 06/15] edited main function. refactored key generation, and added comments --- mafia.py | 39 +++++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/mafia.py b/mafia.py index a8cc234..de7620b 100644 --- a/mafia.py +++ b/mafia.py @@ -34,17 +34,18 @@ def index(): if ip in ip2player.keys(): return render_template("Player.html", player=ip2player[ip]) - else: - if player_id > nPlayers: - return not_found_page() - role = roles[player_id] - image_name = role + "_" + str(randrange(1, nRoles[role] + 1)) - ip2player[ip] = Player(ip, username, role, image_name) - print("*" * 20, "New Player","*" * 20) - toGod = ip + " : " + str(player_id) + " : " + username + " --> " + role - toGod += "/" + role2fa[role] #TODO: Just in Farsi Mode - print(toGod) - player_id += 1 + + if player_id > nPlayers: + return not_found_page() + + role = roles[player_id] + image_name = role + "_" + str(randrange(1, nRoles[role] + 1)) + ip2player[ip] = Player(ip, username, role, image_name) + print("*" * 20, "New Player","*" * 20) + toGod = ip + " : " + str(player_id) + " : " + username + " --> " + role + toGod += "/" + role2fa[role] #TODO: Just in Farsi Mode + print(toGod) + player_id += 1 return render_template("index.html", image_name=image_name, role_name=role, role_name_fa=role2fa[role], @@ -169,22 +170,32 @@ def give_me_roles(ordered_roles): pass return ordered_roles +def gen_preshared_key() -> str: + key = "" + chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789!@#$%^&*()" + for _ in range(4): + key += chars[randrange(0, len(chars))] + return key if __name__ == "__main__": + # parse args if len(argv) < 2 or argv[1] in ['--help', 'help', '-h']: help_me() nPlayers = int(argv[1]) + + # make roles if nPlayers > len(ordered_roles): print("Too many players, mafia doesn't support a game with", nPlayers, "player.") help_me() roles = give_me_roles(ordered_roles[:nPlayers]) shuffle(roles) - chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789!@#$%^&*()" - for i in range(4): - preshared_key += chars[randrange(0, len(chars))] + + # preshared key generation + preshared_key = gen_preshared_key() print("_" * 20 + "GOD's password" + "_" * 20) print(preshared_key) print("_" * 54) + app.run(host="0.0.0.0", port=5000, use_reloader=False) From da511522c907cda3a7b0ff15d59892b9fd7fdaf0 Mon Sep 17 00:00:00 2001 From: aeirya Date: Wed, 16 Sep 2020 17:21:26 +0430 Subject: [PATCH 07/15] edited mafia. added comments --- mafia.py | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/mafia.py b/mafia.py index de7620b..5507328 100644 --- a/mafia.py +++ b/mafia.py @@ -10,10 +10,12 @@ auth = HTTPBasicAuth() auth_GOD = HTTPBasicAuth() preshared_key = "" + +ip2player = {} +roles = [] player_id = 0 nPlayers = 0 -roles = [] -ip2player = {} + nComments = 0 comments_ordered = [] @@ -21,44 +23,47 @@ def verify_password(username, password): if len(username) > 0: return username - return None @app.route('/') @auth.login_required def index(): - global player_id, ip2player username = str(auth.current_user()) - role = "" - image_name = "" ip = str(request.remote_addr) + # redirect current players if ip in ip2player.keys(): return render_template("Player.html", player=ip2player[ip]) + # reject excess players + global player_id if player_id > nPlayers: return not_found_page() + # create new player role = roles[player_id] image_name = role + "_" + str(randrange(1, nRoles[role] + 1)) ip2player[ip] = Player(ip, username, role, image_name) + + # next player id + player_id += 1 + + # log new player print("*" * 20, "New Player","*" * 20) - toGod = ip + " : " + str(player_id) + " : " + username + " --> " + role - toGod += "/" + role2fa[role] #TODO: Just in Farsi Mode - print(toGod) - player_id += 1 + to_god = ip + " : " + str(player_id) + " : " + username + " --> " + role + to_god += "/" + role2fa[role] #TODO: Just in Farsi Mode + print(to_god) + return render_template("index.html", image_name=image_name, role_name=role, role_name_fa=role2fa[role], description=descriptions[role], description_fa=descriptions_fa[role], is_farsi=True) - @auth_GOD.verify_password def verify_password_god(username, password): if password == preshared_key: return username - @app.route('/GOD') @auth_GOD.login_required def god_page(): @@ -140,7 +145,6 @@ def help_me(): print(usage) exit() - def give_me_roles(ordered_roles): """ Check the number of players and roles. @@ -198,4 +202,4 @@ def gen_preshared_key() -> str: app.run(host="0.0.0.0", port=5000, - use_reloader=False) + use_reloader=False) \ No newline at end of file From 85d03b93727b7763223b38d09537f0e382cdf90a Mon Sep 17 00:00:00 2001 From: aeirya Date: Wed, 16 Sep 2020 17:42:21 +0430 Subject: [PATCH 08/15] refactored mafia_params to different json files --- config.py | 10 ++ config/english.json | 34 ++++++ config/mafia_param.json | 104 ++++++++++++++++++ config/persian.json | 68 ++++++++++++ lang.py | 20 ++++ mafia_params.py | 233 ++-------------------------------------- 6 files changed, 243 insertions(+), 226 deletions(-) create mode 100644 config.py create mode 100644 config/english.json create mode 100644 config/mafia_param.json create mode 100644 config/persian.json create mode 100644 lang.py diff --git a/config.py b/config.py new file mode 100644 index 0000000..6027b85 --- /dev/null +++ b/config.py @@ -0,0 +1,10 @@ +import json +from typing import Dict + + +config_path : str = "config/" + +def load_data(filename : str) -> Dict: + with open(config_path + filename) as f: + data = json.load(f) + return data diff --git a/config/english.json b/config/english.json new file mode 100644 index 0000000..8745cb5 --- /dev/null +++ b/config/english.json @@ -0,0 +1,34 @@ +{ + "descriptions": { + "Boxor" : "Boxor is a member of mafia team. Boxor hits one of the players at night and the one who hited Can't deffend oneself during day phase due to it's hit effect.", + "Bride" : "Bride is a member of city team. Bride has been engaged to Groom recently at nigh both of them will get up and see each other after death of each one of them, other one can kill anyone as a revenge of his/her sweetheart at night phase.", + "Bulletproof" : "Bulletproof is the most powerful resident which doesn't hurt from night shots. he/she won't die through night phase.", + "Bus Driver" : "Bus Driver is city team member. He/She can switch two player which means each shot/question from first one will hurt/asked from second one.", + "Chef" : "Chef is critical member of city team. After his/her death city team should win at last after 3 days. Clown can do this just for one time and this should take place at night, GOD should be informed whos role to be reavealed.", + "Curious Kid" : "He/She is a member of city team which can open his/her eyes and spy on mafias in the way that no one can see him/her.", + "Detective" : "Detective is from city team gets up at night phase and tries to ask GOD if someone is good (Resident, Doctor, Rebel, Bulletproof) or bad(Mafia), but his/her first attempt to ask from Don may be answered incorrect by GOD.", + "Doctor": "Doctor is a helpful participant of city team which gets up after mafia team and tries to rescue a person (or two in the first night) from mafia's shot.", + "Don" : "Don is the boss of the mafia group. At night phsae Don decides whom to be killed from the mafia team. Don can't be detected by detective.", + "Genie" : "Genie is a kind member of city team despite his/her name. Genie selects a player at night and GOD will ask the player to wish something and his/her wish will come true. Genie can use his/her power just three time in a game.", + "Grandma" : "Grandma with gun is a frightening member of city team. She will kill anyone who tries to kill her at night. Mafia and other roles with kiling power should be aware of her.", + "Groom" : "Groom is a member of city team. Groom has been engaged to Bride recently at nigh both of them will get up and see each other after death of each one of them, other one can kill anyone as a revenge of his/her sweetheart at night phase.", + "Hit Man" : "Hit Man is a rather powerful member of mafia team. His/Her shots won't fail even if the doctor save or the victim is Bulletproof. Hit Man can use his shot only one time during the game his shot will be replaced by one of mafia's night shot.", + "Insane" : "Insane is a member of city team. GOD will infrom Insane who is aiming at his/her neighbors (left hand player or right hand player).", + "Jailer" : "Jailer is a member of city team. Jailer can bust any player at night phase, one who has been busted won't play at earlier day phase just for a night.", + "Judge" : "Judge is a member of city team. Judge can reveal his role and decide to kill a player at day phase, Judge can use his/her power only once during the game.", + "Kind Wife" : "Kind Wife is mafia team's sweetheart. After the day she died the mafia team get up and kill two suspects instead of one to take her revenge.", + "Lawyer" : "Lawyer is from mafia team. Lawyer wakes up at night and inform the GOD whom should be sued to be to the court for next day phase.", + "Made Man" : "Made Man is the one of the most powerful participant of the mafia team. Made Man gets up at night and turn one of the members of city team to Mafia.", + "Mafia" : "Mafia is the simple participant of the mafia team. Mafia gets up at night and try to decide which one of the players they want to kill, detective can detect this kind of mafia in night phase.", + "Magician" : "Magician is member of city team. He/She decides to kill or save a player during night and can use his/her power just once during the game.", + "Miller" : "Miller is a member of city team. When Detective ask GOD about Millers role the result will be bad(Mafia) so Detective will be confused about Millers role and asume he/she as a mafia team member.", + "Postman" : "Postman is a member of city team. After Postman's death he/she can select a player to die with him/her. With this power Postman can help city team by killing a mafia member.", + "Priest" : "", + "Rebel" : "Rebel is from city team which gets up at night phase and kills a person.if the victim was chosen from residents, Rebel (him/her)self may die.", + "Reporter" : "Reporter is a city team member. GOD will inform Reporter who was chosen by Made Man to become Mafia.", + "Resident" : "Resident is the typical player of the game. he/she has no power but to blame mafia in order to remove them from the game in day phase.", + "Serial Killer" : "Serial Killer is a seperate team. He/She wakes up once each two night and shot a player. Serial Killer will win if He/She is in last three players.", + "Student" : "Student is a innocent city team member. After His/Her death, players will kill two players at day court.", + "Undercover Cop" : "Undercover Cop is a member of city team but he/she will act just like mafia (wakes up at night) and decide whome to be killed)." + } +} \ No newline at end of file diff --git a/config/mafia_param.json b/config/mafia_param.json new file mode 100644 index 0000000..0dbb53c --- /dev/null +++ b/config/mafia_param.json @@ -0,0 +1,104 @@ +{ + "ordered_roles" : [ + "Resident", + "Don", + "Resident", + "Detective", + "Doctor", + "Hit Man", + "Rebel", + "Bulletproof", + "Mafia", + "Resident", + "Resident", + "Mafia", + "Resident", + "Resident", + "Mafia", + "Doctor", + "Chef", + "Mafia", + "Detective", + "Miller", + "Mafia", + "Undercover Cop", + "Grandma", + "Mafia", + "Student", + "Postman", + "Mafia", + "Clown", + "Resident", + "Mafia", + "Resident", + "Resident" + ], + + "nRoles" : { + "Boxer" : 2, + "Bride" : 5, + "Bulletproof" : 9, + "Bus Driver" : 3, + "Chef" : 3, + "Clown" : 2, + "Curious Kid" : 2, + "Detective" : 3, + "Doctor" : 10, + "Don" : 4, + "Genie" : 2, + "Grandma" : 2, + "Groom" : 4, + "Hit Man" : 2, + "Insane" : 3, + "Jailer" : 2, + "Judge" : 6, + "Kind Wife" : 4, + "Lawyer" : 3, + "Made Man" : 2, + "Mafia" : 9, + "Magician" : 4, + "Miller" : 3, + "Postman" : 3, + "Priest" : 3, + "Rebel" : 3, + "Reporter" : 6, + "Resident" : 21, + "Serial Killer" : 6, + "Student" : 2, + "Undercover Cop" : 2 + }, + + "role2team" : { + "Boxer" : "mafia", + "Bride" : "city", + "Bulletproof" : "city", + "Bus Driver" : "city", + "Chef" : "city", + "Clown" : "city", + "Curious Kid" : "city", + "Detective" : "city", + "Doctor" : "city", + "Don" : "mafia", + "Genie" : "city", + "Grandma" : "city", + "Groom" : "city", + "Hit Man" : "mafia", + "Insane" : "city", + "Jailer" : "city", + "Judge" : "city", + "Kind Wife" : "mafia", + "Lawyer" : "mafia", + "Made Man" : "mafia", + "Mafia" : "mafia", + "Magician" : "city", + "Miller" : "city", + "Postman" : "city", + "Priest" : "city", + "Rebel" : "city", + "Reporter" : "city", + "Resident" : "city", + "Serial Killer" : "serial_killer", + "Student" : "city", + "Undercover Cop" : "city" + } +} \ No newline at end of file diff --git a/config/persian.json b/config/persian.json new file mode 100644 index 0000000..eaee5cf --- /dev/null +++ b/config/persian.json @@ -0,0 +1,68 @@ +{ + "names": { + "Boxer" : "بوکسور", + "Bride" : "عروس", + "Bulletproof" : "ضدضربه", + "Bus Driver" : "راننده اتوبوس", + "Chef" : "آشپز", + "Clown" : "دلقک", + "Curious Kid" : "کودک کنجکاو", + "Detective" : "کارآگاه", + "Doctor" : "دکتر", + "Don" : "دن", + "Genie" : "غول چراغ جادو", + "Grandma" : "مادربزرگ با اسلحه", + "Groom" : "داماد", + "Hit Man" : "آدم کش", + "Insane" : "دیوانه", + "Jailer" : "زندان بان", + "Judge" : "قاضی", + "Kind Wife" : "همسر مهربان", + "Lawyer" : "وکیل", + "Made Man" : "آدم اجیر کن", + "Mafia" : "مافیا", + "Magician" : "جادوگر", + "Miller" : "آسیابان", + "Postman" : "پست چی", + "Priest" : "کشیش", + "Rebel" : "شورشی", + "Reporter" : "خبرنگار", + "Resident" : "شهروند", + "Serial Killer" : "قاتل سریالی", + "Student" : "دانش آموز", + "Undercover Cop" : "پلیس مخفی" + }, + "descriptions": { + "Boxor" : "بوکسور عضو تیم مافیا است. او یک فرد را در شب انتخاب میکند و به او مشت میزند پس از این حرکت آن فرد نمیتواند در روز بعد صحبت کند.", + "Bride" : "عروس عضو تیم شهروندان است. او که به تازگی با داماد وصلت کرده است دوران عاشقی را میگذراند. در صورتی که داماد کشته شود عروس میتواند یک فردرا به دلخواه بکشد.", + "Bulletproof" : "ضد ضربه قوی ترين شهروند بازی ميباشد ،و از هر تير مافیا در فاز شب در امان ميباشد.بنابرين ضد ضربه توسط مافيا در فاز شب قابل کشته شدن نميباشد", + "BusDriver" : "راننده اتوبوس عضو تیم شهروندان است و میتواند جای دو نفر را عوض کند یعنی استعلامات و ضربه های روی نفر اول روی نفر دوم اثر میکند.", + "Chef" : "آشپز عضو تیم شهروندان است و با مرگ او شهروندان تنها ۳ روز دیگر برای برد وقت دارند و در غیر این صورت از گشنگی می میرند و مافیا برنده می شود", + "Clown" : "دلقک عضو تیم شهروندان است. در هر بازی میتواند یکبار یک فرد را انتخاب کند تا نقش خود را فاش کند.", + "Curious Kid" : "کودک کنجکاو عضو تیم شهروندان است. وی باید در شب به شکلی که کسی متوجه نشود تیم مافیا را تشخیص دهد.", + "Detective" : "کارآگاه يکی از اعضای تیم شهروند ميباشد که در فاز شب چشم هايش را باز کرده و ميتواند از خدای بازی هويت يکی از افراد بازی را بپرسد ، و خدا با اشاره بله يا خیر به کاراگاه ميگويد که فرد استعلام شده جزو اعضای مافيا هست يا نه", + "Doctor": "دکتر يکی از اعضای تیم شهروند ميباشد که در فاز شب به فرمان خدای بازی چشم هايش را باز کرده و ميتواند خود و يا يکی از بازيکنان را از حذف شدن و کشته شدن در فاز شب بازی نجات دهد.", + "Don" : "اين نقش سردسته تيم مافيا مي باشد و مسئوليت تيم مافيا بر عهده دُن است.امتياز حائز اهميتی که دُن در بازی دارد اين است که استعلامش توسط کاراگاه همانند شهروندان منفی میباشد.", + "Genie" : "غول چراغ جادو عضو تیم شهروندان است. در مجموع می تواند ۳ آرزو را برآورده کند. در شب مشخص می شود که آرزو چه کسی را برآورده کند در روز با آرزو کردن آن شخص آرزو او برآروده می شود", + "Grandma" : "مادربزرگ با اسلحه عضو تیم شهروندان است. در شب هر کسی که به وی سر بزند (بخواهد او را بکشد) خودش خواهد مرد.", + "Groom" : "داماد عضو تیم شهروندان است. او که به تازگی با عروس وصلت کرده است و دوران عاشقی خود را می گذراند . در صورتی که عروس در بازی بمیرد میتواند یک فرد را به دلخواه بکشد.", + "Hit Man" : "آدمکش یکی از حرفه ای ترین مافیا ها است. او تنها یک تیر دارد که جایگزین یکی از قتل های مافیا میشود. اگر تصمیم بگیرد کسی را بکشد چیزی جلوی او را نمیگیرد (نه دکتر و نه ضد ضربه بودن آن شخص)", + "Insane" : "دیوانه عضو تیم شهروندان است. در شب میتواند ببیند که چه کسی فرد کناری او را انتخاب کرده است.", + "Jailer" : "زندان بان عضو تیم شهروندان است. او هر شب به دلخواه یک فرد را انتخاب میکند تا به زندان برود و یک شب از بازی محروم شود.", + "Judge" : "قاضی عضو تیم شهروندان است. او نقش خود را فاش میکند و یک فرد را به دلخواه اعدام میکند.", + "Kind Wife" : "همسر مهربان عضو تیم مافیا است. با مرگ او مافیا ۲ نفر را در فاز شب میکشد.", + "Lawyer" : "وکیل عضو تیم مافیا است. او در شب بیدار میشود و تصمیم میگیرد که چه کسی باید امشب به دادگاه برود.", + "Made Man" : "آدم اجیر کن عضو تیم مافیا است. او شب از خواب بلند میشود و یک فرد از شهروندان را تبدیل به مافیا میکند.", + "Mafia" : "از اعضای تیم مافیا میباشد و اگر کارآگاه از او استعلام بگیرد، استعلامش مثبت می شود", + "Magician" : "جادوگر عضو تیم شهروندان است. او می تواند تنها یکبار یک فرد را بکشد یا نجات دهد.", + "Miller" : "آسیابان عضو تیم شهروندان است. استعلام آسیابان توسط کارآگاه منفی (شبیه مافیا) است .", + "Postman" : "پستچی یکی از اعضای شروندان است. او پس از مرگ یک فرد دیگر را برای مرگ انتخاب میکند و همراه خودش میکشد.", + "Priest" : "", + "Rebel" : "از اعضای تیم شهروند میباشد و در فاز شب میتواند کسی را که فکر میکند مافیا است را هدف قرار دهد اگر شخص مافیا بود خواهد مرد.اما اگر شورشی به اشتباه یک شهروند را هدف قرار دهد خودش خواهد مرد.", + "Reporter" : "گزارشگر عضو تیم شهروندان است. هنگامی که آدم اجیر کن بازیکنی را برای تیم مافیا انتخاب میکند به گزارشگر اطلاع داده می شود.", + "Resident" : "شهروند عضو ساده شهر است. تنها قدرتی که شهروند دارد حذف افراد به واسطه رای گیری در روز است", + "Serial Killer" : "قاتل سریالی یک تیم جدا است که اگر در ۳ نفر آخر باشد برنده است. او یک شب در میان بلند می شود و یک فرد را به دلخواه میشکد", + "Student" : "دانش آموز شهروند بیگناهی است که در صورت کشته شدن تیم شهروندان در فاز روز ۲ تفر را در دادگاه می شکند.", + "Undercover Cop" : "پلیس مخفی عضو تیم شهروندان است او به همراه مافیا بازی میکند و به همراه آن ها در شب بیدار میشود و افراد را برای مرگ انتخاب میکند ولی در نهایت باید به نفع شهروندان عمل کند." + } +} \ No newline at end of file diff --git a/lang.py b/lang.py new file mode 100644 index 0000000..235694f --- /dev/null +++ b/lang.py @@ -0,0 +1,20 @@ + +from Role import Role +from dataclasses import dataclass +from config_loader import load_data + +@dataclass +class LanguageService: + address : str + + def __post_init__(self) -> None: + self._data = load_data(self.address) + + def get_name(self, key : Role) -> str: + return self._data.get("names").get(key.name) + + def get_description(self, key : Role) -> str: + return self._data.get("descriptions").get(key.name) + +english : LanguageService = LanguageService('english.json') +persian : LanguageService = LanguageService('persian.json') \ No newline at end of file diff --git a/mafia_params.py b/mafia_params.py index 2e7a020..f684f38 100644 --- a/mafia_params.py +++ b/mafia_params.py @@ -1,229 +1,10 @@ -max_comments : int = lambda nPlayers : nPlayers // 3 - -ordered_roles = ["Resident", - "Don", - "Resident", - "Detective", - "Doctor", - "Hit Man", - "Rebel", - "Bulletproof", - "Mafia", - "Resident", - "Resident", - "Mafia", - "Resident", - "Resident", - "Mafia", - "Doctor", - "Chef", - "Mafia", - "Detective", - "Miller", - "Mafia", - "Undercover Cop", - "Grandma", - "Mafia", - "Student", - "Postman", - "Mafia", - "Clown", - "Resident", - "Mafia", - "Resident", - "Resident"] - -nRoles = {"Boxer" : 2, - "Bride" : 5, - "Bulletproof" : 9, - "Bus Driver" : 3, - "Chef" : 3, - "Clown" : 2, - "Curious Kid" : 2, - "Detective" : 3, - "Doctor" : 10, - "Don" : 4, - "Genie" : 2, - "Grandma" : 2, - "Groom" : 4, - "Hit Man" : 2, - "Insane" : 3, - "Jailer" : 2, - "Judge" : 6, - "Kind Wife" : 4, - "Lawyer" : 3, - "Made Man" : 2, - "Mafia" : 9, - "Magician" : 4, - "Miller" : 3, - "Postman" : 3, - "Priest" : 3, - "Rebel" : 3, - "Reporter" : 6, - "Resident" : 21, - "Serial Killer" : 6, - "Student" : 2, - "Undercover Cop" : 2 - } +from lang import english, persian +from config import load_data -role2team = {"Boxer" : "mafia", - "Bride" : "city", - "Bulletproof" : "city", - "Bus Driver" : "city", - "Chef" : "city", - "Clown" : "city", - "Curious Kid" : "city", - "Detective" : "city", - "Doctor" : "city", - "Don" : "mafia", - "Genie" : "city", - "Grandma" : "city", - "Groom" : "city", - "Hit Man" : "mafia", - "Insane" : "city", - "Jailer" : "city", - "Judge" : "city", - "Kind Wife" : "mafia", - "Lawyer" : "mafia", - "Made Man" : "mafia", - "Mafia" : "mafia", - "Magician" : "city", - "Miller" : "city", - "Postman" : "city", - "Priest" : "city", - "Rebel" : "city", - "Reporter" : "city", - "Resident" : "city", - "Serial Killer" : "serial_killer", - "Student" : "city", - "Undercover Cop" : "city" - } - -descriptions = {"Boxor" : "Boxor is a member of mafia team. Boxor hits one of the players at night and the one" - " who hited Can't deffend oneself during day phase due to it's hit effect.", - "Bride" : "Bride is a member of city team. Bride has been engaged to Groom recently at nigh both of" - " them will get up and see each other after death of each one of them, other one can kill" - " anyone as a revenge of his/her sweetheart at night phase.", - "Bulletproof" : "Bulletproof is the most powerful resident which doesn't hurt from night shots. he/she won't die" - " through night phase.", - "Bus Driver" : "Bus Driver is city team member. He/She can switch two player which means each shot/question" - " from first one will hurt/asked from second one.", - "Chef" : "Chef is critical member of city team. After his/her death city team should win at last after 3 days.", - "Clown" : "Clown is a member of city team. Clown forces someone to reveal his/her role for another players." - " Clown can do this just for one time and this should take place at night, GOD should be informed" - " whos role to be reavealed.", - "Curious Kid" : "He/She is a member of city team which can open his/her eyes and spy on mafias in the way" - " that no one can see him/her.", - "Detective" : "Detective is from city team gets up at night phase and tries to ask GOD if someone is good" - " (Resident, Doctor, Rebel, Bulletproof) or bad(Mafia), but his/her first attempt to ask from" - " Don may be answered incorrect by GOD.", - "Doctor": "Doctor is a helpful participant of city team which gets up after mafia team and tries to rescue a person" - " (or two in the first night) from mafia's shot.", - "Don" : "Don is the boss of the mafia group. At night phsae Don decides whom to be killed from the mafia team." - "Don can't be detected by detective.", - "Genie" : "Genie is a kind member of city team despite his/her name. Genie selects a player at night and GOD " - "will ask the player to wish something and his/her wish will come true. Genie can use his/her power" - " just three time in a game.", - "Grandma" : "Grandma with gun is a frightening member of city team. She will kill anyone who tries to kill her" - " at night. Mafia and other roles with kiling power should be aware of her.", - "Groom" : "Groom is a member of city team. Groom has been engaged to Bride recently at nigh both of" - " them will get up and see each other after death of each one of them, other one can kill" - " anyone as a revenge of his/her sweetheart at night phase.", - "Hit Man" : "Hit Man is a rather powerful member of mafia team. His/Her shots won't fail even if the doctor save" - " or the victim is Bulletproof. Hit Man can use his shot only one time during the game his shot will" - " be replaced by one of mafia's night shot.", - "Insane" : "Insane is a member of city team. GOD will infrom Insane who is aiming at his/her neighbors (left hand" - " player or right hand player).", - "Jailer" : "Jailer is a member of city team. Jailer can bust any player at night phase, one who has been busted won't" - " play at earlier day phase just for a night.", - "Judge" : "Judge is a member of city team. Judge can reveal his role and decide to kill a player at day phase, Judge" - " can use his/her power only once during the game.", - "Kind Wife" : "Kind Wife is mafia team's sweetheart. After the day she died the mafia team get up and kill two suspects" - " instead of one to take her revenge.", - "Lawyer" : "Lawyer is from mafia team. Lawyer wakes up at night and inform the GOD whom should be sued to be to the court" - " for next day phase.", - "Made Man" : "Made Man is the one of the most powerful participant of the mafia team. Made Man gets up at night and turn" - " one of the members of city team to Mafia.", - "Mafia" : "Mafia is the simple participant of the mafia team. Mafia gets up at night and try to decide which one of" - "the players they want to kill, detective can detect this kind of mafia in night phase.", - "Magician" : "Magician is member of city team. He/She decides to kill or save a player during night and can use his/her" - "power just once during the game.", - "Miller" : "Miller is a member of city team. When Detective ask GOD about Millers role the result will be bad(Mafia) so" - " Detective will be confused about Millers role and asume he/she as a mafia team member.", - "Postman" : "Postman is a member of city team. After Postman's death he/she can select a player to die with him/her." - " With this power Postman can help city team by killing a mafia member.", - "Priest" : "", - "Rebel" : "Rebel is from city team which gets up at night phase and kills a person.if the victim was chosen from" - " residents, Rebel (him/her)self may die.", - "Reporter" : "Reporter is a city team member. GOD will inform Reporter who was chosen by Made Man to become Mafia.", - "Resident" : "Resident is the typical player of the game. he/she has no power but to blame mafia in order to remove " - "them from the game in day phase.", - "Serial Killer" : "Serial Killer is a seperate team. He/She wakes up once each two night and shot a player." - " Serial Killer will win if He/She is in last three players.", - "Student" : "Student is a innocent city team member. After His/Her death, players will kill two players at day court.", - "Undercover Cop" : "Undercover Cop is a member of city team but he/she will act just like mafia (wakes up at night)" - " and decide whome to be killed)."} +max_comments : int = lambda nPlayers : nPlayers // 3 -descriptions_fa = {"Boxor" : "بوکسور عضو تیم مافیا است. او یک فرد را در شب انتخاب میکند و به او مشت میزند پس از این حرکت آن فرد نمیتواند در روز بعد صحبت کند.", - "Bride" : "عروس عضو تیم شهروندان است. او که به تازگی با داماد وصلت کرده است دوران عاشقی را میگذراند. در صورتی که داماد کشته شود عروس میتواند یک فردرا به دلخواه بکشد.", - "Bulletproof" : "ضد ضربه قوی ترين شهروند بازی ميباشد ،و از هر تير مافیا در فاز شب در امان ميباشد.بنابرين ضد ضربه توسط مافيا در فاز شب قابل کشته شدن نميباشد", - "BusDriver" : "راننده اتوبوس عضو تیم شهروندان است و میتواند جای دو نفر را عوض کند یعنی استعلامات و ضربه های روی نفر اول روی نفر دوم اثر میکند.", - "Chef" : "آشپز عضو تیم شهروندان است و با مرگ او شهروندان تنها ۳ روز دیگر برای برد وقت دارند و در غیر این صورت از گشنگی می میرند و مافیا برنده می شود", - "Clown" : "دلقک عضو تیم شهروندان است. در هر بازی میتواند یکبار یک فرد را انتخاب کند تا نقش خود را فاش کند.", - "Curious Kid" : "کودک کنجکاو عضو تیم شهروندان است. وی باید در شب به شکلی که کسی متوجه نشود تیم مافیا را تشخیص دهد.", - "Detective" : "کارآگاه يکی از اعضای تیم شهروند ميباشد که در فاز شب چشم هايش را باز کرده و ميتواند از خدای بازی هويت يکی از افراد بازی را بپرسد ، و خدا با اشاره بله يا خیر به کاراگاه ميگويد که فرد استعلام شده جزو اعضای مافيا هست يا نه", - "Doctor": "دکتر يکی از اعضای تیم شهروند ميباشد که در فاز شب به فرمان خدای بازی چشم هايش را باز کرده و ميتواند خود و يا يکی از بازيکنان را از حذف شدن و کشته شدن در فاز شب بازی نجات دهد.", - "Don" : "اين نقش سردسته تيم مافيا مي باشد و مسئوليت تيم مافيا بر عهده دُن است.امتياز حائز اهميتی که دُن در بازی دارد اين است که استعلامش توسط کاراگاه همانند شهروندان منفی میباشد.", - "Genie" : "غول چراغ جادو عضو تیم شهروندان است. در مجموع می تواند ۳ آرزو را برآورده کند. در شب مشخص می شود که آرزو چه کسی را برآورده کند در روز با آرزو کردن آن شخص آرزو او برآروده می شود", - "Grandma" : "مادربزرگ با اسلحه عضو تیم شهروندان است. در شب هر کسی که به وی سر بزند (بخواهد او را بکشد) خودش خواهد مرد.", - "Groom" : "داماد عضو تیم شهروندان است. او که به تازگی با عروس وصلت کرده است و دوران عاشقی خود را می گذراند . در صورتی که عروس در بازی بمیرد میتواند یک فرد را به دلخواه بکشد.", - "Hit Man" : "آدمکش یکی از حرفه ای ترین مافیا ها است. او تنها یک تیر دارد که جایگزین یکی از قتل های مافیا میشود. اگر تصمیم بگیرد کسی را بکشد چیزی جلوی او را نمیگیرد (نه دکتر و نه ضد ضربه بودن آن شخص)", - "Insane" : "دیوانه عضو تیم شهروندان است. در شب میتواند ببیند که چه کسی فرد کناری او را انتخاب کرده است.", - "Jailer" : "زندان بان عضو تیم شهروندان است. او هر شب به دلخواه یک فرد را انتخاب میکند تا به زندان برود و یک شب از بازی محروم شود.", - "Judge" : "قاضی عضو تیم شهروندان است. او نقش خود را فاش میکند و یک فرد را به دلخواه اعدام میکند.", - "Kind Wife" : "همسر مهربان عضو تیم مافیا است. با مرگ او مافیا ۲ نفر را در فاز شب میکشد.", - "Lawyer" : "وکیل عضو تیم مافیا است. او در شب بیدار میشود و تصمیم میگیرد که چه کسی باید امشب به دادگاه برود.", - "Made Man" : "آدم اجیر کن عضو تیم مافیا است. او شب از خواب بلند میشود و یک فرد از شهروندان را تبدیل به مافیا میکند.", - "Mafia" : "از اعضای تیم مافیا میباشد و اگر کارآگاه از او استعلام بگیرد، استعلامش مثبت می شود", - "Magician" : "جادوگر عضو تیم شهروندان است. او می تواند تنها یکبار یک فرد را بکشد یا نجات دهد.", - "Miller" : "آسیابان عضو تیم شهروندان است. استعلام آسیابان توسط کارآگاه منفی (شبیه مافیا) است .", - "Postman" : "پستچی یکی از اعضای شروندان است. او پس از مرگ یک فرد دیگر را برای مرگ انتخاب میکند و همراه خودش میکشد.", - "Priest" : "", - "Rebel" : "از اعضای تیم شهروند میباشد و در فاز شب میتواند کسی را که فکر میکند مافیا است را هدف قرار دهد اگر شخص مافیا بود خواهد مرد.اما اگر شورشی به اشتباه یک شهروند را هدف قرار دهد خودش خواهد مرد.", - "Reporter" : "گزارشگر عضو تیم شهروندان است. هنگامی که آدم اجیر کن بازیکنی را برای تیم مافیا انتخاب میکند به گزارشگر اطلاع داده می شود.", - "Resident" : "شهروند عضو ساده شهر است. تنها قدرتی که شهروند دارد حذف افراد به واسطه رای گیری در روز است", - "Serial Killer" : "قاتل سریالی یک تیم جدا است که اگر در ۳ نفر آخر باشد برنده است. او یک شب در میان بلند می شود و یک فرد را به دلخواه میشکد", - "Student" : "دانش آموز شهروند بیگناهی است که در صورت کشته شدن تیم شهروندان در فاز روز ۲ تفر را در دادگاه می شکند.", - "Undercover Cop" : "پلیس مخفی عضو تیم شهروندان است او به همراه مافیا بازی میکند و به همراه آن ها در شب بیدار میشود و افراد را برای مرگ انتخاب میکند ولی در نهایت باید به نفع شهروندان عمل کند."} +data = load_data("mafia_param.json") -role2fa = {"Boxer" : "بوکسور", - "Bride" : "عروس", - "Bulletproof" : "ضدضربه", - "Bus Driver" : "راننده اتوبوس", - "Chef" : "آشپز", - "Clown" : "دلقک", - "Curious Kid" : "کودک کنجکاو", - "Detective" : "کارآگاه", - "Doctor" : "دکتر", - "Don" : "دن", - "Genie" : "غول چراغ جادو", - "Grandma" : "مادربزرگ با اسلحه", - "Groom" : "داماد", - "Hit Man" : "آدم کش", - "Insane" : "دیوانه", - "Jailer" : "زندان بان", - "Judge" : "قاضی", - "Kind Wife" : "همسر مهربان", - "Lawyer" : "وکیل", - "Made Man" : "آدم اجیر کن", - "Mafia" : "مافیا", - "Magician" : "جادوگر", - "Miller" : "آسیابان", - "Postman" : "پست چی", - "Priest" : "کشیش", - "Rebel" : "شورشی", - "Reporter" : "خبرنگار", - "Resident" : "شهروند", - "Serial Killer" : "قاتل سریالی", - "Student" : "دانش آموز", - "Undercover Cop" : "پلیس مخفی"} +ordered_roles = data.get("ordered_roles") +nRoles = data.get("nRoles") +role2team = data.get("role2team") \ No newline at end of file From 8dcea3c5a0e6fecb442b76798b12aec74dc84f97 Mon Sep 17 00:00:00 2001 From: aeirya Date: Wed, 16 Sep 2020 17:59:06 +0430 Subject: [PATCH 09/15] hotfixed bugs. added functions to allow backward compatibility. ready to pull request. --- lang.py | 11 +++++++++-- mafia.py | 3 ++- mafia_params.py | 6 +++++- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/lang.py b/lang.py index 235694f..50d40cd 100644 --- a/lang.py +++ b/lang.py @@ -1,7 +1,7 @@ - +from typing import Dict, List from Role import Role from dataclasses import dataclass -from config_loader import load_data +from config import load_data @dataclass class LanguageService: @@ -15,6 +15,13 @@ def get_name(self, key : Role) -> str: def get_description(self, key : Role) -> str: return self._data.get("descriptions").get(key.name) + + # TODO: remove these after refactoring mafia.py + def get_name_dict(self) -> Dict[str, str]: + return self._data.get("names"); + + def get_description_dict(self) -> Dict[str, str]: + return self._data.get("descriptions") english : LanguageService = LanguageService('english.json') persian : LanguageService = LanguageService('persian.json') \ No newline at end of file diff --git a/mafia.py b/mafia.py index 5507328..6daa2bb 100644 --- a/mafia.py +++ b/mafia.py @@ -76,13 +76,14 @@ def switch_ban(player : Player) -> None: player.switch_ban() def comment(player : Player) -> None: + global nComments, comments_ordered + if nComments > max_comments(nPlayers): nonlocal msg msg = "Error: Out of Comments." return if player.get_comment() is False: - global nComments, comments_ordered player.set_comment(True) nComments += 1 comments_ordered.append(player.get_ip()) diff --git a/mafia_params.py b/mafia_params.py index f684f38..e10b0dc 100644 --- a/mafia_params.py +++ b/mafia_params.py @@ -7,4 +7,8 @@ ordered_roles = data.get("ordered_roles") nRoles = data.get("nRoles") -role2team = data.get("role2team") \ No newline at end of file +role2team = data.get("role2team") + +descriptions = english.get_description_dict() +role2fa = persian.get_name_dict() +descriptions_fa = persian.get_description_dict() \ No newline at end of file From 45fc6e81fa860aefd03712fea8af123b7eca4fd0 Mon Sep 17 00:00:00 2001 From: aeirya Date: Wed, 16 Sep 2020 18:59:28 +0430 Subject: [PATCH 10/15] fixed bugs: converted request mapper to a dict, handled invalid requests better --- mafia.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/mafia.py b/mafia.py index 6daa2bb..37cca14 100644 --- a/mafia.py +++ b/mafia.py @@ -92,10 +92,10 @@ def comment(player : Player) -> None: nComments -= 1 comments_ordered.remove(player.get_ip()) - request_mapper : Dict[Callable] = { - "Kill", kill, - "Ban", switch_ban, - "Comment", comment + request_mapper : Dict[str, Callable] = { + "Kill": kill, + "Ban": switch_ban, + "Comment": comment } # filters out invalid requests @@ -103,20 +103,21 @@ def get_requests() -> List[Tuple[str, Player]]: requests = [] for key in request_mapper.keys(): ip = request.args.get(key) - - if ip is None or ip not in ip2player.keys(): - print("invalid ip / request: ", ip, f"({key})") + + if ip is None: continue + if ip not in ip2player.keys(): + print("invalid ip / request: ", ip, f"({key})") + return -1 player = ip2player[ip] requests.append((key, player)) - return requests msg = "" request_list = get_requests() - if len(request_list) == 0: + if request_list == -1: return not_found_page() # handle requests From 128fa0cd73270ae39114c5637938cc3586ffcbd7 Mon Sep 17 00:00:00 2001 From: aeirya Date: Wed, 16 Sep 2020 20:29:52 +0430 Subject: [PATCH 11/15] shutting down code factor warnings. working on the role module. (gets teams from the json) --- Role.py | 32 +++++++++++++++++++++----------- lang.py | 16 ++++------------ mafia_params.py | 6 +++--- player.py | 7 +++++-- 4 files changed, 33 insertions(+), 28 deletions(-) diff --git a/Role.py b/Role.py index df28404..e5617ee 100644 --- a/Role.py +++ b/Role.py @@ -1,5 +1,7 @@ -from dataclasses import dataclass +from dataclasses import dataclass, field +from mimetypes import init import mafia_params +import lang @dataclass class Team: @@ -8,15 +10,26 @@ class Team: def __repr__(self) -> str: return self.name.capitalize() -@dataclass(frozen= True) +def get_team(s : str) -> Team: + return Team(mafia_params.role2team[s]) + +@dataclass(frozen= False) class Role: name : str - team : Team + team : Team = field(default= None) + + def __post_init__(self): + self.team = get_team(self.name) - def get_description(self, is_english : bool = True) -> str: - if (is_english): - return mafia_params.descriptions.get(self.name) - return mafia_params.descriptions_fa.get(self.name) + def get_name(self, is_farsi : bool = False): + if is_farsi: + return lang.persian.get_name(self.name) + return self.name + + def get_description(self, is_farsi : bool = False) -> str: + if is_farsi: + return lang.persian.get_description(self.name) + return lang.english.get_description(self.name) def is_mafia(self) -> bool: return self.team == MAFIA @@ -24,7 +37,4 @@ def is_mafia(self) -> bool: # Teams initiation MAFIA = Team("mafia") CITY = Team("city") - -#Roles initiation -RESIDENT = Role("Resident", CITY) -MAFIA = Role("Mafia", MAFIA) +SERIAL_KILLER = Team("serial_killer") diff --git a/lang.py b/lang.py index 50d40cd..f83deaf 100644 --- a/lang.py +++ b/lang.py @@ -1,5 +1,4 @@ from typing import Dict, List -from Role import Role from dataclasses import dataclass from config import load_data @@ -10,18 +9,11 @@ class LanguageService: def __post_init__(self) -> None: self._data = load_data(self.address) - def get_name(self, key : Role) -> str: - return self._data.get("names").get(key.name) + def get_name(self, key : str) -> str: + return self._data.get("names").get(key) - def get_description(self, key : Role) -> str: - return self._data.get("descriptions").get(key.name) - - # TODO: remove these after refactoring mafia.py - def get_name_dict(self) -> Dict[str, str]: - return self._data.get("names"); - - def get_description_dict(self) -> Dict[str, str]: - return self._data.get("descriptions") + def get_description(self, key : str) -> str: + return self._data.get("descriptions").get(key) english : LanguageService = LanguageService('english.json') persian : LanguageService = LanguageService('persian.json') \ No newline at end of file diff --git a/mafia_params.py b/mafia_params.py index e10b0dc..3916300 100644 --- a/mafia_params.py +++ b/mafia_params.py @@ -9,6 +9,6 @@ nRoles = data.get("nRoles") role2team = data.get("role2team") -descriptions = english.get_description_dict() -role2fa = persian.get_name_dict() -descriptions_fa = persian.get_description_dict() \ No newline at end of file +# descriptions = english.get_description_dict() +# role2fa = persian.get_name_dict() +# descriptions_fa = persian.get_description_dict() \ No newline at end of file diff --git a/player.py b/player.py index f9ba8a9..e848e51 100644 --- a/player.py +++ b/player.py @@ -7,7 +7,7 @@ class PlayerState: BANNED: str = "banned" all: List[str] = [ALIVE, DEAD, BANNED] -"""A player in mafia game""" +# A player in mafia game @dataclass class Player: ip : str @@ -24,7 +24,10 @@ def die(self) -> None: self.state = PlayerState.DEAD def switch_ban(self): - self.unban() if self.is_banned() else self.ban() + if self.is_banned(): + self.unban() + else: + self.ban() def is_banned(self) -> bool: return self.state == PlayerState.BANNED From 027c12f2e217981f70e4a397353897cfeab801ea Mon Sep 17 00:00:00 2001 From: aeirya Date: Wed, 16 Sep 2020 20:35:58 +0430 Subject: [PATCH 12/15] roles are initiated and stored as members of an enum, and their teams are hardcored into code (and removed from json) --- Role.py | 45 +++++++++++++++++++++++++++++++++-------- config/mafia_param.json | 34 ------------------------------- mafia_params.py | 1 - 3 files changed, 37 insertions(+), 43 deletions(-) diff --git a/Role.py b/Role.py index e5617ee..0462e53 100644 --- a/Role.py +++ b/Role.py @@ -2,6 +2,7 @@ from mimetypes import init import mafia_params import lang +import enum @dataclass class Team: @@ -10,16 +11,10 @@ class Team: def __repr__(self) -> str: return self.name.capitalize() -def get_team(s : str) -> Team: - return Team(mafia_params.role2team[s]) - -@dataclass(frozen= False) +@dataclass(frozen= True) class Role: name : str - team : Team = field(default= None) - - def __post_init__(self): - self.team = get_team(self.name) + team : Team def get_name(self, is_farsi : bool = False): if is_farsi: @@ -38,3 +33,37 @@ def is_mafia(self) -> bool: MAFIA = Team("mafia") CITY = Team("city") SERIAL_KILLER = Team("serial_killer") + +#Roles initiation +class Roles(enum.Enum): + BOXER = Role("Boxer", MAFIA) + BRIDE = Role("Bride", CITY) + BULLETPROOF = Role("Bulletproof", CITY) + BUS_DRIVER = Role("Bus Driver", CITY) + CHEF = Role("Chef", CITY) + CLOWN = Role("Clown", CITY) + CURIOUS_KID = Role("Curious Kid", CITY) + DETECTIVE = Role("Detective", CITY) + DOCTOR = Role("Doctor" , CITY) + DON = Role("Don", MAFIA) + GENIE = Role("Genie", CITY) + GRANDMA = Role("Grandma", CITY) + GROOM = Role("Groom", CITY) + HIT_MAN = Role("Hit Man", MAFIA) + INSANE = Role("Insane", CITY) + JAILER = Role("Jailer", CITY) + JUDGE = Role("Judge", CITY) + KIND_WIFE = Role("Kind Wife", MAFIA) + LAWYER = Role("Lawyer", MAFIA) + MADE_MAN = Role("Made Man", MAFIA) + MAFIA = Role("Mafia", MAFIA) + MAGICIAN = Role("Magician", CITY) + MILLER = Role("Miller", CITY) + POSTMAN = Role("Postman", CITY) + PRIEST = Role("Priest", CITY) + REBEL = Role("Rebel", CITY) + REPORTER = Role("Reporter", CITY) + RESIDENT = Role("Resident" , CITY) + SERIAL_KILLER = Role("Serial Killer", SERIAL_KILLER) + STUDENT = Role("Student", CITY) + UNDER_COVER_COP = Role("Undercover Cop", CITY) \ No newline at end of file diff --git a/config/mafia_param.json b/config/mafia_param.json index 0dbb53c..31206bb 100644 --- a/config/mafia_param.json +++ b/config/mafia_param.json @@ -66,39 +66,5 @@ "Serial Killer" : 6, "Student" : 2, "Undercover Cop" : 2 - }, - - "role2team" : { - "Boxer" : "mafia", - "Bride" : "city", - "Bulletproof" : "city", - "Bus Driver" : "city", - "Chef" : "city", - "Clown" : "city", - "Curious Kid" : "city", - "Detective" : "city", - "Doctor" : "city", - "Don" : "mafia", - "Genie" : "city", - "Grandma" : "city", - "Groom" : "city", - "Hit Man" : "mafia", - "Insane" : "city", - "Jailer" : "city", - "Judge" : "city", - "Kind Wife" : "mafia", - "Lawyer" : "mafia", - "Made Man" : "mafia", - "Mafia" : "mafia", - "Magician" : "city", - "Miller" : "city", - "Postman" : "city", - "Priest" : "city", - "Rebel" : "city", - "Reporter" : "city", - "Resident" : "city", - "Serial Killer" : "serial_killer", - "Student" : "city", - "Undercover Cop" : "city" } } \ No newline at end of file diff --git a/mafia_params.py b/mafia_params.py index 3916300..bb9f7bb 100644 --- a/mafia_params.py +++ b/mafia_params.py @@ -7,7 +7,6 @@ ordered_roles = data.get("ordered_roles") nRoles = data.get("nRoles") -role2team = data.get("role2team") # descriptions = english.get_description_dict() # role2fa = persian.get_name_dict() From 89e510fdb03b484dcd204bf147c4daa08676c459 Mon Sep 17 00:00:00 2001 From: aeirya Date: Wed, 16 Sep 2020 23:28:44 +0430 Subject: [PATCH 13/15] made enums for roles and replaced strings in the code with its enum equivalent --- Role.py | 102 +++++++++++++++++++++++++++------------- config/mafia_param.json | 34 +++++++++++++- mafia.py | 43 ++++++++--------- mafia_params.py | 5 +- 4 files changed, 126 insertions(+), 58 deletions(-) diff --git a/Role.py b/Role.py index 0462e53..55b0a5a 100644 --- a/Role.py +++ b/Role.py @@ -1,5 +1,6 @@ from dataclasses import dataclass, field from mimetypes import init +from typing import List import mafia_params import lang import enum @@ -15,8 +16,9 @@ def __repr__(self) -> str: class Role: name : str team : Team + repitition : int - def get_name(self, is_farsi : bool = False): + def get_name(self, is_farsi : bool = False) -> str: if is_farsi: return lang.persian.get_name(self.name) return self.name @@ -29,41 +31,77 @@ def get_description(self, is_farsi : bool = False) -> str: def is_mafia(self) -> bool: return self.team == MAFIA + def __hash__(self): + return hash(self.name) + # Teams initiation MAFIA = Team("mafia") CITY = Team("city") SERIAL_KILLER = Team("serial_killer") #Roles initiation + +@dataclass +class RoleFactory: + name : str + + def get_team(self) -> str: + return Team(mafia_params.role2team[self.name]) + + def get_repitition(self) -> int: + return int(mafia_params.nRoles[self.name]) + + # get desription(self) -> str here + + def build(self) -> str: + return Role( + name = self.name, + team = self.get_team(), + repitition = self.get_repitition() + ) + class Roles(enum.Enum): - BOXER = Role("Boxer", MAFIA) - BRIDE = Role("Bride", CITY) - BULLETPROOF = Role("Bulletproof", CITY) - BUS_DRIVER = Role("Bus Driver", CITY) - CHEF = Role("Chef", CITY) - CLOWN = Role("Clown", CITY) - CURIOUS_KID = Role("Curious Kid", CITY) - DETECTIVE = Role("Detective", CITY) - DOCTOR = Role("Doctor" , CITY) - DON = Role("Don", MAFIA) - GENIE = Role("Genie", CITY) - GRANDMA = Role("Grandma", CITY) - GROOM = Role("Groom", CITY) - HIT_MAN = Role("Hit Man", MAFIA) - INSANE = Role("Insane", CITY) - JAILER = Role("Jailer", CITY) - JUDGE = Role("Judge", CITY) - KIND_WIFE = Role("Kind Wife", MAFIA) - LAWYER = Role("Lawyer", MAFIA) - MADE_MAN = Role("Made Man", MAFIA) - MAFIA = Role("Mafia", MAFIA) - MAGICIAN = Role("Magician", CITY) - MILLER = Role("Miller", CITY) - POSTMAN = Role("Postman", CITY) - PRIEST = Role("Priest", CITY) - REBEL = Role("Rebel", CITY) - REPORTER = Role("Reporter", CITY) - RESIDENT = Role("Resident" , CITY) - SERIAL_KILLER = Role("Serial Killer", SERIAL_KILLER) - STUDENT = Role("Student", CITY) - UNDER_COVER_COP = Role("Undercover Cop", CITY) \ No newline at end of file + #could've used enum.auto() + BOXER = 0 + BRIDE = 1 + BULLETPROOF = 2 + BUS_DRIVER = 3 + CHEF = 4 + CLOWN = 5 + CURIOUS_KID = 6 + DETECTIVE = 7 + DOCTOR = 8 + DON = 9 + GENIE = 10 + GRANDMA = 11 + GROOM = 12 + HIT_MAN = 13 + INSANE = 14 + JAILER = 15 + JUDGE = 16 + KIND_WIFE = 17 + LAWYER = 18 + MADE_MAN = 19 + MAFIA = 20 + MAGICIAN = 21 + MILLER = 22 + POSTMAN = 23 + PRIEST = 24 + REBEL = 25 + REPORTER = 26 + RESIDENT = 27 + SERIAL_KILLER = 28 + STUDENT = 29 + UNDERCOVER_COP = 30 + + def get_name(self) -> str: + return " ".join([word.capitalize() for word in self.name.split("_")]) + + def to_role(self) -> Role: + return RoleFactory(self.get_name()).build() + +def get(string : str) -> Roles: + return Roles["_".join([word.upper() for word in string.split()])] + +roles = dict([(r, r.to_role()) for r in Roles]) +ordered_roles = [roles.get(get(key)) for key in mafia_params.ordered_roles] \ No newline at end of file diff --git a/config/mafia_param.json b/config/mafia_param.json index 31206bb..5007e3e 100644 --- a/config/mafia_param.json +++ b/config/mafia_param.json @@ -33,7 +33,6 @@ "Resident", "Resident" ], - "nRoles" : { "Boxer" : 2, "Bride" : 5, @@ -66,5 +65,38 @@ "Serial Killer" : 6, "Student" : 2, "Undercover Cop" : 2 + }, + "role2team": { + "Boxer" : "mafia", + "Bride" : "city", + "Bulletproof" : "city", + "Bus Driver" : "city", + "Chef" : "city", + "Clown" : "city", + "Curious Kid" : "city", + "Detective" : "city", + "Doctor" : "city", + "Don" : "mafia", + "Genie" : "city", + "Grandma" : "city", + "Groom" : "city", + "Hit Man" : "mafia", + "Insane" : "city", + "Jailer" : "city", + "Judge" : "city", + "Kind Wife" : "mafia", + "Lawyer" : "mafia", + "Made Man" : "mafia", + "Mafia" : "mafia", + "Magician" : "city", + "Miller" : "city", + "Postman" : "city", + "Priest" : "city", + "Rebel" : "city", + "Reporter" : "city", + "Resident" : "city", + "Serial Killer" : "serial_killer", + "Student" : "city", + "Undercover Cop" : "city" } } \ No newline at end of file diff --git a/mafia.py b/mafia.py index 37cca14..05562c3 100644 --- a/mafia.py +++ b/mafia.py @@ -3,18 +3,19 @@ from typing import Callable, Dict, List, Text, Tuple from flask import Flask, render_template, url_for, request from flask_httpauth import HTTPBasicAuth -from mafia_params import ordered_roles, nRoles, role2team, descriptions, descriptions_fa, role2fa, max_comments +from mafia_params import max_comments, role2team from player import Player +from role import Role, Roles, roles, ordered_roles app = Flask(__name__) auth = HTTPBasicAuth() auth_GOD = HTTPBasicAuth() -preshared_key = "" +preshared_key : str = "" -ip2player = {} -roles = [] -player_id = 0 -nPlayers = 0 +ip2player : Dict[str, str] = {} +roles : List[Role] = [] +player_id : int = 0 +nPlayers : int = 0 nComments = 0 comments_ordered = [] @@ -41,22 +42,22 @@ def index(): # create new player role = roles[player_id] - image_name = role + "_" + str(randrange(1, nRoles[role] + 1)) - ip2player[ip] = Player(ip, username, role, image_name) + image_name = role.get_name() + "_" + str(randrange(1, role.repitition + 1)) + ip2player[ip] = Player(ip, username, role.name, image_name) # next player id player_id += 1 # log new player print("*" * 20, "New Player","*" * 20) - to_god = ip + " : " + str(player_id) + " : " + username + " --> " + role - to_god += "/" + role2fa[role] #TODO: Just in Farsi Mode + to_god = ip + " : " + str(player_id) + " : " + username + " --> " + role.get_name() + to_god += "/" + role.get_name(is_farsi= True) #TODO: Just in Farsi Mode print(to_god) return render_template("index.html", image_name=image_name, - role_name=role, role_name_fa=role2fa[role], - description=descriptions[role], description_fa=descriptions_fa[role], + role_name=role.name, role_name_fa=role.get_name(is_farsi= True), + description=role.get_description(), description_fa=role.get_description(is_farsi= True), is_farsi=True) @auth_GOD.verify_password @@ -125,7 +126,7 @@ def get_requests() -> List[Tuple[str, Player]]: request_mapper[req](player) return render_template("GOD.html", ip2player=ip2player, - prompt_message=msg, roles={role:roles.count(role) for role in set(roles)}, + prompt_message=msg, roles={role.get_name() : roles.count(role) for role in set(roles)}, comments=comments_ordered, role2team=role2team) @app.errorhandler(404) @@ -157,21 +158,21 @@ def give_me_roles(ordered_roles): """ n = len(ordered_roles) if n >= 14: - ordered_roles[12] = 'Groom' - ordered_roles[13] = 'Bride' + ordered_roles[12] = Roles.GROOM + ordered_roles[13] = Roles.BRIDE if n % 3 == 0: - ordered_roles[14] = 'Serial Killer' + ordered_roles[14] = Roles.SERIAL_KILLER if n % 3 != 0: try: - i = ordered_roles.index('Mafia') - ordered_roles[i] = 'Made Man' - ordered_roles[2] = 'Reporter' + i = ordered_roles.index(Roles.MAFIA) + ordered_roles[i] = Roles.MADE_MAN + ordered_roles[2] = Roles.REPORTER except ValueError: pass if n % 3 == 2: try: - i = ordered_roles.index('Mafia') - ordered_roles[i] = 'Kind Wife' + i = ordered_roles.index(Roles.MAFIA) + ordered_roles[i] = Roles.KIND_WIFE except ValueError: pass return ordered_roles diff --git a/mafia_params.py b/mafia_params.py index bb9f7bb..f684f38 100644 --- a/mafia_params.py +++ b/mafia_params.py @@ -7,7 +7,4 @@ ordered_roles = data.get("ordered_roles") nRoles = data.get("nRoles") - -# descriptions = english.get_description_dict() -# role2fa = persian.get_name_dict() -# descriptions_fa = persian.get_description_dict() \ No newline at end of file +role2team = data.get("role2team") \ No newline at end of file From e11eaff9323c6766af5bd83499b14b5e68fd2476 Mon Sep 17 00:00:00 2001 From: aeirya Date: Thu, 17 Sep 2020 00:27:23 +0430 Subject: [PATCH 14/15] added player manager class. no more need for global variables --- mafia.py | 119 +++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 76 insertions(+), 43 deletions(-) diff --git a/mafia.py b/mafia.py index 05562c3..38748e6 100644 --- a/mafia.py +++ b/mafia.py @@ -7,18 +7,67 @@ from player import Player from role import Role, Roles, roles, ordered_roles +is_farsi_mode : bool = True + +class PlayerManager: + n_players : int + roles : List[Role] + + ip2player : Dict[str, str] = {} + player_id : int = 0 + n_comments = 0 + comments_ordered = [] + + def __init__(self, n_players : int, roles : List[Role]): + self.n_players = n_players + self.roles = roles + + def is_ip_valid(self, ip : str) -> bool: + return ip in self.ip2player.keys() + + def get_player(self, ip : str): + if not self.is_ip_valid(ip): + return None + return self.ip2player[ip] + + def get_next_role(self) -> Role: + return self.roles[self.player_id] + + def new_player(self, ip : str, username : str) -> Player: + if self.player_id > self.n_players: + return None + role = self.get_next_role() + image_name = role.get_name() + "_" + str(randrange(1, role.repitition + 1)) + player = Player(ip, username, role, image_name) + self.ip2player[ip] = player + + self.player_id += 1 + + # log new player + print("*" * 20, "New Player","*" * 20) + to_god = ip + " : " + str(self.player_id) + " : " + username + " --> " + role.get_name() + if is_farsi_mode: + to_god += "/" + role.get_name(is_farsi= True) + print(to_god) + + return player + + def comment(self, player : Player): + player.set_comment(True) + self.n_comments += 1 + self.comments_ordered.append(player.get_ip()) + + def uncomment(self, player : Player): + player.set_comment(False) + self.n_comments -= 1 + self.comments_ordered.remove(player.get_ip()) + app = Flask(__name__) auth = HTTPBasicAuth() auth_GOD = HTTPBasicAuth() preshared_key : str = "" -ip2player : Dict[str, str] = {} -roles : List[Role] = [] -player_id : int = 0 -nPlayers : int = 0 - -nComments = 0 -comments_ordered = [] +player_manager = None @auth.verify_password def verify_password(username, password): @@ -32,30 +81,19 @@ def index(): ip = str(request.remote_addr) # redirect current players - if ip in ip2player.keys(): - return render_template("Player.html", player=ip2player[ip]) - - # reject excess players - global player_id - if player_id > nPlayers: - return not_found_page() + if player_manager.is_ip_valid(ip): + return render_template("Player.html", player=player_manager.get_player[ip]) # create new player - role = roles[player_id] - image_name = role.get_name() + "_" + str(randrange(1, role.repitition + 1)) - ip2player[ip] = Player(ip, username, role.name, image_name) + player : Player = player_manager.new_player(ip, username) - # next player id - player_id += 1 - - # log new player - print("*" * 20, "New Player","*" * 20) - to_god = ip + " : " + str(player_id) + " : " + username + " --> " + role.get_name() - to_god += "/" + role.get_name(is_farsi= True) #TODO: Just in Farsi Mode - print(to_god) + # reject excess players + if player is None: + return not_found_page() + role = player.get_role() return render_template("index.html", - image_name=image_name, + image_name=player.image_name, role_name=role.name, role_name_fa=role.get_name(is_farsi= True), description=role.get_description(), description_fa=role.get_description(is_farsi= True), is_farsi=True) @@ -77,21 +115,14 @@ def switch_ban(player : Player) -> None: player.switch_ban() def comment(player : Player) -> None: - global nComments, comments_ordered - - if nComments > max_comments(nPlayers): - nonlocal msg - msg = "Error: Out of Comments." - return - if player.get_comment() is False: - player.set_comment(True) - nComments += 1 - comments_ordered.append(player.get_ip()) + if player_manager.n_comments > max_comments(nPlayers): + nonlocal msg + msg = "Error: Out of Comments." + return + player_manager.comment(player) else: - player.set_comment(False) - nComments -= 1 - comments_ordered.remove(player.get_ip()) + player_manager.uncomment(player) request_mapper : Dict[str, Callable] = { "Kill": kill, @@ -107,11 +138,11 @@ def get_requests() -> List[Tuple[str, Player]]: if ip is None: continue - if ip not in ip2player.keys(): + if not player_manager.is_ip_valid(ip): print("invalid ip / request: ", ip, f"({key})") return -1 - player = ip2player[ip] + player = player_manager.get_player(ip) requests.append((key, player)) return requests @@ -125,9 +156,9 @@ def get_requests() -> List[Tuple[str, Player]]: for req, player in request_list: request_mapper[req](player) - return render_template("GOD.html", ip2player=ip2player, + return render_template("GOD.html", ip2player=player_manager.ip2player, prompt_message=msg, roles={role.get_name() : roles.count(role) for role in set(roles)}, - comments=comments_ordered, role2team=role2team) + comments=player_manager.comments_ordered, role2team=role2team) @app.errorhandler(404) def invalid_route(e): @@ -197,6 +228,8 @@ def gen_preshared_key() -> str: roles = give_me_roles(ordered_roles[:nPlayers]) shuffle(roles) + player_manager = PlayerManager(n_players= nPlayers, roles= roles) + # preshared key generation preshared_key = gen_preshared_key() print("_" * 20 + "GOD's password" + "_" * 20) From 37503c8da3d1fd3e13221df3035b7f7d6279b22b Mon Sep 17 00:00:00 2001 From: aeirya Date: Thu, 17 Sep 2020 00:43:21 +0430 Subject: [PATCH 15/15] fix: typos and showing player role name --- mafia.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mafia.py b/mafia.py index 38748e6..e60c5e5 100644 --- a/mafia.py +++ b/mafia.py @@ -5,7 +5,7 @@ from flask_httpauth import HTTPBasicAuth from mafia_params import max_comments, role2team from player import Player -from role import Role, Roles, roles, ordered_roles +from Role import Role, Roles, roles, ordered_roles is_farsi_mode : bool = True @@ -38,7 +38,7 @@ def new_player(self, ip : str, username : str) -> Player: return None role = self.get_next_role() image_name = role.get_name() + "_" + str(randrange(1, role.repitition + 1)) - player = Player(ip, username, role, image_name) + player = Player(ip, username, role.get_name(), image_name) self.ip2player[ip] = player self.player_id += 1 @@ -82,16 +82,16 @@ def index(): # redirect current players if player_manager.is_ip_valid(ip): - return render_template("Player.html", player=player_manager.get_player[ip]) + return render_template("Player.html", player=player_manager.get_player(ip)) # create new player + role = player_manager.get_next_role() player : Player = player_manager.new_player(ip, username) # reject excess players if player is None: return not_found_page() - role = player.get_role() return render_template("index.html", image_name=player.image_name, role_name=role.name, role_name_fa=role.get_name(is_farsi= True),