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/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)