cetragm 0.1.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cetragm/__init__.py +16 -0
- cetragm/audio.py +1 -0
- cetragm/bag.py +24 -0
- cetragm/config.py +18 -0
- cetragm/controls.py +102 -0
- cetragm/draw.py +154 -0
- cetragm/game.py +101 -0
- cetragm/main.py +322 -0
- cetragm/player.py +78 -0
- cetragm/srs.py +1 -0
- cetragm/tables.py +416 -0
- cetragm/ui.txt +48 -0
- cetragm-0.1.3.dist-info/METADATA +71 -0
- cetragm-0.1.3.dist-info/RECORD +17 -0
- cetragm-0.1.3.dist-info/WHEEL +4 -0
- cetragm-0.1.3.dist-info/entry_points.txt +4 -0
- cetragm-0.1.3.dist-info/licenses/LICENSE +674 -0
cetragm/main.py
ADDED
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
# Main module
|
|
2
|
+
import os
|
|
3
|
+
import sys
|
|
4
|
+
import time
|
|
5
|
+
import threading
|
|
6
|
+
import signal
|
|
7
|
+
import queue
|
|
8
|
+
|
|
9
|
+
from cetragm.draw import draw_board
|
|
10
|
+
from cetragm.game import lock_piece, collides, rotate
|
|
11
|
+
from cetragm.player import Player
|
|
12
|
+
from cetragm.bag import Bag
|
|
13
|
+
from cetragm.controls import InputHandler
|
|
14
|
+
|
|
15
|
+
def sigint_handler(sig, frame):
|
|
16
|
+
sigint.set()
|
|
17
|
+
print("\x1b[2j\x1b[Hgoodbye!")
|
|
18
|
+
|
|
19
|
+
sigint = threading.Event()
|
|
20
|
+
lose = threading.Event()
|
|
21
|
+
board_lock = threading.Lock()
|
|
22
|
+
ROT_SEQ = ["0", "r", "2", "l"]
|
|
23
|
+
|
|
24
|
+
signal.signal(signal.SIGINT, sigint_handler)
|
|
25
|
+
|
|
26
|
+
def setup_board(rows, cols):
|
|
27
|
+
board = [[[0] for _ in range(cols)] for _ in range(rows)]
|
|
28
|
+
return board
|
|
29
|
+
|
|
30
|
+
def lock_and_are(player, board, shared):
|
|
31
|
+
board, cleared, loss = lock_piece(player.active_piece, board, player)
|
|
32
|
+
shared["board"] = board
|
|
33
|
+
|
|
34
|
+
if loss:
|
|
35
|
+
lose.set()
|
|
36
|
+
return "loss", 0.0
|
|
37
|
+
|
|
38
|
+
player.active_piece = {}
|
|
39
|
+
player.fall_progress = 0.0
|
|
40
|
+
player.hold_lock = False
|
|
41
|
+
player.soft = 0
|
|
42
|
+
|
|
43
|
+
if cleared:
|
|
44
|
+
return "line_clear", 0.0
|
|
45
|
+
else:
|
|
46
|
+
return "are", 0.0
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def lock_now(player, board, shared, bag):
|
|
50
|
+
try:
|
|
51
|
+
board, cleared, loss = lock_piece(player.active_piece, board, player)
|
|
52
|
+
except ValueError:
|
|
53
|
+
lose.set()
|
|
54
|
+
return "loss"
|
|
55
|
+
shared["board"] = board
|
|
56
|
+
|
|
57
|
+
if loss:
|
|
58
|
+
lose.set()
|
|
59
|
+
return "loss"
|
|
60
|
+
elif cleared:
|
|
61
|
+
player.active_piece = {}
|
|
62
|
+
player.fall_progress = 0.0
|
|
63
|
+
player.soft = 0
|
|
64
|
+
return "line_clear"
|
|
65
|
+
else:
|
|
66
|
+
player.active_piece = {"name": bag.get_piece(), "pos": [3, 0], "rotation": "0"}
|
|
67
|
+
player.fall_progress = 0.0
|
|
68
|
+
player.soft = 0
|
|
69
|
+
player.hold_lock = False
|
|
70
|
+
return "active"
|
|
71
|
+
|
|
72
|
+
def input_handler(player, board, action, bag, shared, LOCK_DELAY, FRAME):
|
|
73
|
+
if not player.active_piece:
|
|
74
|
+
return None
|
|
75
|
+
|
|
76
|
+
piece = player.active_piece
|
|
77
|
+
x, y = piece["pos"]
|
|
78
|
+
|
|
79
|
+
if action == "pause":
|
|
80
|
+
sigint.set()
|
|
81
|
+
return None
|
|
82
|
+
|
|
83
|
+
elif action == "move_left":
|
|
84
|
+
piece["pos"][0] -= 1
|
|
85
|
+
if collides(piece, board):
|
|
86
|
+
piece["pos"][0] += 1
|
|
87
|
+
return None
|
|
88
|
+
|
|
89
|
+
elif action == "move_right":
|
|
90
|
+
piece["pos"][0] += 1
|
|
91
|
+
if collides(piece, board):
|
|
92
|
+
piece["pos"][0] -= 1
|
|
93
|
+
return None
|
|
94
|
+
|
|
95
|
+
elif action == "soft_drop":
|
|
96
|
+
piece["pos"][1] += 1
|
|
97
|
+
if collides(piece, board):
|
|
98
|
+
piece["pos"][1] -= 1
|
|
99
|
+
return "ground"
|
|
100
|
+
player.soft += 1
|
|
101
|
+
return None
|
|
102
|
+
|
|
103
|
+
elif action == "hard_drop":
|
|
104
|
+
while not collides(piece, board):
|
|
105
|
+
piece["pos"][1] += 1
|
|
106
|
+
piece["pos"][1] -= 1
|
|
107
|
+
player.soft += 4
|
|
108
|
+
return lock_now(player, board, shared, bag)
|
|
109
|
+
|
|
110
|
+
elif action == "rotate_cw":
|
|
111
|
+
old_rot = piece["rotation"]
|
|
112
|
+
piece["rotation"] = rotate(old_rot, +1)
|
|
113
|
+
if collides(piece, board):
|
|
114
|
+
piece["rotation"] = old_rot
|
|
115
|
+
return None
|
|
116
|
+
|
|
117
|
+
elif action == "rotate_ccw":
|
|
118
|
+
old_rot = piece["rotation"]
|
|
119
|
+
piece["rotation"] = rotate(old_rot, -1)
|
|
120
|
+
if collides(piece, board):
|
|
121
|
+
piece["rotation"] = old_rot
|
|
122
|
+
return None
|
|
123
|
+
|
|
124
|
+
elif action == "rotate_180":
|
|
125
|
+
old_rot = piece["rotation"]
|
|
126
|
+
piece["rotation"] = rotate(old_rot, 2)
|
|
127
|
+
if collides(piece, board):
|
|
128
|
+
piece["rotation"] = old_rot
|
|
129
|
+
return None
|
|
130
|
+
|
|
131
|
+
elif action == "hold":
|
|
132
|
+
if player.hold_lock:
|
|
133
|
+
return None
|
|
134
|
+
old = player.hold_piece
|
|
135
|
+
player.hold_piece = player.active_piece["name"]
|
|
136
|
+
if not old:
|
|
137
|
+
player.active_piece = {"name": bag.get_piece(), "pos": [3, 0], "rotation": "0"}
|
|
138
|
+
player.fall_progress = 0.0
|
|
139
|
+
else:
|
|
140
|
+
player.active_piece = {"name": old, "pos": [3, 0], "rotation": "0"}
|
|
141
|
+
player.fall_progress = 0.0
|
|
142
|
+
player.hold_lock = True
|
|
143
|
+
return None
|
|
144
|
+
|
|
145
|
+
return None
|
|
146
|
+
|
|
147
|
+
def render_loop(shared, player, bag, fps):
|
|
148
|
+
frame_time = 1.0 / fps
|
|
149
|
+
while not sigint.is_set():
|
|
150
|
+
if lose.is_set():
|
|
151
|
+
sigint.set()
|
|
152
|
+
with board_lock:
|
|
153
|
+
board = shared["board"]
|
|
154
|
+
|
|
155
|
+
start = time.perf_counter()
|
|
156
|
+
player.upd_time()
|
|
157
|
+
print("\x1b[H\x1b[2J")
|
|
158
|
+
draw_board(
|
|
159
|
+
board,
|
|
160
|
+
player.active_piece,
|
|
161
|
+
player.score,
|
|
162
|
+
player.grade,
|
|
163
|
+
player.time_ms,
|
|
164
|
+
player.level,
|
|
165
|
+
player.line_goal,
|
|
166
|
+
player.hold_piece,
|
|
167
|
+
bag.get_preview()
|
|
168
|
+
) # got damn
|
|
169
|
+
elapsed = time.perf_counter() - start
|
|
170
|
+
sleep_time = frame_time - elapsed
|
|
171
|
+
if sleep_time > 0:
|
|
172
|
+
time.sleep(sleep_time)
|
|
173
|
+
else:
|
|
174
|
+
print("\x1b[H\x1b[31mRunning below 60fps!! Performance will be degraded\x1b[0m")
|
|
175
|
+
|
|
176
|
+
def game_loop(shared, player, bag, inputs, fps):
|
|
177
|
+
from cetragm.config import ARE_FRAMES, LINE_CLEAR_FRAMES, LOCK_DELAY_FRAMES
|
|
178
|
+
FRAME = 1.0 / fps
|
|
179
|
+
|
|
180
|
+
LOCK_DELAY = LOCK_DELAY_FRAMES * FRAME
|
|
181
|
+
ARE_DELAY = ARE_FRAMES * FRAME
|
|
182
|
+
LINE_CLEAR_DELAY = LINE_CLEAR_FRAMES * FRAME
|
|
183
|
+
|
|
184
|
+
state = "spawn"
|
|
185
|
+
lock_timer = 0.0
|
|
186
|
+
phase_timer = 0.0
|
|
187
|
+
|
|
188
|
+
last_time = time.perf_counter()
|
|
189
|
+
|
|
190
|
+
if not hasattr(player, "fall_progress"):
|
|
191
|
+
player.fall_progress = 0.0
|
|
192
|
+
|
|
193
|
+
while not sigint.is_set():
|
|
194
|
+
now = time.perf_counter()
|
|
195
|
+
dt = now - last_time
|
|
196
|
+
last_time = now
|
|
197
|
+
if dt > 0.1:
|
|
198
|
+
dt = 0.1
|
|
199
|
+
|
|
200
|
+
with board_lock:
|
|
201
|
+
board = shared["board"]
|
|
202
|
+
while True:
|
|
203
|
+
try:
|
|
204
|
+
action = inputs.queue.get_nowait()
|
|
205
|
+
except queue.Empty:
|
|
206
|
+
break
|
|
207
|
+
|
|
208
|
+
new_state = input_handler(player, board, action, bag, shared, LOCK_DELAY, FRAME)
|
|
209
|
+
|
|
210
|
+
if new_state == "ground":
|
|
211
|
+
lock_timer += dt
|
|
212
|
+
if lock_timer >= LOCK_DELAY:
|
|
213
|
+
state, lock_timer = lock_and_are(player, board, shared)
|
|
214
|
+
if state == "loss":
|
|
215
|
+
return
|
|
216
|
+
phase_timer = 0.0
|
|
217
|
+
continue
|
|
218
|
+
|
|
219
|
+
if new_state in ("line_clear", "are", "loss"):
|
|
220
|
+
state = new_state
|
|
221
|
+
phase_timer = 0.0
|
|
222
|
+
player.hold_lock = False
|
|
223
|
+
if state == "active":
|
|
224
|
+
player.fall_progess = 0.0
|
|
225
|
+
break
|
|
226
|
+
|
|
227
|
+
player.check_grade()
|
|
228
|
+
|
|
229
|
+
# gravity
|
|
230
|
+
if state == "active":
|
|
231
|
+
g_units = player.get_grav()
|
|
232
|
+
cells_per_frame = g_units / 256.0
|
|
233
|
+
cells_per_second = cells_per_frame * fps
|
|
234
|
+
player.fall_progress += cells_per_second * dt
|
|
235
|
+
cells_to_fall = int(player.fall_progress)
|
|
236
|
+
|
|
237
|
+
if cells_to_fall > 0:
|
|
238
|
+
player.fall_progress -= cells_to_fall
|
|
239
|
+
piece = player.active_piece
|
|
240
|
+
|
|
241
|
+
for _ in range(cells_to_fall):
|
|
242
|
+
piece["pos"][1] += 1
|
|
243
|
+
if collides(piece, board):
|
|
244
|
+
piece["pos"][1] -= 1
|
|
245
|
+
lock_timer += dt
|
|
246
|
+
if lock_timer >= LOCK_DELAY:
|
|
247
|
+
state, lock_timer = lock_and_are(player, board, shared)
|
|
248
|
+
if state == "loss":
|
|
249
|
+
return
|
|
250
|
+
phase_timer = 0.0
|
|
251
|
+
break
|
|
252
|
+
else:
|
|
253
|
+
lock_timer = 0.0
|
|
254
|
+
|
|
255
|
+
piece = player.active_piece
|
|
256
|
+
temp_pos = piece["pos"].copy()
|
|
257
|
+
temp_pos[1] += 1
|
|
258
|
+
if collides({"name": piece["name"], "pos": temp_pos, "rotation": piece["rotation"]}, board):
|
|
259
|
+
lock_timer += dt
|
|
260
|
+
if lock_timer >= LOCK_DELAY:
|
|
261
|
+
state, lock_timer = lock_and_are(player, board, shared)
|
|
262
|
+
if state == "loss":
|
|
263
|
+
return
|
|
264
|
+
phase_timer = 0.0
|
|
265
|
+
|
|
266
|
+
# pause after line clear
|
|
267
|
+
elif state == "line_clear":
|
|
268
|
+
phase_timer += dt
|
|
269
|
+
if phase_timer >= LINE_CLEAR_DELAY:
|
|
270
|
+
state = "are"
|
|
271
|
+
phase_timer = 0.0
|
|
272
|
+
|
|
273
|
+
# pause after a piece locking without soft drop
|
|
274
|
+
elif state == "are":
|
|
275
|
+
phase_timer += dt
|
|
276
|
+
if phase_timer >= ARE_DELAY:
|
|
277
|
+
player.active_piece = {"name": bag.get_piece(), "pos": [3, 0], "rotation": "0"}
|
|
278
|
+
player.fall_progress = 0.0
|
|
279
|
+
lock_timer = 0.0
|
|
280
|
+
state = "active"
|
|
281
|
+
|
|
282
|
+
# first piece
|
|
283
|
+
elif state == "spawn":
|
|
284
|
+
player.active_piece = {"name": bag.get_piece(), "pos": [3, 0], "rotation": "0"} # and again
|
|
285
|
+
player.fall_progress = 0.0
|
|
286
|
+
lock_timer = 0.0
|
|
287
|
+
state = "active"
|
|
288
|
+
|
|
289
|
+
elapsed_loop = time.perf_counter() - now
|
|
290
|
+
to_sleep = FRAME - elapsed_loop
|
|
291
|
+
time.sleep(to_sleep if to_sleep > 0 else 0)
|
|
292
|
+
|
|
293
|
+
# sigint
|
|
294
|
+
inputs.stop()
|
|
295
|
+
|
|
296
|
+
def entry():
|
|
297
|
+
player = Player()
|
|
298
|
+
bag = Bag(preview_size=5)
|
|
299
|
+
shared = { "board": setup_board(22, 10) }
|
|
300
|
+
|
|
301
|
+
inputs = InputHandler()
|
|
302
|
+
inputs.start()
|
|
303
|
+
|
|
304
|
+
try:
|
|
305
|
+
render_thread = threading.Thread(target=render_loop, args=(shared, player, bag, 60))
|
|
306
|
+
render_thread.start()
|
|
307
|
+
|
|
308
|
+
game_thread = threading.Thread(target=game_loop, args=(shared, player, bag, inputs, 60))
|
|
309
|
+
game_thread.start()
|
|
310
|
+
|
|
311
|
+
except KeyboardInterrupt:
|
|
312
|
+
sigint.set()
|
|
313
|
+
inputs.stop()
|
|
314
|
+
game_thread.join()
|
|
315
|
+
render_thread.join()
|
|
316
|
+
|
|
317
|
+
if __name__ == "__main__":
|
|
318
|
+
try:
|
|
319
|
+
os.system("clear")
|
|
320
|
+
entry()
|
|
321
|
+
except KeyboardInterrupt:
|
|
322
|
+
sys.exit(0)
|
cetragm/player.py
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# module containing the Player class and its functions
|
|
2
|
+
|
|
3
|
+
import time
|
|
4
|
+
from cetragm.tables import thresholds, gravity
|
|
5
|
+
|
|
6
|
+
class Player:
|
|
7
|
+
def __init__(self):
|
|
8
|
+
self.score = 0
|
|
9
|
+
self.time_ms = 0
|
|
10
|
+
self.start_time = time.perf_counter()
|
|
11
|
+
self.grade = "9"
|
|
12
|
+
self.level = 0
|
|
13
|
+
self.line_goal = 100
|
|
14
|
+
self.hold_piece = ""
|
|
15
|
+
self.active_piece = {}
|
|
16
|
+
|
|
17
|
+
# checks for midgame
|
|
18
|
+
self.can_gm = True
|
|
19
|
+
self.met_gm_condition_300 = False
|
|
20
|
+
self.met_gm_condition_500 = False
|
|
21
|
+
self.met_gm_condition_999 = False
|
|
22
|
+
|
|
23
|
+
self.combo = 0
|
|
24
|
+
self.soft = 0
|
|
25
|
+
self.hold_lock = False
|
|
26
|
+
self.fall_progress = 0.0
|
|
27
|
+
|
|
28
|
+
def upd_time(self):
|
|
29
|
+
self.time_ms = int((time.perf_counter() - self.start_time) * 1000)
|
|
30
|
+
|
|
31
|
+
def check_grade(self):
|
|
32
|
+
self.upd_time()
|
|
33
|
+
# checking for GM eligibility (called every piece, so it'll be up to date)
|
|
34
|
+
if not self.met_gm_condition_300 and self.level >= 300:
|
|
35
|
+
if self.time_ms <= 225000 and self.score >= 12000 and self.can_gm: # 4m 15s
|
|
36
|
+
self.met_gm_condition_300 = True
|
|
37
|
+
else:
|
|
38
|
+
self.can_gm = False
|
|
39
|
+
|
|
40
|
+
if not self.met_gm_condition_500 and self.level >= 500:
|
|
41
|
+
if self.time_ms <= 450000 and self.score >= 40000 and self.can_gm: # 7m 30s
|
|
42
|
+
self.met_gm_condition_500 = True
|
|
43
|
+
else:
|
|
44
|
+
self.can_gm = False
|
|
45
|
+
|
|
46
|
+
for name, val in thresholds.items(): # actually set grade
|
|
47
|
+
if self.score >= val:
|
|
48
|
+
if not self.grade == "Gm":
|
|
49
|
+
self.grade = name
|
|
50
|
+
else:
|
|
51
|
+
break
|
|
52
|
+
|
|
53
|
+
def check_gm(self):
|
|
54
|
+
self.upd_time()
|
|
55
|
+
if not self.can_gm:
|
|
56
|
+
return False
|
|
57
|
+
|
|
58
|
+
if not (self.met_gm_condition_300 and self.met_gm_condition_500):
|
|
59
|
+
return False
|
|
60
|
+
|
|
61
|
+
if self.time_ms <= 810000 and self.score >= 126000:
|
|
62
|
+
self.met_gm_condition_999 = True
|
|
63
|
+
self.grade = "Gm"
|
|
64
|
+
return True
|
|
65
|
+
return False
|
|
66
|
+
|
|
67
|
+
def get_grav(self):
|
|
68
|
+
keys = sorted(gravity.keys())
|
|
69
|
+
current_g = gravity[0]
|
|
70
|
+
for k in keys:
|
|
71
|
+
if self.level >= k:
|
|
72
|
+
current_g = gravity[k]
|
|
73
|
+
else:
|
|
74
|
+
break
|
|
75
|
+
|
|
76
|
+
if current_g <= 0:
|
|
77
|
+
return float('inf')
|
|
78
|
+
return current_g
|
cetragm/srs.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# Definitions of the tomfuckery that is Super Rotation System (rotation and wallkicks)
|