Files
project_game/cursor/test_game.py
Chris Proctor c8d1ddd58f Started retro tetris game
Started developing a retro version of Tetris, following
the planning on the board of the classroom
(see planning.jpg).

Moved cursor work into cursor.
2025-12-18 17:45:39 -05:00

143 lines
3.1 KiB
Python

import inspect
import os
import random
import sys
import retro
import tetris
from retro.agent import ArrowKeyAgent
# Expose Game name expected by create_game helper
game = tetris.Tetris()
# --- Factory helpers and small harness ---
def create_game():
"""Create a Game instance with minimal sensible defaults."""
try:
return Game()
except TypeError:
try:
sig = inspect.signature(Game)
kwargs = {}
if 'agents' in sig.parameters:
kwargs['agents'] = []
if 'state' in sig.parameters:
kwargs['state'] = {}
return Game(**kwargs)
except Exception:
for args in (([], {}), ([], None), ([],), (None,)):
try:
return Game(*args)
except Exception:
continue
raise
def create_agent(game=None):
try:
return ArrowKeyAgent(game)
except TypeError:
return ArrowKeyAgent()
def draw_screen(game: Game):
# simple text render
game.clear()
s = game.draw_board()
game.refresh()
# store/return the string for tests
return s
def main():
argv = sys.argv[1:]
if len(argv) >= 1 and argv[0] == 'play':
# Try to run a terminal player. Use curses if available.
try:
play_in_terminal(create_game())
except Exception as e:
print('Terminal play failed:', e)
print('Run without args to run smoke tests instead.')
return
game = create_game()
agent = create_agent(game)
while not game.is_over():
action = agent.get_action()
game.step(action)
draw_screen(game)
print('Game Over! Score:', game.get_score())
def play_in_terminal(game):
"""Simple curses-based player loop.
Controls:
- Left/Right arrows or 'a'/'d' to move
- Up arrow or 'w' to rotate
- Down arrow or 's' to soft drop
- Space for hard drop
- 'q' to quit
"""
keymap = {
# map keys to the Testris.action integer codes:
# 0 noop, 1 left, 2 right, 3 rotate, 4 soft drop
curses.KEY_LEFT: 1,
curses.KEY_RIGHT: 2,
curses.KEY_UP: 3,
curses.KEY_DOWN: 4,
ord('a'): 1,
ord('d'): 2,
ord('w'): 3,
ord('s'): 4,
# space will perform a hard drop (special handling)
ord(' '): 'hard_drop',
ord('q'): 'quit',
}
# --- Simple smoke tests ---
def test_game_initialization():
g = create_game()
assert g is not None
assert g.get_score() == 0
assert not g.is_over()
def test_game_step():
g = create_game()
score0 = g.get_score()
g.step(0)
assert g.get_score() >= score0
def test_draw_board_returns_str():
g = create_game()
s = g.draw_board()
assert isinstance(s, str)
def test_game_over_sequence():
g = create_game()
# run a few steps to ensure no immediate crash
for _ in range(50):
if g.is_over():
break
g.step(0)
assert g.get_score() >= 0
if __name__ == '__main__':
main()