IPVGO: Add support to netscript API for game state, current player, and alternate ways to check/wait on AI turn (#1142)

This commit is contained in:
Michael Ficocelli
2024-03-19 14:07:15 -04:00
committed by GitHub
parent 6aaeb6b59e
commit d81358c80f
22 changed files with 541 additions and 308 deletions
+50 -38
View File
@@ -2,7 +2,6 @@ import type { InternalAPI, NetscriptContext } from "../Netscript/APIWrapper";
import type { Go as NSGo } from "@nsdefs";
import type { Play } from "../Go/Types";
import { GoColor } from "@enums";
import { Go } from "../Go/Go";
import { helpers } from "../Netscript/NetscriptHelpers";
import { simpleBoardFromBoard } from "../Go/boardAnalysis/boardAnalysis";
@@ -15,36 +14,23 @@ import {
checkCheatApiAccess,
getChains,
getControlledEmptyNodes,
getCurrentPlayer,
getGameState,
getLiberties,
getOpponentNextMove,
getValidMoves,
handlePassTurn,
invalidMoveResponse,
makePlayerMove,
resetBoardState,
throwError,
validateMove,
validateTurn,
} from "../Go/effects/netscriptGoImplementation";
import { getEnumHelper } from "../utils/EnumHelper";
const logger = (ctx: NetscriptContext) => (message: string) => helpers.log(ctx, () => message);
const error = (ctx: NetscriptContext) => (message: string) => throwError(ctx.workerScript, message);
/**
* Ensures the given coordinates are valid for the current board size
*/
function validateRowAndColumn(ctx: NetscriptContext, x: number, y: number) {
const boardSize = Go.currentGame.board.length;
if (x < 0 || x >= boardSize) {
throwError(
ctx.workerScript,
`Invalid column number (x = ${x}), column must be a number 0 through ${boardSize - 1}`,
);
}
if (y < 0 || y >= boardSize) {
throwError(ctx.workerScript, `Invalid row number (y = ${y}), row must be a number 0 through ${boardSize - 1}`);
}
}
/**
* Go API implementation
*/
@@ -52,24 +38,29 @@ export function NetscriptGo(): InternalAPI<NSGo> {
return {
makeMove:
(ctx: NetscriptContext) =>
async (_x, _y): Promise<Play> => {
(_x, _y): Promise<Play> => {
const x = helpers.number(ctx, "x", _x);
const y = helpers.number(ctx, "y", _y);
validateRowAndColumn(ctx, x, y);
return makePlayerMove(logger(ctx), x, y);
validateMove(error(ctx), x, y, "makeMove");
return makePlayerMove(logger(ctx), error(ctx), x, y);
},
passTurn: (ctx: NetscriptContext) => async (): Promise<Play> => {
if (Go.currentGame.previousPlayer === GoColor.black) {
helpers.log(ctx, () => `It is not your turn; you cannot pass.`);
helpers.log(ctx, () => `Do you have multiple scripts running, or did you forget to await makeMove() ?`);
return Promise.resolve(invalidMoveResponse);
}
passTurn: (ctx: NetscriptContext) => (): Promise<Play> => {
validateTurn(error(ctx), "passTurn()");
return handlePassTurn(logger(ctx));
},
opponentNextTurn: (ctx: NetscriptContext) => (_logOpponentMove) => {
const logOpponentMove = typeof _logOpponentMove === "boolean" ? _logOpponentMove : true;
return getOpponentNextMove(logOpponentMove, logger(ctx));
},
getBoardState: () => () => {
return simpleBoardFromBoard(Go.currentGame.board);
},
getCurrentPlayer: () => () => {
return getCurrentPlayer();
},
getGameState: () => () => {
return getGameState();
},
getOpponent: () => () => {
return Go.currentGame.ai;
},
@@ -100,44 +91,65 @@ export function NetscriptGo(): InternalAPI<NSGo> {
},
removeRouter:
(ctx: NetscriptContext) =>
async (_x, _y): Promise<Play> => {
(_x, _y): Promise<Play> => {
checkCheatApiAccess(error(ctx));
const x = helpers.number(ctx, "x", _x);
const y = helpers.number(ctx, "y", _y);
validateRowAndColumn(ctx, x, y);
validateMove(error(ctx), x, y, "removeRouter", {
emptyNode: false,
requireNonEmptyNode: true,
repeat: false,
suicide: false,
});
return cheatRemoveRouter(logger(ctx), x, y);
},
playTwoMoves:
(ctx: NetscriptContext) =>
async (_x1, _y1, _x2, _y2): Promise<Play> => {
(_x1, _y1, _x2, _y2): Promise<Play> => {
checkCheatApiAccess(error(ctx));
const x1 = helpers.number(ctx, "x", _x1);
const y1 = helpers.number(ctx, "y", _y1);
validateRowAndColumn(ctx, x1, y1);
validateMove(error(ctx), x1, y1, "playTwoMoves", {
repeat: false,
suicide: false,
});
const x2 = helpers.number(ctx, "x", _x2);
const y2 = helpers.number(ctx, "y", _y2);
validateRowAndColumn(ctx, x2, y2);
validateMove(error(ctx), x2, y2, "playTwoMoves", {
repeat: false,
suicide: false,
});
return cheatPlayTwoMoves(logger(ctx), x1, y1, x2, y2);
},
repairOfflineNode:
(ctx: NetscriptContext) =>
async (_x, _y): Promise<Play> => {
(_x, _y): Promise<Play> => {
checkCheatApiAccess(error(ctx));
const x = helpers.number(ctx, "x", _x);
const y = helpers.number(ctx, "y", _y);
validateRowAndColumn(ctx, x, y);
validateMove(error(ctx), x, y, "repairOfflineNode", {
emptyNode: false,
repeat: false,
onlineNode: false,
requireOfflineNode: true,
suicide: false,
});
return cheatRepairOfflineNode(logger(ctx), x, y);
},
destroyNode:
(ctx: NetscriptContext) =>
async (_x, _y): Promise<Play> => {
(_x, _y): Promise<Play> => {
checkCheatApiAccess(error(ctx));
const x = helpers.number(ctx, "x", _x);
const y = helpers.number(ctx, "y", _y);
validateRowAndColumn(ctx, x, y);
validateMove(error(ctx), x, y, "destroyNode", {
repeat: false,
onlineNode: true,
suicide: false,
});
return cheatDestroyNode(logger(ctx), x, y);
},