-
Notifications
You must be signed in to change notification settings - Fork 3
/
mafia_game.py
155 lines (135 loc) · 7.19 KB
/
mafia_game.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
from server import WebServerSocket
import threading,time
class MafiaGame:
def __init__(self):
''' Define all init variables and start a thread for the WebServerSocket '''
self.round = ""
self.victims = []
self.mafias = []
self.detectives = []
self.wssock = WebServerSocket()
threading.Thread(target = self.wssock.start, daemon=True).start()
def type_round(self, num):
''' Waits till all users have joined and then assigns them type and sends namelists'''
while len(self.wssock.client_list)!=num: # Wait till we're done with connections
pass
self.wssock.send(self.wssock.client_list, "#NAMES:" + ",".join([str(cl) for cl in self.wssock.client_list]))
# Randomize
# This is a really poor way to randomize
self.wssock.client_list = list(set(self.wssock.client_list))
#Assign numbers - of mafia, of detectives
number_maf = num//3
number_det = min(num//3, 3)
# TODO: Make this assignment random, not like it is now.
self.mafias = self.wssock.client_list[:number_maf]
self.detectives = self.wssock.client_list[number_maf:number_det+number_maf]
self.victims = self.wssock.client_list[number_det+number_maf:]
self.wssock.send(self.victims, "#TYPE:Victim")
self.wssock.send(self.mafias, "#TYPE:Mafia")
# Now wait for all mafia to acknowledge
self._wait_acknowledge(self.mafias, "#LOADED_MAFIA_JS")
self.wssock.send(self.detectives, "#TYPE:Detective")
self._wait_acknowledge(self.detectives, "#LOADED_DETECTIVE_JS")
self.wssock.send(self.mafias, "#MAFIA_NAMES:" + ",".join([str(m) for m in self.mafias]))
self.wssock.send(self.detectives, "#DETECTIVE_NAMES:" + ",".join([str(d) for d in self.detectives]))
def _wait_acknowledge(self, cl_list, message):
looking_for = {(cl, message) for cl in cl_list}
forward_q_set = set(self.wssock.forward_q)
while (forward_q_set | looking_for != forward_q_set):
looking_for = {(cl, message) for cl in cl_list}
forward_q_set = set(self.wssock.forward_q)
with self.wssock.forward_q_lock:
self.wssock.forward_q = []
def mafia_round(self):
self.wssock.send(self.mafias, "#MAFIA_VOTE")
print("Sent.")
vote_state = self._vote_mechanism(self.mafias,self.wssock.client_list, self.mafias)
votes_counter = {x:0 for x in self.wssock.client_list}
for key in vote_state:
print(str(key) + " : " + str(vote_state[key]))
votes_counter[vote_state[key]]+=1
max_votes = sorted(votes_counter, key=votes_counter.get, reverse=True)[0]
return (max_votes)
def detective_round(self):
self.wssock.send(self.detectives, "#DETECTIVE_VOTE")
print("Sent")
vote_state = self._vote_mechanism(self.detectives, self.wssock.client_list, self.detectives);
votes_counter = {x:0 for x in self.wssock.client_list}
for key in vote_state:
print(str(key) + " : " + str(vote_state[key]))
votes_counter[vote_state[key]]+=1
max_votes = sorted(votes_counter, key=votes_counter.get, reverse=True)[0]
self.wssock.send(self.detectives, "#DETECTION_RESULT:"+max_votes.name+":"+str(max_votes in self.mafias))
def first_voting_round(self):
self.wssock.send(self.wssock.client_list, "#VOTE_ANON")
print("Gen vote 1")
vote_state = self._vote_mechanism(self.wssock.client_list,self.wssock.client_list)
votes_counter = {x:0 for x in self.wssock.client_list}
for key in vote_state:
print(str(key) + " : " + str(vote_state[key]))
votes_counter[vote_state[key]]+=1
#I need to sort votes_counter by keys, so it's best to finalize it as a list. The question is, how should I sort?
max_votes = sorted(votes_counter, key=votes_counter.get, reverse=True)
if(len(max_votes)==1): return max_votes[0],max_votes[0]
return max_votes[0], max_votes[1];
def discussion_round(self, max_votes, max_votes2):
self.wssock.send(self.wssock.client_list,"#DISCUSSION:"+max_votes.name+","+max_votes2.name)
self._wait_acknowledge(self.wssock.client_list, "#DONE_DISCUSSION")
def second_voting_round(self):
self.wssock.send(self.wssock.client_list, "#VOTE_OPEN")
print("Gen vote 2")
vote_state = self._vote_mechanism(self.wssock.client_list,self.wssock.client_list,self.wssock.client_list)
votes_counter = {x:0 for x in self.wssock.client_list}
for key in vote_state:
print(str(key) + " : " + str(vote_state[key]))
votes_counter[vote_state[key]]+=1
max_votes = sorted(votes_counter, key=votes_counter.get, reverse=True)[0]
self.wssock.send(self.wssock.client_list, "#ELIMINATED:"+max_votes.name+":"+str(max_votes in self.mafias))
return max_votes
def _vote_mechanism(self, voter_list, votee_list, send_to_list=None):
breaking = 0
votee_str_dic = {str(v.name):v for v in votee_list}
vote_state = {}
while breaking!=len(voter_list):
time.sleep(0.5) #TODO: NEEDS INVESTIGATION. Without a time.sleep, it fails periodically
with self.wssock.forward_q_lock:
# if len(self.wssock.forward_q)!=0:print(self.wssock.forward_q)
for i in range(len(self.wssock.forward_q)):
cl,mes = self.wssock.forward_q.pop()
for v in voter_list:
if (v,"#DONE_VOTING")==(cl,mes):
breaking += 1
if(mes[:len("#VOTE:")] == "#VOTE:"):
votee_key = mes[len("#VOTE:"):]
vote_state[cl] = votee_str_dic[votee_key]
if send_to_list!=None:
self.wssock.send(send_to_list, "#VOTE:" + cl.name + ":" + votee_key)
return vote_state
def play(self, num=6):
self.type_round(num)
time.sleep(2)
while len(self.mafias)!=0 and len(self.victims)+len(self.detectives)>=len(self.mafias):
time.sleep(2)
who_died = self.mafia_round()
self.detective_round()
#time for anonymous voting round!
self.wssock.send(self.wssock.client_list, "#KILLED:" + who_died.name)
max1, max2 = self.first_voting_round()
self.discussion_round(max1, max2)
eliminated = self.second_voting_round()
time.sleep(2)
if who_died in self.mafias: self.mafias.remove(who_died)
if who_died in self.victims: self.victims.remove(who_died)
if who_died in self.detectives: self.detectives.remove(who_died)
if eliminated in self.mafias: self.mafias.remove(eliminated)
if eliminated in self.victims: self.victims.remove(eliminated)
if eliminated in self.detectives: self.detectives.remove(eliminated)
if(len(self.mafias)==0):
self.wssock.send(self.wssock.client_list, "#WIN:CITIZEN")
else:
self.wssock.send(self.wssock.client_list, "#WIN:MAFIA")
n = 6
import sys
if(len(sys.argv)==2):
n = int(sys.argv[1])
MafiaGame().play(n)