-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.py
238 lines (181 loc) · 9.69 KB
/
main.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
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
import math
# name of cards are written as a tuple. Their indexes are indicative of their game value.
cards = ("2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A")
# liars function returns the probability of "x" desired cards being present randomly in "n" unknown cards
# while there are "maxx" unknown desired cards in "t" unknown cards in total.
def liars(n, x, t, m):
return math.comb(n, x) * math.comb(m, x) * math.comb(t - m, n - x) / (math.comb(t, x) * math.comb(t - x, n - x))
# conditional_p function returns "p", the probability of "x" or more desired cards being present randomly in "n" cards
# while there are "k" known cards present and "b" known desired cards present
# which there are total of "t" cards and "m" desired cards.
def conditional_p(n, x, k, b, t=52, m=8):
p = 0
for i in range(x, m + 1):
if i - b > n - k:
continue
if i - b < 0:
return 1
p += liars(n - k, i - b, t - k, m - b)
return p
# claim_p returns the probability of the claim "c"
# with "t" being the dictionary of known cards and there are "n" cards on the table.
# dictionary of known cards has keys as the name of a card and values as number of that card known.
# a claim is a tuple whose first element is number of the card in question and second element is the name of the card.
def claim_p(n, t, c):
k = 0
for i in t.values():
k += i
if c[1] == "2":
return conditional_p(n, c[0], k, t.get(c[1], 0))
return conditional_p(n, c[0], k, t.get(c[1], 0) + t.get("2", 0))
# this function returns all the possible legal claims with "c" being the previous claim.
# if c is not specified, output will be the whole list.
def legal_claims(c=(2, "2")):
card_values = {"2": 0, "3": 1, "4": 2, "5": 3, "6": 4, "7": 5, "8": 6, "9": 7, "10": 8, "J": 9, "Q": 10, "K": 11,
"A": 12}
list_of_legal_claims = []
initial_value = card_values[c[1]]
for i in range(c[0], 9):
for j in range(initial_value + 1, card_values["A"] + 1):
list_of_legal_claims.append((i, cards[j]))
initial_value = 0
return list_of_legal_claims
# this function handles a string claim input and turns it to a proper tuple claim.
def claim_handler(claim_input):
claim = claim_input.upper().split()
claim[0] = int(claim[0])
return tuple(claim)
# this function handles string card information and turns it to a proper known cards dictionary.
def card_handler(cards_input):
cards_dictionary = {}
for i in cards_input.upper().split():
cards_dictionary[i] = cards_dictionary.get(i, 0) + 1
return cards_dictionary
# claims_and_probs function returns the list of legal claims and their probabilities
# given "n", number of cards in the game; "t", the dictionary of known cards and the previous claim. the list is sorted,
# starting from the most probable.
def claims_and_probabilities(n, t, previous_claim):
claims = legal_claims(previous_claim)
claims_and_probs = []
for i in claims:
claims_and_probs.append([i, claim_p(n, t, i)])
return sorted(claims_and_probs, key=lambda x: x[1])[::-1]
# action_of_choice returns the best move given the most probable claim and its probability
# and the probability of the previous claim.
def action_of_choice(claim_and_its_probability, p_of_previous_claim):
if claim_and_its_probability[1] > 1 - p_of_previous_claim:
return "claim that there are {} {}'s since this is likelier than the previous being false". \
format(claim_and_its_probability[0][0], claim_and_its_probability[0][1])
else:
return "open the cards since your best claim is not likely than the previous being false"
# this function takes a probability as an input, rounds it and returns as visually nice percentage.
def goodformat(p):
return str(round(p * 100, 2)) + "%"
# top_x_most_probable_claims returns the most probable x claims in a nice way.
def top_x_most_probable_claims(x, claims_and_probs):
for i in range(x):
print("There are {} {}'s => {}".format(claims_and_probs[i][0][0],
claims_and_probs[i][0][1],
goodformat(claims_and_probs[i][1])))
# the never ending game mode in which the player will need to give the necessary informations needed
# every time they want to know the probability of a specific claim in a specific scenario.
def infinite_claims():
while True:
print("How many cards are there in the game?")
a = input().lower()
if a == "":
return
n = int(a)
print("Which cards do you have?")
your_cards_input = input()
print("Which other cards do you think are on the table?")
other_cards_input = input()
print("What do you claim?")
claim = claim_handler(input())
all_cards_dict = card_handler(your_cards_input)
your_cards_dict = card_handler(your_cards_input + " " + other_cards_input)
print("If what you think about the other cards are true, the probability of the claim is",
goodformat(claim_p(n, your_cards_dict, claim)))
print("Based just on your own cards, the probability is", goodformat(claim_p(n, all_cards_dict, claim)))
print("\nIf you want to learn about best claims above some claim, write that claim. Else, just pass.")
sus_input = input()
if sus_input == "":
continue
sus_claim = claim_handler(sus_input)
best_claim_and_p_based_on_all = claims_and_probabilities(n, all_cards_dict, sus_claim)
best_claim_and_p_based_on_yours = claims_and_probabilities(n, your_cards_dict, sus_claim)
print("How many claims you want printed out?")
top_number = int(input())
print(f"Top {top_number} claims you can make")
print("\nIf you are right about the cards:")
top_x_most_probable_claims(top_number, best_claim_and_p_based_on_all)
print("\nIf we consider only the cards you have:")
top_x_most_probable_claims(top_number, best_claim_and_p_based_on_yours)
# "liars: the game". keeps all the information about how the game progresses.
# probabilities are calculated for two scenarios:
# in the first one, your guesses for the other cards in the game along with your own cards are considered.
# in the second one, only your cards are considered.
# "n" is the initial number of cards there are.
def game(n):
n = int(n)
previous_claim = (2, "2")
print("There are total of {} cards in the game.".format(n))
print("Which cards do you have?")
your_cards_input = input()
print("Which other cards do you think are on the table?")
other_cards_input = input()
print("What was the last claim?")
last_claim_input = input()
print("Do you have any specific claim you want to know about?")
special_claim_input = input()
your_cards_dict = card_handler(your_cards_input)
all_cards_dict = card_handler(your_cards_input + " " + other_cards_input)
if last_claim_input != "":
previous_claim = claim_handler(last_claim_input)
if special_claim_input != "":
special_claim = claim_handler(special_claim_input)
print("The probability of your claim is {} if you are right about the other cards. If not, it is {}".format(
goodformat(claim_p(n, all_cards_dict, special_claim)),
goodformat(claim_p(n, your_cards_dict, special_claim))))
prev_claim_probs = (claim_p(n, all_cards_dict, previous_claim), claim_p(n, your_cards_dict, previous_claim))
print("The probability of the previous claim is {} if you are right about the other cards. If not, it is {}".format(
goodformat(prev_claim_probs[0]), goodformat(prev_claim_probs[1])))
best_claim_and_p_based_on_all = claims_and_probabilities(n, all_cards_dict, previous_claim)
best_claim_and_p_based_on_yours = claims_and_probabilities(n, your_cards_dict, previous_claim)
print("\nTop 10 claims you can make")
print("\nIf you are right about the cards:")
top_x_most_probable_claims(10, best_claim_and_p_based_on_all)
print("\nIf we consider only the cards you have:")
top_x_most_probable_claims(10, best_claim_and_p_based_on_yours)
print(
"\nYour best action would be to {} if you are right about the cards. \nIf not, best action would be to {}."
.format(
action_of_choice(best_claim_and_p_based_on_all[0], prev_claim_probs[0]),
action_of_choice(best_claim_and_p_based_on_yours[0], prev_claim_probs[1])))
finisher = input().lower()
while True:
if finisher == "n":
return game(n + 1)
if finisher == "l":
print("How many cards are removed?")
return game(n - int(input()))
if finisher == "f":
return
print("Please write: (without the quotation marks)")
print("\"n\" if game continued with someone having one more card.")
print("\"l\" if game continued with someone eliminated.")
print("\"f\" if game is finished.")
print("Please select your what you want:")
print("write 'g' if you want to play the normal game")
print("write 'i' if you want to know about a specific claim in a specific scenario")
while True:
wanted_game_mode = input().lower()
if wanted_game_mode == "g":
print("To play the game, please provide the number of cards in the game.")
game(int(input()))
break
if wanted_game_mode == "i":
infinite_claims()
break
else:
print("Your input was invalid.")