Update scoring and handling

This commit is contained in:
2026-05-01 18:39:06 -07:00
parent c6c5e2720a
commit c6c77e9091
+93 -29
View File
@@ -300,14 +300,26 @@ class LazyVariable:
class Game:
NORMAL_PLACE_POINTS = 10
HARD_PLACE_POINTS = 20
CLEAR_POINTS = 100
# Points
DROP_POINTS = 1
HARD_DROP_POINTS = 2
POINTS_PER_LINE = [100, 300, 500, 800]
LINES_PER_LEVEL = 10
MOVE_SPEED = 20 # cells per second
MOVE_INITIAL_SLOWDOWN = 3.0 # cells
DROP_LEVEL_SCALE = 0.025
# These are *= 1 + (DROP_LEVEL_SCALE * (LEVEL - 1))
NORMAL_DROP_SPEED = 3 # cells per second
FAST_DROP_SPEED = 30 # cells per second
MOVED_PROP_SPEED = 1 # cells per second
CLEAR_SPEED = 10 # frames per block
MOVED_DROP_SPEED = 1 # cells per second
DROP_CLEAR_SCALE = 0.025
# This is *= 1 - (DROP_CLEAR_SCALE * (LEVEL - 1))
CLEAR_SPEED = 15 # frames per block
BOARD_SIZE = Size(10, 20) # Cell count
CELL_SIZE = Size(30, 30)
CELL_BORDER_SIZE = CELL_SIZE.width // 10
@@ -391,7 +403,7 @@ class Game:
pygame.K_h,
Action.Type.OPEN_HELP,
False,
"Toggle the help menu.",
"Toggle the help menu/pause.",
),
)
GAME_OVER_ACTION_MAP = Action.make_map(
@@ -620,7 +632,8 @@ class Game:
if cell and self.board[y + cy][x + cx]:
return True
except IndexError:
continue
# a cell was out of bounds of the board, this is a hit!
return True
return False
def rotate_current_piece(self, times: int):
@@ -636,10 +649,24 @@ class Game:
return
def move_current_piece(self, dir: Direction):
dx = dir * Game.MOVE_SPEED * self.frame_time()
self.subcell_move += dx
move_cell = int(self.subcell_move)
self.subcell_move -= move_cell
if self.was_move_down != dir:
self.subcell_move = 0
move_cell = dir
self.was_move_down = dir
self.inhibit_next_move = Game.MOVE_INITIAL_SLOWDOWN
else:
dx = dir * Game.MOVE_SPEED * self.frame_time()
self.subcell_move += dx
if self.inhibit_next_move > 0.0:
oi = self.inhibit_next_move
self.inhibit_next_move -= abs(self.subcell_move)
if self.inhibit_next_move <= 0.0:
self.inhibit_next_move = 0.0
self.subcell_move -= oi
else:
self.subcell_move = 0
move_cell = int(self.subcell_move)
self.subcell_move -= move_cell
if move_cell:
new_pos = Cell(
self.current_block_pos.x + move_cell, self.current_block_pos.y
@@ -658,10 +685,13 @@ class Game:
self.did_user_move_or_spin = True
def process_game_actions(self):
if not (
{Action.Type.MOVE_LEFT, Action.Type.MOVE_RIGHT}
& set(self.pending_actions)
):
move_set = {Action.Type.MOVE_LEFT, Action.Type.MOVE_RIGHT} & set(
self.pending_actions
)
move_both = len(move_set) == 2
if not move_set:
self.was_move_down = None
self.inhibit_next_move = 0.0
self.subcell_move = 0
if not (
{Action.Type.SOFT_DROP, Action.Type.HARD_DROP}
@@ -680,19 +710,17 @@ class Game:
self.soft_drop = True
case Action.Type.HARD_DROP if not self.stop_drop:
self.hard_drop = True
case Action.Type.MOVE_LEFT:
case Action.Type.MOVE_LEFT if not move_both:
self.move_current_piece(Direction.LEFT)
case Action.Type.MOVE_RIGHT:
self.was_move_down = Direction.LEFT
case Action.Type.MOVE_RIGHT if not move_both:
self.move_current_piece(Direction.RIGHT)
self.was_move_down = Direction.RIGHT
case Action.Type.RESTART:
self.start_new_game()
self.pending_actions = []
def place_piece(self, x: int, y: int, piece: Tetromino):
if self.hard_drop:
self.score += Game.HARD_PLACE_POINTS
else:
self.score += Game.NORMAL_PLACE_POINTS
for dy, row in enumerate(piece.shape):
for dx, cell in enumerate(row):
if cell:
@@ -711,21 +739,27 @@ class Game:
def advance_piece(self):
speed = Game.NORMAL_DROP_SPEED
if self.did_user_move_or_spin:
speed = Game.MOVED_PROP_SPEED
speed = Game.MOVED_DROP_SPEED
elif self.soft_drop:
speed = Game.FAST_DROP_SPEED
speed *= 1 + (Game.DROP_CLEAR_SCALE * (self.level - 1))
self.subcell_drop += speed * self.frame_time()
move_cell = int(self.subcell_drop)
self.subcell_drop -= move_cell
if self.hard_drop:
move_cell = self.cells_for_hard_drop()
if not move_cell:
return
cp = self.current_block_pos
if not self.intersects_board(
cp.x, cp.y + move_cell, self.current_block
):
self.score += move_cell * Game.DROP_POINTS * self.level
self.current_block_pos = Cell(cp.x, cp.y + move_cell)
# don't place the piece if the user moved it
elif not self.did_user_move_or_spin:
if self.hard_drop:
self.score += move_cell * Game.HARD_DROP_POINTS * self.level
for dy in range(move_cell, -1, -1):
if not self.intersects_board(
cp.x, cp.y + dy, self.current_block
@@ -744,6 +778,11 @@ class Game:
else:
return zip(range(bw // 2, -1, -1), range(bw // 2, bw))
def calc_clear_speed(self):
return Game.CLEAR_SPEED * (
1 - (Game.DROP_CLEAR_SCALE * (self.level - 1))
)
def maybe_clear_rows(self):
def do_single_clear(y: int):
row = self.board[y]
@@ -761,16 +800,25 @@ class Game:
if not self.clearing_rows:
for y, row in enumerate(self.board):
if all(row):
self.score += self.CLEAR_POINTS
self.clearing_rows.add(y)
if self.clearing_rows:
self.score += (
Game.POINTS_PER_LINE[len(self.clearing_rows) - 1]
* self.level
)
else:
if self.clearing_frames == self.CLEAR_SPEED:
speed = self.calc_clear_speed()
if self.clearing_frames >= speed:
if not any(self.board[next(iter(self.clearing_rows))]):
self.cleared_this_level += len(self.clearing_rows)
if self.cleared_this_level >= 10:
self.level += self.cleared_this_level // 10
self.cleared_this_level %= 10
# Order matters here
for y in sorted(self.clearing_rows):
drop_rows_above_for_clear(y)
self.clearing_rows = set()
self.clearing_frames = self.CLEAR_SPEED
self.clearing_frames = speed
else:
for y in self.clearing_rows:
do_single_clear(y)
@@ -780,8 +828,9 @@ class Game:
def draw_score_and_instructions(self):
text = (
"Press <h> \nfor help.\n"
"Press <h> \nfor help\nor pause.\n"
"\n"
f"Level: {self.level:02}\n"
f"Score: {self.score:05}\n"
f" HS: {self.high_score:05}"
)
@@ -955,6 +1004,8 @@ class Game:
self.process_and_draw_help_overlay()
def start_new_game(self):
self.was_move_down = None
self.inhibit_next_move = 0.0
self.cur_random_peice_seq = None
self.clear_board()
self.next_piece = None
@@ -965,8 +1016,11 @@ class Game:
self.subcell_drop = 0
self.clearing_rows = set()
# immediately clear the first block
self.clearing_frames = Game.CLEAR_SPEED
self.score = 0
self.level = 1
self.cleared_this_level = 0
# depends on level
self.clearing_frames = self.calc_clear_speed()
self.held_piece = None
self.game_over = False
@@ -1063,8 +1117,8 @@ class Game:
def move_piece_back_to_top(self):
self.current_block_pos = Cell(
self.BOARD_SIZE.width // 2
- math.ceil(self.current_block.width / 2),
0,
- math.ceil(self.current_block.bounding_box_width / 2),
0 - self.current_block.y_adj,
)
def swap_in_next_piece(self, force: bool = False):
@@ -1525,6 +1579,16 @@ GLYPH_DATA = [
"** ",
],
),
Font.Glyph(
"/",
[
" *",
" * ",
" * ",
" * ",
"* ",
],
),
]