dimensions-ai
Version:
A generalized AI Competition framework that allows you to create any competition you want in any language you want with no hassle.
345 lines (344 loc) • 12.8 kB
TypeScript
/// <reference types="node" />
import { DeepPartial } from '../utils/DeepPartial';
import { MatchEngine } from '../MatchEngine';
import { Agent } from '../Agent';
import { Logger } from '../Logger';
import { Design } from '../Design';
import { Tournament } from '../Tournament';
import EngineOptions = MatchEngine.EngineOptions;
import Command = MatchEngine.Command;
import { ChildProcess } from 'child_process';
import { NanoID, Dimension } from '../Dimension';
/**
* An match created using a {@link Design} and a list of Agents. The match can be stopped and resumed with
* {@link stop}, {@link resume}, and state and configurations can be retrieved at any point in time with the
* {@link state} and {@link configs} fields
*
* @see {@link Design} for Design information
* @see {@link Agent} for Agent information
*/
export declare class Match {
design: Design;
/**
* agent meta data regarding files, ids, etc.
*/
agentFiles: Agent.GenerationMetaData;
private dimension;
/**
* When the match was created (called with new)
*/
creationDate: Date;
/**
* When the match finished
*/
finishDate: Date;
/**
* Name of the match
*/
name: string;
/**
* Match ID. It's always a 12 character NanoID
*/
id: NanoID;
/**
* The state field. This can be used to store anything by the user when this `match` is passed to the {@link Design}
* life cycle functions {@link Design.initialize}, {@link Design.update}, and {@link Design.getResults}
*
* This is also used by the {@link CustomDesign} class to store all standard outputted match output for
* matches running using a custom design and passing in {@link Design.OverrideOptions}.
*/
state: any;
/**
* List of the agents currently involved in the match.
* @See {@link Agent} for details on the agents.
*/
agents: Array<Agent>;
/**
* Map from an {@link Agent.ID} ID to the {@link Agent}
*/
idToAgentsMap: Map<Agent.ID, Agent>;
/**
* The current time step of the Match. This time step is independent of any {@link Design} and agents are coordianted
* against this timeStep
*/
timeStep: number;
/**
* The associated {@link MatchEngine} that is running this match and serves as the backend for this match.
*/
matchEngine: MatchEngine;
/**
* The match logger.
* @see {@link Logger} for details on how to use this
*/
log: Logger;
/**
* The results field meant to store any results retrieved with {@link Design.getResults}
* @default `null`
*/
results: any;
/**
* The current match status
*/
matchStatus: Match.Status;
/**
* A mapping from {@link Agent} IDs to the tournament id of the {@link Player} in a tournament that generated the
* {@link Agent}
*/
mapAgentIDtoTournamentID: Map<Agent.ID, Tournament.ID>;
/**
* Match Configurations. See {@link Match.Configs} for configuration options
*/
configs: Match.Configs;
/** Match process used to store the process governing a match running on a custom design */
matchProcess: ChildProcess;
/** The timer set for the match process */
matchProcessTimer: any;
/** Signal to stop at next time step */
private shouldStop;
/** Promise for resuming */
private resumePromise;
/** Resolver for the above promise */
private resumeResolve;
/** Resolver for stop Promise */
private resolveStopPromise;
/** Rejecter for the run promise */
private runReject;
/**
* Path to the replay file for this match
*/
replayFile: string;
/**
* Key used to retrieve the replay file from a storage plugin
*/
replayFileKey: string;
/**
* Non local files that should be removed as they are stored somewhere else. Typically bot files are non local if
* using a backing storage service
*/
private nonLocalFiles;
/**
* Match Constructor
* @param design - The {@link Design} used
* @param agents - List of agents used to create Match.
* @param configs - Configurations that are passed to every run through {@link Design.initialize}, {@link Design.update}, and {@link Design.getResults} functioon in the
* given {@link Design}
*/
constructor(design: Design,
/**
* agent meta data regarding files, ids, etc.
*/
agentFiles: Agent.GenerationMetaData, configs: DeepPartial<Match.Configs>, dimension: Dimension);
/**
* Initializes this match using its configurations and using the {@link Design.initialize} function. This can
* throw error with agent generation, design initialization, or with engine initialization. In engine initialization,
* errors that can be thrown can be {@link AgentCompileError | AgentCompileErrors},
* {@link AgentInstallError | AgentInstallErrors}, etc.
*
*
* @returns a promise that resolves true if initialized correctly
*/
initialize(): Promise<boolean>;
/**
* Retrieves a bot through its key and downloads it to a random generated folder. Returns the new file's path
* @param botkey
* @param file
* @param useCached - if true, storage plugin will avoid redownloading data. If false, storage plugin will always
* redownload data
*/
private retrieveBot;
/**
* Runs this match to completion. Sets this.results to match results and resolves with the match results when done
*/
run(): Promise<any>;
/**
* Handles log files and stores / uploads / deletes them as necessary
*/
private handleLogFiles;
/**
* Step forward the match by one timestep by sending commands individually.
*/
step(commands: Array<Command>): Promise<Match.Status>;
/**
* Next function. Moves match forward by one timestep. Resolves with the match status
* This function should always used to advance forward a match unless a custom design is provided
*
* Gathers commands from agents via the {@link MatchEngine}
*
* Should not be called by user
*/
next(): Promise<Match.Status>;
/**
* Stops the match. For non-custom designs, stops at the next nearest timestep possible. Otherwise attempts to stop
* the match using the {@link MatchEngine} stopCustom function.
*
* Notes:
* - If design uses a PARALLEL match engine, stopping behavior can be a little unpredictable
* - If design uses a SEQUENTIAL match engine, a stop will result in ensuring all agents complete all their actions up
* to a coordinated stopping `timeStep`
*/
stop(): Promise<void>;
/**
* Resume the match if it was in the stopped state
* @returns true if succesfully resumed
*/
resume(): Promise<void>;
/**
* Stop all agents through the match engine and clean up any other files and processes
*
* Used by custom and dimensions based designs
*/
private killAndCleanUp;
/**
* Terminate an {@link Agent}, kill the process. Note, the agent is still stored in the Match, but you can't send or
* receive messages from it anymore
*
* @param agent - id of agent or the Agent object to kill
* @param reason - an optional reason string to provide for logging purposes
*/
kill(agent: Agent.ID | Agent, reason?: string): Promise<void>;
/**
* Retrieve results through delegating the task to {@link Design.getResults}
*/
getResults(): Promise<any>;
/**
* Sends a message to the standard input of all agents in this match
* @param message - the message to send to all agents available
* @returns a promise resolving true/false if it was succesfully sent
*/
sendAll(message: string): Promise<boolean>;
/**
* Functional method for sending a message string to a particular {@link Agent}. Returns a promise that resolves true
* if succesfully sent. Returns false if could not send message, meaning agent was also killed.
* @param message - the string message to send
* @param receiver - receiver of message can be specified by the {@link Agent} or it's {@link Agent.ID} (a number)
*/
send(message: string, receiver: Agent | Agent.ID): Promise<boolean>;
/**
* Throw an {@link FatalError}, {@link MatchError}, or {@link MatchWarn} within the Match. Indicates that the
* {@link Agent} with id agentID caused this error/warning.
*
* Throwing MatchWarn will just log a warning level message and throwing a MatchError will just log it as an error
* level message.
*
* Throwing FatalError will cause the match to automatically be destroyed. This is highly not recommended and it is
* suggested to have some internal logic to handle moments when the match cannot continue.
*
*
* Examples are misuse of an existing command or using incorrect commands or sending too many commands
* @param agentID - the misbehaving agent's ID
* @param error - The error
*/
throw(agentID: Agent.ID, error: Error): Promise<void>;
/**
* Destroys this match and makes sure to remove any leftover processes
*/
destroy(): Promise<void>;
/**
* Generates a 12 character nanoID string for identifying matches
*/
static genMatchID(): string;
getMatchErrorLogDirectory(): string;
}
export declare namespace Match {
/**
* Match Configurations. Has 5 specified fields. All other fields are up to user discretion
*/
interface Configs {
/**
* Name of the match
*/
name: string;
/**
* Logging level for this match.
* @see {@link Logger}
*/
loggingLevel: Logger.LEVEL;
/**
* The engine options to use in this match.
*/
engineOptions: DeepPartial<EngineOptions>;
/**
* Whether to run match in secure mode or not
* @default true
*/
secureMode: boolean;
/**
* Default Agent options to use for all agents in a match. Commonly used for setting resource use boundaries
*/
agentOptions: DeepPartial<Agent.Options>;
/**
* Agent options to override with depending on extension of file
* @default `{}` - an empty object
*/
languageSpecificAgentOptions: Agent.LanguageSpecificOptions;
/**
* Agent options to lastly overridde with depending on agent index
* @default `[]` - empty array meaning no more overrides
*/
agentSpecificOptions: Array<DeepPartial<Agent.Options>>;
/**
* Whether or not to store a replay file if match results indicate a replay file was stored
*
* @default `true`
*/
storeReplay: boolean;
/**
* Used only when a {@link Storage} plugin is used. Indicates the directory to use to store onto the storage.
* (Typically some path in the bucket).
*
* @default `replays`
*/
storeReplayDirectory: string;
/**
* Whether to store error output for each {@link Match}
*
* @default true
*/
storeErrorLogs: boolean;
/**
* Whether to store error and warnings outputted by match from calling match.throw
*
* @default false
*/
storeMatchErrorLogs: boolean;
/**
* Directory to store error logs locally. When a {@link Storage} plugin is used, this indicates the path in the
* bucket to store the log in, and removes the local copy.
*
* @default `errorlogs`
*/
storeErrorDirectory: string;
/**
* Whether to run in detached mode. When in detached mode (true), the match can initialize within dimensions using the {@link Design} but will now
* instead update step by step
*
* @default `false`
*/
detached: boolean;
[key: string]: any;
}
enum Status {
/** Match was created with new but initialize was not called */
UNINITIALIZED = "uninitialized",
/**
* If the match has been initialized and checks have been passed, the match is ready to run using {@link Match.run}
*/
READY = "ready",
/**
* If the match is running at the moment
*/
RUNNING = "running",
/**
* If the match is stopped
*/
STOPPED = "stopped",
/**
* If the match is completed
*/
FINISHED = "finished",
/**
* If fatal error occurs in Match, appears when match stops itself
*/
ERROR = "error"
}
}