-
Notifications
You must be signed in to change notification settings - Fork 1
/
main.py
executable file
·181 lines (161 loc) · 6.45 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
#!/usr/bin/env python3
#
# Copyright (c) 2021-2023 alexcoder04 <https://github.com/alexcoder04>
# Copyright (c) 2021-2022 nilswgnr <https://github.com/nilswgnr>
#
# a script that can play the Uno card game
#
from db import SqliteDatabase
import argh
import random
from dl import _input, COLOR_MAP, NUMBER_MAP
CARDS_BEGIN = 7
class UnoPlayer:
def __init__(self, database, dataloader, dev_mode: bool) -> None:
print("Creating Uno Player...")
self.DEV_MODE = dev_mode
self.NORMAL_COLORS = {"r", "g", "b", "y"}
print("Creating Data Loader...")
self.dl = dataloader(dev_mode=dev_mode)
print("Creating Database...")
self.db = database(dev_mode=dev_mode)
self.made_first_move = False
self.skip_pull = None
self.players_number = self.dl.get_players_number()
print("Reading own cards...")
for _ in range(CARDS_BEGIN):
color, number, special = self.dl.read_card("Enter cards I got: ")
self.db.add_card(color, number, special)
self.dl.clear()
print("I am now ready to play!")
# the best color, which we wish if we put a joker
def best_color(self):
max_num = 0
selected = self.NORMAL_COLORS.copy()
for color in self.NORMAL_COLORS:
length = len(self.db.get_cards_by_color(color))
if length > max_num:
selected = {color}
max_num = length
continue
if length == max_num:
selected.add(color)
return random.choice(list(selected))
# output a message on the console
def say(self, message):
message = "-----" + message + "-----"
header = len(message) * "-"
print(header)
print(message)
print(header)
# put pulled card if it matches
def handle_pull(self, curColor, curNumber):
print("Well, I have to pull...")
color, number, special = self.dl.read_card("Enter the card I pulled:")
if special == 1:
self.say("I put pulled card")
self.say(f"I want {COLOR_MAP[self.best_color()]}!")
return
if color == curColor or number == curNumber:
self.say("I put pulled card")
return
self.db.add_card(color, number, special)
self.dl.clear()
# main game loop which runs
def game_loop(self):
while True:
cards = self.db.get_cards_all()
if self.DEV_MODE:
print(cards)
if len(cards) == 1:
self.say("UNO")
if len(cards) == 0:
print("WON!")
self.end_game()
break
if self.made_first_move:
print("Move ended\n")
else:
self.made_first_move = True
if self.skip_pull is None:
pull = self.dl.get_how_many_to_pull()
if pull != 0:
for _ in range(pull):
color, number, special = self.dl.read_card("Enter the card I pulled:")
self.db.add_card(color, number, special)
self.dl.clear()
continue
curColor, curNumber, _ = self.dl.read_card("Enter the card on stack:")
else:
(curColor, curNumber) = self.skip_pull
self.skip_pull = None
if curColor == "j":
curColor = input("What color was wished: ")
possible = self.db.get_cards_matching_no_special(curColor, curNumber)
if len(possible) == 0:
res = self.db.get_cards_special()
if len(res) == 0:
self.handle_pull(curColor, curNumber)
continue
if len(res) == 1:
(card_id, color, number, special) = res[0]
self.db.delete_card_by_id(card_id)
self.say(f"I Put {COLOR_MAP[color]} {NUMBER_MAP[number]}")
self.say(f"I want {COLOR_MAP[self.best_color()]}!")
if number == "+4" and self.players_number == 2:
self.skip_pull = (self.best_color(), number)
continue
jokers = [i for i in res if i[2] != "+4"]
plus4s = [i for i in res if i[2] == "+4"]
best_color = self.best_color()
if len(jokers) == 0:
(card_id, color, number, special) = random.choice(plus4s)
if self.players_number == 2:
self.skip_pull = (best_color, number)
else:
(card_id, color, number, special) = random.choice(jokers)
self.db.delete_card_by_id(card_id)
self.say(f"I Put {COLOR_MAP[color]} {NUMBER_MAP[number]}")
self.say(f"I want {COLOR_MAP[best_color]}!")
continue
(card_id, color, number, special) = random.choice(possible)
self.db.delete_card_by_id(card_id)
self.say(f"I Put {COLOR_MAP[color]} {NUMBER_MAP[number]}")
if number in ("+2", "n", "r") and self.players_number == 2:
self.skip_pull = (color, number)
def end_game(self):
print("Closing Database...")
self.db.close()
print("Thank you very much for the game!")
def die(msg="An error occured"):
print(msg)
exit(1)
@argh.arg("--db", "-b", help="select database ('sql')")
@argh.arg("--dl", "-l", help="select dataloader ('cmdline', 'camera', 'rcam', 'rcam2')")
@argh.arg("--dev-mode", "-d", help="whether to start in dev mode")
def run(db="sql", dl="camera", dev_mode=False):
if db == "sql":
database = SqliteDatabase
else:
die("Invalid databse selected. Available: 'sql'")
if dl == "cmdline":
from dl import CmdLineDataloader
dataloader = CmdLineDataloader
elif dl == "camera":
from dl import CameraDataloader
dataloader = CameraDataloader
elif dl == "rcam":
from dl import RCamDataloader
dataloader = RCamDataloader
elif dl == "rcam2":
from dl import RCam2Dataloader
dataloader = RCam2Dataloader
else:
die("Invalid dataloader selected. Available: 'cmdline', 'camera', 'rcam', 'rcam2'")
player = UnoPlayer(database, dataloader, dev_mode)
try:
player.game_loop()
except KeyboardInterrupt:
player.end_game()
if __name__ == "__main__":
argh.dispatch_command(run)