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