loop-benchmarking

Controlled experiments across agentic coding configurations. Same task, one variable, what actually works.
git clone https://git.shiptheloop.com/loop-benchmarking.git
Log | Files | Refs | README

types.ts (5440B)


      1 import type { Page } from "@playwright/test";
      2 
      3 /** A 10x20 boolean grid: true = filled cell, false = empty. Row 0 is the top. */
      4 export type Grid = boolean[][];
      5 
      6 /** Pixel bounds of the game grid on the page. */
      7 export interface GridBounds {
      8   x: number;
      9   y: number;
     10   width: number;
     11   height: number;
     12 }
     13 
     14 /** How the game renders its grid. */
     15 export type RendererType = "canvas" | "dom" | "svg" | "unknown";
     16 
     17 /** Key mappings for game controls. */
     18 export interface Controls {
     19   left: string;
     20   right: string;
     21   down: string;
     22   rotate: string;
     23   drop: string;
     24 }
     25 
     26 /** How the game was started. */
     27 export type StartMechanism =
     28   | "auto"
     29   | "click_canvas"
     30   | "enter"
     31   | "space"
     32   | "button"
     33   | "anykey"
     34   | "unknown";
     35 
     36 /** Pre-test survey data collected before any tests run. */
     37 export interface SurveyData {
     38   has_overlay: boolean;
     39   has_canvas: boolean;
     40   has_dom_grid: boolean;
     41   visible_text: string[];
     42   clickable_elements: number;
     43 }
     44 
     45 /** Competitive play results (Phase 8). */
     46 export interface CompetitivePlayResult {
     47   duration_seconds: number;
     48   pieces_placed: number;
     49   total_lines_cleared: number;
     50   single_clears: number;
     51   double_clears: number;
     52   triple_clears: number;
     53   tetris_clears: number;
     54   max_combo: number;
     55   score_readings: number[];
     56   score_final: number;
     57   score_increases: number[];
     58   level_readings: number[];
     59   level_final: number;
     60   game_over_reached: boolean;
     61   game_over_text_found: string | null;
     62   restart_available: boolean;
     63   next_piece_visible: boolean;
     64   speed_increased: boolean;
     65   bugs_detected: string[];
     66   rendering_trail_detected?: boolean;
     67 }
     68 
     69 /** Result of the calibration phase. */
     70 export interface CalibrationResult {
     71   renderer: RendererType;
     72   gridDetected: boolean;
     73   gridBounds: GridBounds | null;
     74   cellWidth: number;
     75   cellHeight: number;
     76   controls: Controls;
     77   startMechanism: StartMechanism;
     78   scoreElementSelector: string | null;
     79   backgroundColor: [number, number, number] | null;
     80   consoleErrors: string[];
     81   /** Fraction of grid reads that returned non-null during calibration polling. */
     82   gridConfidence: number;
     83   /** Details about the button that started the game, if any. */
     84   startButton?: {
     85     selector: string;
     86     text: string;
     87     disappeared: boolean;
     88     position: { x: number; y: number };
     89   };
     90 }
     91 
     92 /** Result of an individual test. */
     93 export interface TestResult {
     94   name: string;
     95   pass: boolean;
     96   detail: string;
     97 }
     98 
     99 /** Standard Tetris piece types. */
    100 export type PieceType = "I" | "O" | "T" | "S" | "Z" | "J" | "L" | "unknown";
    101 
    102 /**
    103  * Tetromino definition: cells in a bounding box.
    104  * Each rotation is a list of [row, col] offsets relative to the piece origin.
    105  */
    106 export interface TetrominoDef {
    107   type: PieceType;
    108   /** All rotation states. Each is a list of [row, col] cell offsets. */
    109   rotations: [number, number][][];
    110   /** Bounding box dimensions per rotation: [width, height]. */
    111   dimensions: [number, number][];
    112 }
    113 
    114 /** An event observed during continuous grid scanning. */
    115 export type GridEvent =
    116   | { type: "piece_spawned"; pieceType: PieceType; frame: number }
    117   | { type: "piece_locked"; frame: number; filledDelta: number }
    118   | { type: "line_cleared"; count: number; frame: number }
    119   | { type: "piece_moved"; direction: "left" | "right" | "down"; frame: number }
    120   | { type: "piece_rotated"; frame: number }
    121   | { type: "hard_drop"; frame: number }
    122   | { type: "game_over"; frame: number }
    123   | { type: "grid_read_failed"; frame: number };
    124 
    125 /** Data collected during one continuous observation session. */
    126 export interface GameSession {
    127   started: boolean;
    128   startMechanism: string;
    129   piecesSpawned: number;
    130   piecesLocked: number;
    131   linesCleared: number;
    132   rotationsObserved: number;
    133   movementsObserved: number;
    134   hardDropsObserved: number;
    135   gameOverDetected: boolean;
    136   consoleErrors: string[];
    137   durationSeconds: number;
    138   pieceTypes: Set<string>;
    139   scoreValues: number[];
    140   gridReadSuccess: number;
    141   gridReadFail: number;
    142   frames: number;
    143   events: GridEvent[];
    144   /** Phases that were skipped and why. */
    145   skippedPhases: string[];
    146 }
    147 
    148 /** Gameplay statistics gathered during the play phase. */
    149 export interface GameplayStats {
    150   pieces_placed: number;
    151   lines_cleared: number;
    152   max_score_observed: number;
    153   play_duration_seconds: number;
    154   errors_during_play: number;
    155 }
    156 
    157 /** The full JSON report written at the end. */
    158 export interface BotReport {
    159   implementation: {
    160     renderer: string;
    161     grid_detected: boolean;
    162     grid_bounds: GridBounds | null;
    163     controls: Record<string, string>;
    164     start_mechanism: string;
    165     score_element_found: boolean;
    166     grid_confidence: number;
    167     survey: SurveyData;
    168   };
    169   tests: Array<{ name: string; pass: boolean; detail: string }>;
    170   summary: {
    171     total: number;
    172     passed: number;
    173     failed: number;
    174     skipped: number;
    175     score: number;
    176   };
    177   gameplay: GameplayStats;
    178   competitive_play: CompetitivePlayResult | null;
    179   session: {
    180     frames: number;
    181     events_count: number;
    182     pieces_spawned: number;
    183     pieces_locked: number;
    184     lines_cleared: number;
    185     piece_types_seen: string[];
    186     grid_read_success_rate: number;
    187   };
    188   performance?: {
    189     load_time_ms: number;
    190   };
    191   accessibility?: {
    192     issues: string[];
    193     issue_count: number;
    194     pass: boolean;
    195   };
    196 }
    197 
    198 /** Context passed through calibration, play, and reporting phases. */
    199 export interface BotContext {
    200   page: Page;
    201   calibration: CalibrationResult;
    202   gameplay: GameplayStats;
    203   testResults: TestResult[];
    204 }

Impressum · Datenschutz