goban
Version:
[](https://opensource.org/licenses/Apache-2.0) [](https://deepwiki.com/online-go/goban)
428 lines (427 loc) • 15.7 kB
TypeScript
import { BoardState, BoardConfig } from "./BoardState";
import { MoveTree, MoveTreeJson } from "./MoveTree";
import { ScoreEstimator } from "./ScoreEstimator";
import { GobanBase, GobanEvents } from "../GobanBase";
import { JGOFTimeControl, JGOFNumericPlayerColor, JGOFMove, JGOFPlayerSummary, JGOFIntersection, JGOFSealingIntersection } from "./formats/JGOF";
import { AdHocPackedMove } from "./formats/AdHocFormat";
import { EventEmitter } from "eventemitter3";
import { GameClock, StallingScoreEstimate } from "./protocol";
export declare const AUTOSCORE_TRIALS = 1000;
export declare const AUTOSCORE_TOLERANCE = 0.1;
export type GobanEnginePhase = "play" | "stone removal" | "finished";
export type GobanEngineRules = "chinese" | "aga" | "japanese" | "korean" | "ing" | "nz";
export type GobanEngineSuperKoAlgorithm = "psk" | "csk" | "ssk" | "noresult" | "ing";
export interface PlayerScore {
total: number;
stones: number;
territory: number;
prisoners: number;
scoring_positions: string;
handicap: number;
komi: number;
}
export interface Score {
white: PlayerScore;
black: PlayerScore;
}
export interface GobanEnginePlayerEntry {
id: number;
username: string;
country?: string;
rank?: number;
/** The accepted stones for the stone removal phase that the player has accepted */
accepted_stones?: string;
/** Whether or not the player has accepted scoring with strict seki mode on or not */
accepted_strict_seki_mode?: boolean;
/** XXX: The server is using these, the client may or may not be, we need to normalize this */
name?: string;
pro?: boolean;
}
export type GobanMovesArray = Array<AdHocPackedMove> | Array<JGOFMove>;
export interface GobanEngineConfig extends BoardConfig {
game_id?: number | string;
review_id?: number;
game_name?: string;
player_id?: number;
tournament_id?: number;
ladder_id?: number;
group_ids?: Array<number>;
initial_player?: PlayerColor;
width?: number;
height?: number;
disable_analysis?: boolean;
handicap_rank_difference?: number;
handicap?: number;
komi?: number;
rules?: GobanEngineRules;
phase?: GobanEnginePhase;
initial_state?: GobanEngineInitialState;
marks?: {
[mark: string]: string;
};
latencies?: {
[player_id: string]: number;
};
player_pool?: {
[id: number]: GobanEnginePlayerEntry;
};
players?: {
black: GobanEnginePlayerEntry;
white: GobanEnginePlayerEntry;
};
rengo?: boolean;
rengo_teams?: {
black: Array<GobanEnginePlayerEntry>;
white: Array<GobanEnginePlayerEntry>;
};
rengo_casual_mode?: boolean;
reviews?: {
[review_id: number]: GobanEnginePlayerEntry;
};
is_game_record?: boolean;
time_control?: JGOFTimeControl;
moves?: GobanMovesArray;
move_tree?: MoveTreeJson;
ranked?: boolean;
original_disable_analysis?: boolean;
original_sgf?: string;
free_handicap_placement?: boolean;
score?: Score;
outcome?: string;
winner?: number | "black" | "white" | "tie";
start_time?: number;
end_time?: number;
game_date?: string;
allow_self_capture?: boolean;
automatic_stone_removal?: boolean;
allow_ko?: boolean;
allow_superko?: boolean;
score_territory?: boolean;
score_territory_in_seki?: boolean;
strict_seki_mode?: boolean;
score_stones?: boolean;
score_passes?: boolean;
score_prisoners?: boolean;
score_handicap?: boolean;
white_must_pass_last?: boolean;
aga_handicap_scoring?: boolean;
opponent_plays_first_after_resume?: boolean;
superko_algorithm?: GobanEngineSuperKoAlgorithm;
stalling_score_estimate?: StallingScoreEstimate;
clock?: GameClock;
/** When loading initial state or moves, by default GobanEngine will try and
* handle bad data by just resorting to 'edit placing' moves. If this is
* true, then those errors are thrown instead.
*/
throw_all_errors?: boolean;
/** Removed stones in stone removal phase
* Passing an array of JGOFMove objects is preferred, the string
* format exists for historical backwards compatibility. It is an
* encoded move string, e.g. "aa" for A19
*/
removed?: string | JGOFMove[];
/** Intersections that need to be sealed before scoring should happen */
needs_sealing?: JGOFSealingIntersection[];
ogs?: {
black_stones: string;
black_territory: string;
black_seki_eyes: string;
black_dead_stones: string;
white_stones: string;
white_territory: string;
white_seki_eyes: string;
white_dead_stones: string;
};
time_per_move?: number;
errors?: Array<{
error: string;
stack: any;
}>;
/** Deprecated, I don't think we need this anymore, but need to be sure */
ogs_import?: boolean;
ladder?: number;
black_player_id?: number;
white_player_id?: number;
}
export interface GobanEngineInitialState {
black?: string;
white?: string;
}
/** Reviews are constructed by a stream of modifications messages,
* this interface describes the format of those modification messages.
* A message can contain any number of the fields listed. */
export interface ReviewMessage {
/** The review ID. This is used when sending from the client to the server,
* but is not sent by the server back to the client (as the id is encoded
* in the message event name) */
"review_id"?: number;
/** timestamp (ms) */
"ts"?: number;
/** from (move number) */
"f"?: number;
/** Moves made */
"m"?: string;
/** official move [reviewing live game] */
"om"?: [number, number, number];
/** official undo [reviewing live game] */
"undo"?: boolean;
/** text note for the current node */
"t"?: string;
/** text append to the current node */
"t+"?: string;
/** Marks made */
"k"?: {
[mark: string]: string;
};
/** pen point */
"pp"?: [number, number];
/** pen color / pen start */
"pen"?: string;
/** Chat message */
"chat"?: {
chat_id: string;
player_id: number;
channel: string;
date: number;
/** Turn number */
from: number;
/** this might just be "string", i'm not entirely sure */
moves: AdHocPackedMove | string;
};
/** Remove's the given chat by id */
"remove-chat"?: string;
/** Clears the pen drawings on the node */
"clearpen"?: boolean;
/** Delete */
"delete"?: number;
/** Sets the owner of the review */
"owner"?: number | {
id: number;
username: string;
};
/** Initial gamedata to review */
"gamedata"?: GobanEngineConfig;
/** Sets the controller of the review */
"controller"?: number | {
id: number;
username: string;
};
/** Updated information about the players, such as name etc. */
"player_update"?: JGOFPlayerSummary;
}
export interface PuzzleConfig extends BoardConfig {
mode?: string;
name?: string;
puzzle_type?: string;
initial_state?: GobanEngineInitialState;
marks?: {
[mark: string]: string;
};
puzzle_autoplace_delay?: number;
puzzle_opponent_move_mode?: PuzzleOpponentMoveMode;
puzzle_player_move_mode?: PuzzlePlayerMoveMode;
puzzle_rank?: number;
puzzle_description?: string;
puzzle_collection?: number;
initial_player?: PlayerColor;
move_tree?: MoveTreeJson;
}
export type PuzzlePlayerMoveMode = "free" | "fixed";
export type PuzzleOpponentMoveMode = "manual" | "automatic";
export type PuzzlePlacementSetting = {
mode: "play";
} | {
mode: "setup";
color: JGOFNumericPlayerColor;
} | {
mode: "place";
color: 0;
};
export type PlayerColor = "black" | "white";
export declare class GobanEngine extends BoardState {
throw_all_errors?: boolean;
handicap_rank_difference?: number;
handicap: number;
initial_state: GobanEngineInitialState;
komi: number;
move_tree: MoveTree;
move_tree_layout_vector: Array<number>;
move_tree_layout_hash: {
[coords: string]: MoveTree;
};
move_tree_layout_dirty: boolean;
readonly name: string;
player_pool: {
[id: number]: GobanEnginePlayerEntry;
};
latencies?: {
[player_id: string]: number;
};
players: {
black: GobanEnginePlayerEntry;
white: GobanEnginePlayerEntry;
};
puzzle_collection: number;
puzzle_description: string;
puzzle_opponent_move_mode: PuzzleOpponentMoveMode;
puzzle_player_move_mode: PuzzlePlayerMoveMode;
puzzle_rank: number;
puzzle_type: string;
readonly config: GobanEngineConfig;
readonly disable_analysis: boolean;
time_control: JGOFTimeControl;
game_id: number;
review_id?: number;
decoded_moves: Array<JGOFMove>;
automatic_stone_removal: boolean;
group_ids?: Array<number>;
rengo?: boolean;
rengo_teams?: {
[colour: string]: Array<GobanEnginePlayerEntry>;
};
rengo_casual_mode: boolean;
stalling_score_estimate?: StallingScoreEstimate;
readonly is_game_record: boolean;
private _phase;
get phase(): GobanEnginePhase;
set phase(phase: GobanEnginePhase);
private _cur_move;
get cur_move(): MoveTree;
set cur_move(cur_move: MoveTree);
private _cur_review_move;
get cur_review_move(): MoveTree | undefined;
set cur_review_move(cur_review_move: MoveTree | undefined);
private _last_official_move;
get last_official_move(): MoveTree;
set last_official_move(last_official_move: MoveTree);
private _strict_seki_mode;
get strict_seki_mode(): boolean;
set strict_seki_mode(strict_seki_mode: boolean);
private _rules;
get rules(): GobanEngineRules;
set rules(rules: GobanEngineRules);
private _winner?;
get winner(): number | "black" | "white" | undefined;
set winner(winner: number | "black" | "white" | undefined);
private _undo_requested?;
get undo_requested(): number | undefined;
set undo_requested(undo_requested: number | undefined);
private _outcome;
get outcome(): string;
set outcome(outcome: string);
private aga_handicap_scoring;
private allow_ko;
private allow_self_capture;
private allow_superko;
private superko_algorithm;
private dontStoreBoardHistory;
free_handicap_placement: boolean;
private loading_sgf;
private move_before_jump?;
needs_sealing?: Array<JGOFSealingIntersection>;
score_prisoners: boolean;
score_stones: boolean;
score_handicap: boolean;
score_territory: boolean;
score_territory_in_seki: boolean;
territory_included_in_sgf: boolean;
constructor(config: GobanEngineConfig, goban_callback?: GobanBase, dontStoreBoardHistory?: boolean);
/**
* Decodes any of the various ways we express moves that we've accumulated over the years into
* a unified `JGOFMove[]`.
*/
decodeMoves(move_obj: string | AdHocPackedMove | AdHocPackedMove[] | JGOFMove | JGOFMove[] | [object] | undefined): JGOFMove[];
encodeMoves(lst: JGOFMove[]): string;
encodeMove(lst: JGOFMove): string;
/**
* Decodes a move string like `"A11"` into a move object like `{x: 0, y: 10}`. Also
* handles the special cases like `".."` and "pass" which map to `{x: -1, y: -1}`.
*/
decodePrettyCoordinates(coordinates: string): JGOFMove;
/** Encodes an x,y pair or a move object like {x: 0, y: 0} into a move string like "A1" */
prettyCoordinates(x: JGOFMove): string;
prettyCoordinates(x: number, y: number): string;
private getState;
private setState;
currentPositionId(): string;
followPath(from_turn: number, moves: AdHocPackedMove | string, cb?: (x: number, y: number, edited: boolean, color: number) => void): Array<MoveTree>;
updatePlayers(player_update: JGOFPlayerSummary): void;
/** Returns true if there was a previous to show */
showPrevious(): boolean;
/** Returns true if there was a next to show */
showNext(): boolean;
/** Returns true if there was a next to show */
showNextTrunk(): boolean;
jumpTo(node?: MoveTree | null): void;
jumpToLastOfficialMove(): void;
/** Saves our current move as our last official move */
setLastOfficialMove(): void;
/** returns true if our current move is our last official move */
isLastOfficialMove(): boolean;
/** Returns a move string from the given official move number (aka branch point) */
getMoveDiff(): {
from: number;
moves: string;
};
setAsCurrentReviewMove(): void;
deleteCurMove(): void;
gameCanBeCancelled(): boolean;
jumpToOfficialMoveNumber(move_number: number): void;
private opponent;
private captureGroup;
isParticipant(player_id: number): boolean;
isActivePlayer(player_id: number): boolean;
playerToMoveOnOfficialBranch(): number;
playerToMove(): number;
playerNotToMove(): number;
otherPlayer(): JGOFNumericPlayerColor;
playerColor(player_id?: number): "black" | "white" | "invalid";
colorToMove(): "black" | "white";
colorNotToMove(): "black" | "white";
playerByColor(color: PlayerColor | JGOFNumericPlayerColor): JGOFNumericPlayerColor;
/** Returns the number of stones removed. If you want the coordinates of
* the stones removed, pass in a removed_stones array to append the moves
* to. */
place(x: number, y: number, checkForKo?: boolean, errorOnSuperKo?: boolean, dontCheckForSuperKo?: boolean, dontCheckForSelfCapture?: boolean, isTrunkMove?: boolean, removed_stones?: Array<JGOFIntersection>): number;
isBoardRepeating(superko_rule: GobanEngineSuperKoAlgorithm): boolean;
editPlace(x: number, y: number, color: JGOFNumericPlayerColor, isTrunkMove?: boolean): void;
initialStatePlace(x: number, y: number, color: JGOFNumericPlayerColor, dont_record_placement?: boolean): void;
resetMoveTree(): void;
computeInitialStateForForkedGame(): {
black: string;
white: string;
};
setNeedsSealing(x: number, y: number, needs_sealing?: boolean): void;
getStoneRemovalString(): string;
getMoveNumber(): number;
getCurrentMoveNumber(): number;
/**
* Computes the score of the current board state.
*
* If only_prisoners is true, we return the same data structure for convenience, but only
* the prisoners will be counted, other sources of points will be zero.
*/
computeScore(only_prisoners?: boolean): Score;
handicapMovesLeft(): number;
/**
* This function migrates old config's to whatever our current standard is
* for configs.
*/
private static migrateConfig;
/**
* This function fills in default values for any missing fields in the
* config.
*/
static fillDefaults(game_obj: GobanEngineConfig): GobanEngineConfig;
static clearRuleSettings(game_obj: GobanEngineConfig): GobanEngineConfig;
private parseSGF;
estimateScore(trials: number, tolerance: number, prefer_remote?: boolean, should_autoscore?: boolean): ScoreEstimator;
getMoveByLocation(x: number, y: number, include_forward_search: boolean): MoveTree | null;
exportAsPuzzle(): PuzzleConfig;
getBlackPrisoners(): number;
getWhitePrisoners(): number;
getHandicapPointAdjustmentForWhite(): number;
parentEventEmitter?: EventEmitter<GobanEvents>;
emit<K extends keyof GobanEvents>(event: K, ...args: EventEmitter.EventArgs<GobanEvents, K>): boolean;
setRemoved(x: number, y: number, removed: boolean, emit_stone_removal_updated?: boolean): void;
}