콘텐츠로 이동

Game

Game 클래스는 테트리스 게임의 전체 흐름을 제어하고, 스코어링, 피스 스폰, 게임 오버 처리를 담당합니다.

API Reference

Game

Game(board: Board, queue: TetrominoQueue, initial_position: str = 'center')

Manages Tetris game logic and orchestration.

Responsibilities: - Game state management (score, lines cleared, game over) - Piece spawning and movement - Reward calculation - Game flow orchestration

Initialize a new game.

Parameters:

Name Type Description Default
board Board

Board instance to use

required
queue TetrominoQueue

TetrominoQueue instance for piece generation

required
initial_position str

How to position new pieces ("center" or "left")

'center'
Source code in rl_tetris/core/game.py
def __init__(
    self,
    board: Board,
    queue: TetrominoQueue,
    initial_position: str = "center"
):
    """
    Initialize a new game.

    Args:
        board: Board instance to use
        queue: TetrominoQueue instance for piece generation
        initial_position: How to position new pieces ("center" or "left")
    """
    self.board = board
    self.queue = queue
    self.initial_position = initial_position

    self.current_piece: Optional[Piece] = None
    self.score = 0
    self.cleared_lines = 0
    self.gameover = False

reset

reset() -> None

Reset the game to initial state.

Source code in rl_tetris/core/game.py
def reset(self) -> None:
    """Reset the game to initial state."""
    self.board.reset()
    self.queue.reset()
    self.score = 0
    self.cleared_lines = 0
    self.gameover = False
    self.spawn_piece()

spawn_piece

spawn_piece() -> bool

Spawn a new piece at the top of the board.

Returns:

Type Description
bool

True if piece was spawned successfully, False if game over

Source code in rl_tetris/core/game.py
def spawn_piece(self) -> bool:
    """
    Spawn a new piece at the top of the board.

    Returns:
        True if piece was spawned successfully, False if game over
    """
    piece_type = self.queue.pop()
    x, y = self._calculate_spawn_position(piece_type)

    self.current_piece = Piece(piece_type, x, y)

    # Check if the new piece collides immediately (game over condition)
    if self.board.check_collision(self.current_piece.shape, x, y):
        self.gameover = True
        return False

    return True

move_piece

move_piece(dx: int, dy: int) -> bool

Move the current piece by the given offset if valid.

Parameters:

Name Type Description Default
dx int

Change in x position

required
dy int

Change in y position

required

Returns:

Type Description
bool

True if move was successful, False otherwise

Source code in rl_tetris/core/game.py
def move_piece(self, dx: int, dy: int) -> bool:
    """
    Move the current piece by the given offset if valid.

    Args:
        dx: Change in x position
        dy: Change in y position

    Returns:
        True if move was successful, False otherwise
    """
    if self.can_move(dx, dy):
        self.current_piece.move(dx, dy)
        return True
    return False

rotate_piece

rotate_piece() -> bool

Rotate the current piece clockwise if valid.

Returns:

Type Description
bool

True if rotation was successful, False otherwise

Source code in rl_tetris/core/game.py
def rotate_piece(self) -> bool:
    """
    Rotate the current piece clockwise if valid.

    Returns:
        True if rotation was successful, False otherwise
    """
    if self.can_rotate():
        self.current_piece.rotate_clockwise()
        return True
    return False

hard_drop

hard_drop() -> int

Drop the current piece to the lowest valid position.

Returns:

Type Description
int

Number of cells the piece dropped

Source code in rl_tetris/core/game.py
def hard_drop(self) -> int:
    """
    Drop the current piece to the lowest valid position.

    Returns:
        Number of cells the piece dropped
    """
    if not self.current_piece:
        return 0

    drop_distance = 0
    while self.can_move(0, 1):
        self.current_piece.move(0, 1)
        drop_distance += 1

    return drop_distance

lock_piece

lock_piece() -> Tuple[int, bool]

Lock the current piece to the board and handle line clearing.

Returns:

Type Description
Tuple[int, bool]

Tuple of (lines_cleared, is_game_over)

Source code in rl_tetris/core/game.py
def lock_piece(self) -> Tuple[int, bool]:
    """
    Lock the current piece to the board and handle line clearing.

    Returns:
        Tuple of (lines_cleared, is_game_over)
    """
    if not self.current_piece:
        return 0, True

    # Check if piece is overflowing the top (game over condition)
    is_overflow = self._is_piece_overflowing()

    # Place the piece on the board
    self.board.place_piece(
        self.current_piece.shape,
        self.current_piece.x,
        self.current_piece.y
    )

    # Clear full rows
    lines_cleared = self.board.clear_full_rows()
    self.cleared_lines += lines_cleared

    # Calculate and add reward
    reward = self.calculate_reward(lines_cleared, is_overflow)
    self.score += reward

    if is_overflow:
        self.gameover = True
        return lines_cleared, True

    # Spawn next piece
    success = self.spawn_piece()
    return lines_cleared, not success

calculate_reward

calculate_reward(lines_cleared: int, is_overflow: bool = False) -> int

Calculate reward based on lines cleared and game state.

Parameters:

Name Type Description Default
lines_cleared int

Number of lines cleared

required
is_overflow bool

Whether the piece caused overflow (game over)

False

Returns:

Type Description
int

Reward value

Source code in rl_tetris/core/game.py
def calculate_reward(self, lines_cleared: int, is_overflow: bool = False) -> int:
    """
    Calculate reward based on lines cleared and game state.

    Args:
        lines_cleared: Number of lines cleared
        is_overflow: Whether the piece caused overflow (game over)

    Returns:
        Reward value
    """
    base_reward = 1 + (lines_cleared ** 2) * self.board.width

    if is_overflow:
        return base_reward - 5

    return base_reward

Usage Examples

게임 시작

from rl_tetris.core import Board, Game
from rl_tetris.tetromino_queue import TetrominoQueue
from rl_tetris.randomizer import BagRandomizer

# 컴포넌트 생성
board = Board(height=20, width=10)
queue = TetrominoQueue(BagRandomizer())
game = Game(board, queue)

# 게임 시작
game.reset()
print(f"Current piece type: {game.current_piece.piece_type}")

피스 조작

# 피스 이동
if game.move_piece(dx=1, dy=0):
    print("Moved right")

if game.move_piece(dx=0, dy=1):
    print("Moved down")

# 피스 회전
if game.rotate_piece():
    print("Rotated")

# 하드 드롭
rows_dropped = game.hard_drop()
print(f"Dropped {rows_dropped} rows")

게임 루프

game.reset()

while not game.gameover:
    # 피스 조작
    game.move_piece(1, 0)
    game.rotate_piece()

    # 하드 드롭 및 고정
    game.hard_drop()
    lines_cleared, is_game_over = game.lock_piece()

    # 보상 계산
    reward = game.calculate_reward(lines_cleared, is_game_over)

    print(f"Lines: {lines_cleared}")
    print(f"Score: {game.score}")
    print(f"Reward: {reward}")

    if is_game_over:
        print("Game Over!")
        break

스코어링

# 줄 클리어에 따른 점수
# 1줄: 100점
# 2줄: 300점
# 3줄: 500점
# 4줄 (Tetris): 800점

lines_cleared, _ = game.lock_piece()
print(f"Score: {game.score}")
print(f"Total lines: {game.cleared_lines}")

Scoring System

Lines Cleared Points
1 100
2 300
3 500
4 (Tetris) 800

Reward System

강화학습을 위한 보상:

  • 줄 클리어: lines_cleared² (1줄=1, 2줄=4, 3줄=9, 4줄=16)
  • 게임 오버: -10
  • 일반 이동: 0

See Also