cetragm 0.1.2__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.
Potentially problematic release.
This version of cetragm might be problematic. Click here for more details.
- 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.2.dist-info/METADATA +71 -0
- cetragm-0.1.2.dist-info/RECORD +17 -0
- cetragm-0.1.2.dist-info/WHEEL +4 -0
- cetragm-0.1.2.dist-info/entry_points.txt +4 -0
- cetragm-0.1.2.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 cgm.draw import draw_board
|
|
10
|
+
from cgm.game import lock_piece, collides, rotate
|
|
11
|
+
from cgm.player import Player
|
|
12
|
+
from cgm.bag import Bag
|
|
13
|
+
from cgm.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 cgm.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 cgm.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)
|