-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.py
186 lines (154 loc) · 6.6 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
from ui.main_window import Ui_MainWindow
from input_window_logic import InputWindow
from error_window_logic import ErrorWindow
from functools import partial
from lib.classes import (
SubmitWindowInfo,
SubmitType,
GridSquare,
ConstraintDisplay,
CORRECT
)
from lib.database.utils import calc_game_difficulty, run_with_timeout
from game_algorithm import generate_game
import lib.stylesheets as ss
from lib.database.utils import get_hash_from_songname, get_db
from CONFIG import DEBUG, PB_WRAP_LEN, GAME_GENERATION_TIMEOUT_S
from PyQt5 import QtWidgets, QtCore
import sys
class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self, *args, **kwargs):
super(MainWindow, self).__init__(*args, **kwargs)
self.setupUi(self)
# get data from db
self._db = get_db()
# generate GridSquare objects
self.grid_buttons: list[list[GridSquare]] = []
for i in range(3):
buf = []
for j in range(3):
buf.append(GridSquare((i, j), getattr(self, f"r{i+1}c{j+1}_pb"), PB_WRAP_LEN, self._db))
self.grid_buttons.append(buf)
self.grid_displays: list[list[ConstraintDisplay]] = []
for pos in ["col", "row"]:
buf = []
for i in range(3):
buf.append(ConstraintDisplay(getattr(self, f"{pos}_{i+1}_l")))
self.grid_displays.append(buf)
self._used_song_hashes: set[str] = set()
# connect input window popup signals
for grid_row in self.grid_buttons:
for button in grid_row:
button.connect_click_callback(self._show_input_window)
self.restart_pb.clicked.connect(self._restart_game)
self._all_song_names: list[str] = [songname for _, songname in self._db["songs"].items()]
# set up autocompleter
self._completer = QtWidgets.QCompleter(self._all_song_names)
self._completer.setCaseSensitivity(False)
self.load_new_game()
self._display_constraints()
self._set_styles_to_default()
# gets info from input window on what song was selected
@QtCore.pyqtSlot(SubmitWindowInfo)
def _handle_input_window(self, value: SubmitWindowInfo):
self.setDisabled(False) # re-enable main window
# ignore cancelled inputs
if value.status == SubmitType.CANCEL:
return
x, y = value.pos
if value.song_name == "":
self.grid_buttons[x][y].clear()
self._update_game_status()
self._check_complete()
return
try:
song_hash = get_hash_from_songname(value.song_name)
except ValueError:
self._show_error_window("Invalid Song!")
return
if song_hash in self._used_song_hashes:
self._show_error_window("Song already used...")
return
self.grid_buttons[x][y].update(song_hash)
self._update_game_status()
self._check_complete()
def _show_input_window(self, row:int, col:int):
self._iw = InputWindow()
self._iw.set_pos(row, col) # window needs to know which cell it corresponds to
self._iw.entry_le.setCompleter(self._completer) # autocomplete
self._iw.callback.connect(self._handle_input_window)
self._iw.show()
# disable main window while the popup window is open
self.setDisabled(True)
def _display_constraints(self):
for constraint_row in self.grid_displays:
for c in constraint_row:
c.show_text()
def _set_styles_to_default(self):
for button_list in self.grid_buttons:
for button in button_list:
button.clear()
for display_list in self.grid_displays:
for display in display_list:
display.style()
self.restart_pb.setStyleSheet(ss.restart_button_ss)
def _restart_game(self):
self.setDisabled(True)
self.setWindowTitle("Loading...")
self.load_new_game()
self._display_constraints()
self._set_styles_to_default()
self.setWindowTitle("The Grateful Grid")
self.setDisabled(False)
for button_list in self.grid_buttons:
for button in button_list:
button.set_enable(True)
def _update_game_status(self):
self._used_song_hashes = set()
for button_list in self.grid_buttons:
for button in button_list:
if button.song_hash is not None:
self._used_song_hashes.add(button.song_hash)
for button_list in self.grid_buttons:
for button in button_list:
button.check_overconstrained(self._used_song_hashes)
def _check_complete(self):
for button_list in self.grid_buttons:
for button in button_list:
if button.status != CORRECT: return
self.setWindowTitle("YOU WIN!")
for button_list in self.grid_buttons:
for button in button_list:
button.set_enable(False)
def load_new_game(self):
self._game = run_with_timeout(generate_game, GAME_GENERATION_TIMEOUT_S, restart=True)
difficulty_score = calc_game_difficulty(self._game)
self.difficulty_label.setText(str(difficulty_score))
self.difficulty_label.setStyleSheet(f"background-color: {ss.title_background_colour_by_hardness[difficulty_score-1]}")
self._used_song_hashes = set()
if DEBUG:
self._game.print_all_info(self._db)
for i in range(3):
for j in range(3):
self.grid_buttons[i][j].possibilities = self._game.possibilities_at(i, j)
for i, c in enumerate(self.grid_displays[0]):
c.constraint = self._game.side_constraints[i]
c.connect_clicked_callback(self._show_error_window)
for i, c in enumerate(self.grid_displays[1]):
c.constraint = self._game.top_constraints[i]
c.connect_clicked_callback(self._show_error_window)
def _show_error_window(self, text: str):
self._ew = ErrorWindow()
self._ew.label.setText(text)
self._ew.setWindowTitle("—")
self._ew.callback.connect(partial(self.setDisabled, False))
self._ew.show()
self.setDisabled(True)
# runner and include guard
def main():
app = QtWidgets.QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec()
if __name__ == "__main__":
main()