From b53c35126e8a243db555d8cc2d0e9be6ad2a3a1d Mon Sep 17 00:00:00 2001 From: Michael Ficocelli Date: Fri, 10 May 2024 04:57:03 -0400 Subject: [PATCH] IPVGO: Provide API for getting game stats per opponent (#1255) Give users access to wins, losses, stat bonuses, and favor gained --- markdown/bitburner.go.analysis.md | 2 ++ markdown/bitburner.go.md | 2 +- markdown/bitburner.md | 1 + markdown/bitburner.simpleopponentstats.md | 20 +++++++++++++ src/Go/Types.ts | 10 +++++++ src/Go/effects/netscriptGoImplementation.ts | 30 +++++++++++++++++-- src/Netscript/RamCostGenerator.ts | 1 + src/NetscriptFunctions/Go.ts | 4 +++ src/ScriptEditor/NetscriptDefinitions.d.ts | 33 +++++++++++++++++++++ 9 files changed, 100 insertions(+), 3 deletions(-) create mode 100644 markdown/bitburner.simpleopponentstats.md diff --git a/markdown/bitburner.go.analysis.md b/markdown/bitburner.go.analysis.md index 51578297b..9edbb690e 100644 --- a/markdown/bitburner.go.analysis.md +++ b/markdown/bitburner.go.analysis.md @@ -17,5 +17,7 @@ analysis: { getLiberties(): number[][]; getControlledEmptyNodes(): string[]; + + getStats(): Partial>; }; ``` diff --git a/markdown/bitburner.go.md b/markdown/bitburner.go.md index a42497d2d..02e57f9e3 100644 --- a/markdown/bitburner.go.md +++ b/markdown/bitburner.go.md @@ -16,7 +16,7 @@ export interface Go | Property | Modifiers | Type | Description | | --- | --- | --- | --- | -| [analysis](./bitburner.go.analysis.md) | | { getValidMoves(): boolean\[\]\[\]; getChains(): (number \| null)\[\]\[\]; getLiberties(): number\[\]\[\]; getControlledEmptyNodes(): string\[\]; } | Tools to analyze the IPvGO subnet. | +| [analysis](./bitburner.go.analysis.md) | | { getValidMoves(): boolean\[\]\[\]; getChains(): (number \| null)\[\]\[\]; getLiberties(): number\[\]\[\]; getControlledEmptyNodes(): string\[\]; getStats(): Partial<Record<[GoOpponent](./bitburner.goopponent.md), [SimpleOpponentStats](./bitburner.simpleopponentstats.md)>>; } | Tools to analyze the IPvGO subnet. | | [cheat](./bitburner.go.cheat.md) | | { getCheatSuccessChance(): number; removeRouter( x: number, y: number, ): Promise<{ type: "move" \| "pass" \| "gameOver"; x: number \| null; y: number \| null; }>; playTwoMoves( x1: number, y1: number, x2: number, y2: number, ): Promise<{ type: "move" \| "pass" \| "gameOver"; x: number \| null; y: number \| null; }>; repairOfflineNode( x: number, y: number, ): Promise<{ type: "move" \| "pass" \| "gameOver"; x: number \| null; y: number \| null; }>; destroyNode( x: number, y: number, ): Promise<{ type: "move" \| "pass" \| "gameOver"; x: number \| null; y: number \| null; }>; } | Illicit and dangerous IPvGO tools. Not for the faint of heart. Requires Bitnode 14.2 to use. | ## Methods diff --git a/markdown/bitburner.md b/markdown/bitburner.md index 5928371a6..52b905955 100644 --- a/markdown/bitburner.md +++ b/markdown/bitburner.md @@ -162,6 +162,7 @@ | [PlayerRequirement](./bitburner.playerrequirement.md) | Structured interface to requirements for joining a faction or company. For fields with numerical value > 0, the player must have at least this value. For fields with numerical value <= 0, the player must have at most this value. For "not", the sub-condition must be failed instead of passed. For "someCondition", at least one sub-condition must be passed. | | [ReactNode](./bitburner.reactnode.md) |

A stand-in for the real React.ReactNode. A [ReactElement](./bitburner.reactelement.md) is rendered dynamically with React. number and string are displayed directly. boolean, null, and undefined are ignored and not rendered. An array of ReactNodes will display all members of that array sequentially.

Use React.createElement to make the ReactElement type, see [creating an element without jsx](https://react.dev/reference/react/createElement#creating-an-element-without-jsx) from the official React documentation.

| | [ScriptArg](./bitburner.scriptarg.md) | | +| [SimpleOpponentStats](./bitburner.simpleopponentstats.md) | | | [SleeveBladeburnerTask](./bitburner.sleevebladeburnertask.md) | | | [SleeveClassTask](./bitburner.sleeveclasstask.md) | | | [SleeveCompanyTask](./bitburner.sleevecompanytask.md) | | diff --git a/markdown/bitburner.simpleopponentstats.md b/markdown/bitburner.simpleopponentstats.md new file mode 100644 index 000000000..252c5d94b --- /dev/null +++ b/markdown/bitburner.simpleopponentstats.md @@ -0,0 +1,20 @@ + + +[Home](./index.md) > [bitburner](./bitburner.md) > [SimpleOpponentStats](./bitburner.simpleopponentstats.md) + +## SimpleOpponentStats type + + +**Signature:** + +```typescript +type SimpleOpponentStats = { + wins: number; + losses: number; + winStreak: number; + highestWinStreak: number; + favor: number; + bonusPercent: number; + bonusDescription: string; +}; +``` diff --git a/src/Go/Types.ts b/src/Go/Types.ts index 0ab0e7217..fdaf0297c 100644 --- a/src/Go/Types.ts +++ b/src/Go/Types.ts @@ -79,3 +79,13 @@ export type OpponentStats = { highestWinStreak: number; favor: number; }; + +export type SimpleOpponentStats = { + wins: number; + losses: number; + winStreak: number; + highestWinStreak: number; + favor: number; + bonusPercent: number; + bonusDescription: string; +}; diff --git a/src/Go/effects/netscriptGoImplementation.ts b/src/Go/effects/netscriptGoImplementation.ts index 4aa3afa61..7f2d41cfa 100644 --- a/src/Go/effects/netscriptGoImplementation.ts +++ b/src/Go/effects/netscriptGoImplementation.ts @@ -1,4 +1,4 @@ -import type { BoardState, Play } from "../Types"; +import { BoardState, Play, SimpleOpponentStats } from "../Types"; import { Player } from "@player"; import { AugmentationName, GoColor, GoOpponent, GoPlayType, GoValidity } from "@enums"; @@ -11,8 +11,10 @@ import { getControlledSpace, simpleBoardFromBoard, } from "../boardAnalysis/boardAnalysis"; -import { getScore, resetWinstreak } from "../boardAnalysis/scoring"; +import { getOpponentStats, getScore, resetWinstreak } from "../boardAnalysis/scoring"; import { WHRNG } from "../../Casino/RNG"; +import { getRecordKeys } from "../../Types/Record"; +import { CalculateEffect, getEffectTypeForFaction } from "./effect"; /** * Check the move based on the current settings @@ -362,6 +364,30 @@ export function resetBoardState( return simpleBoardFromBoard(Go.currentGame.board); } +/** + * Retrieve and clean up stats for each opponent played against + */ +export function getStats() { + const statDetails: Partial> = {}; + for (const opponent of getRecordKeys(Go.stats)) { + const details = getOpponentStats(opponent); + const nodePower = getOpponentStats(opponent).nodePower; + const effectPercent = (CalculateEffect(nodePower, opponent) - 1) * 100; + const effectDescription = getEffectTypeForFaction(opponent); + statDetails[opponent] = { + wins: details.wins, + losses: details.losses, + winStreak: details.winStreak, + highestWinStreak: details.highestWinStreak, + favor: details.favor, + bonusPercent: effectPercent, + bonusDescription: effectDescription, + }; + } + + return statDetails; +} + /** Validate singularity access by throwing an error if the player does not have access. */ export function checkCheatApiAccess(error: (s: string) => void): void { const hasSourceFile = Player.sourceFileLvl(14) > 1; diff --git a/src/Netscript/RamCostGenerator.ts b/src/Netscript/RamCostGenerator.ts index f8e9228c9..e466bc767 100644 --- a/src/Netscript/RamCostGenerator.ts +++ b/src/Netscript/RamCostGenerator.ts @@ -260,6 +260,7 @@ const go = { getChains: 16, getLiberties: 16, getControlledEmptyNodes: 16, + getStats: 0, }, cheat: { getCheatSuccessChance: 1, diff --git a/src/NetscriptFunctions/Go.ts b/src/NetscriptFunctions/Go.ts index b1d6809f6..9a76c7e17 100644 --- a/src/NetscriptFunctions/Go.ts +++ b/src/NetscriptFunctions/Go.ts @@ -18,6 +18,7 @@ import { getGameState, getLiberties, getOpponentNextMove, + getStats, getValidMoves, handlePassTurn, makePlayerMove, @@ -85,6 +86,9 @@ export function NetscriptGo(): InternalAPI { getControlledEmptyNodes: () => () => { return getControlledEmptyNodes(); }, + getStats: () => () => { + return getStats(); + }, }, cheat: { getCheatSuccessChance: (ctx: NetscriptContext) => () => { diff --git a/src/ScriptEditor/NetscriptDefinitions.d.ts b/src/ScriptEditor/NetscriptDefinitions.d.ts index 33346ce78..25821421e 100644 --- a/src/ScriptEditor/NetscriptDefinitions.d.ts +++ b/src/ScriptEditor/NetscriptDefinitions.d.ts @@ -3949,6 +3949,17 @@ type GoOpponent = | "Illuminati" | "????????????"; +/** @public */ +type SimpleOpponentStats = { + wins: number; + losses: number; + winStreak: number; + highestWinStreak: number; + favor: number; + bonusPercent: number; + bonusDescription: string; +}; + /** * IPvGO api * @public @@ -4167,6 +4178,28 @@ export interface Go { * (This is intentionally expensive; you can derive this info from just getBoardState() ) */ getControlledEmptyNodes(): string[]; + + /** + * Displays the game history, captured nodes, and gained bonuses for each opponent you have played against. + * + * The details are keyed by opponent name, in this structure: + * + *
+     * {
+     *   : {
+     *     wins: number,
+     *     losses: number,
+     *     winStreak: number,
+     *     highestWinStreak: number,
+     *     favor: number,
+     *     bonusPercent: number,
+     *     bonusDescription: string,
+     *   }
+     * }
+     * 
+ * + */ + getStats(): Partial>; }; /**