IPVGO: Support playing manually as white against your scripts using the No AI type board (#1296)

This commit is contained in:
Michael Ficocelli
2024-06-02 20:41:31 -04:00
committed by GitHub
parent f40d4f8e92
commit a28bb4bd99
7 changed files with 80 additions and 24 deletions
+22 -2
View File
@@ -1,6 +1,6 @@
import type { Board, BoardState, Neighbor, PointState, SimpleBoard } from "../Types";
import type { Board, BoardState, Neighbor, Play, PointState, SimpleBoard } from "../Types";
import { GoValidity, GoOpponent, GoColor } from "@enums";
import { GoValidity, GoOpponent, GoColor, GoPlayType } from "@enums";
import { Go } from "../Go";
import {
findAdjacentPointsInChain,
@@ -655,3 +655,23 @@ export function getPreviousMove(): [number, number] | null {
return null;
}
/**
* Gets the last move, if it was made by the specified color and is present
*/
export function getPreviousMoveDetails(): Play {
const priorMove = getPreviousMove();
if (priorMove) {
return {
type: GoPlayType.move,
x: priorMove[0],
y: priorMove[1],
};
}
return {
type: !priorMove && Go.currentGame?.passCount ? GoPlayType.pass : GoPlayType.gameOver,
x: null,
y: null,
};
}
+36 -9
View File
@@ -1,7 +1,7 @@
import type { Board, BoardState, EyeMove, Move, MoveOptions, Play, PointState } from "../Types";
import { Player } from "@player";
import { AugmentationName, GoOpponent, GoColor, GoPlayType } from "@enums";
import { AugmentationName, GoColor, GoOpponent, GoPlayType } from "@enums";
import { opponentDetails } from "../Constants";
import { findNeighbors, isNotNullish, makeMove, passTurn } from "../boardState/boardState";
import {
@@ -15,22 +15,35 @@ import {
getAllEyesByChainId,
getAllNeighboringChains,
getAllValidMoves,
getPreviousMoveDetails,
} from "./boardAnalysis";
import { findDisputedTerritory } from "./controlledTerritory";
import { findAnyMatchedPatterns } from "./patternMatching";
import { WHRNG } from "../../Casino/RNG";
import { Go, GoEvents } from "../Go";
let currentAITurn: Promise<Play> | null = null;
let isAiThinking: boolean = false;
let currentTurnResolver: (() => void) | null = null;
/**
* Retrieves a move from the current faction in response to the player's move
*/
export function makeAIMove(boardState: BoardState): Promise<Play> {
// If AI is already taking their turn, return the existing turn.
if (currentAITurn) return currentAITurn;
currentAITurn = Go.nextTurn = getMove(boardState, GoColor.white, Go.currentGame.ai)
.then(async (play): Promise<Play> => {
if (isAiThinking) {
return Go.nextTurn;
}
isAiThinking = true;
// If the AI is disabled, simply make a promise to be resolved once the player makes a move as white
if (boardState.ai === GoOpponent.none) {
GoEvents.emit();
// Update currentTurnResolver to call Go.nextTurn's resolve function with the last played move's details
Go.nextTurn = new Promise((resolve) => (currentTurnResolver = () => resolve(getPreviousMoveDetails())));
}
// If an AI is in use, find the faction's move in response, and resolve the Go.nextTurn promise once it is found and played.
else {
Go.nextTurn = getMove(boardState, GoColor.white, Go.currentGame.ai).then(async (play): Promise<Play> => {
if (boardState !== Go.currentGame) return play; //Stale game
// Handle AI passing
@@ -54,15 +67,29 @@ export function makeAIMove(boardState: BoardState): Promise<Play> {
}
return play;
})
.finally(() => {
currentAITurn = null;
GoEvents.emit();
});
}
// Once the AI moves (or the player playing as white with No AI moves),
// clear the isAiThinking semaphore and update the board UI.
Go.nextTurn = Go.nextTurn.finally(() => {
isAiThinking = false;
GoEvents.emit();
});
return Go.nextTurn;
}
/**
* Resolves the current turn.
* This is used for players manually playing against their script on the no-ai board.
*/
export function resolveCurrentTurn() {
// Call the resolve function on Go.nextTurn, if it exists
currentTurnResolver?.();
currentTurnResolver = null;
}
/*
Basic GO AIs, each with some personality and weaknesses