/** Public game I/O is pixels plus neutral controls. Metadata/solutions remain author-only. */ export type Button=1|2|3|4|5|6; export interface GameAction {button:Button;x?:number;y?:number} export interface PixelObservation {pixels:number[][];actions:Button[];level:number;status:'playing'|'won'} export interface EpisodeInit {state:S;witness:GameAction[]} export interface Environment { id:string; /** Private author metadata; NEVER rendered or given to a blind solver. */ name:string;family:string;version:string;levels:number; mechanics:string[];stateVariables:string[];novelty:string; init(level:number,seed:number):EpisodeInit; observe(state:S):PixelObservation; step(state:S,action:GameAction):S; solved(state:S):boolean; } export function clone(v:T):T{return structuredClone(v)} export function random(seed:number){let a=seed>>>0;return()=>{a+=0x6d2b79f5;let t=a;t=Math.imul(t^t>>>15,t|1);t^=t+Math.imul(t^t>>>7,t|61);return((t^t>>>14)>>>0)/4294967296}} export function grid(w:number,h:number,fill=0){return Array.from({length:h},()=>Array(w).fill(fill))} export function action(button:Button,x?:number,y?:number):GameAction{return{x,y,button}}