Skip to content

Commit bee59eb

Browse files
committed
IPVGO: Add support for highlighting nodes and adding small text
1 parent 6530b43 commit bee59eb

File tree

10 files changed

+174
-25
lines changed

10 files changed

+174
-25
lines changed

src/Go/Go.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,17 @@ import { getNewBoardState } from "./boardState/boardState";
77
import { EventEmitter } from "../utils/EventEmitter";
88
import { newOpponentStats } from "./Constants";
99

10+
export const getEmptyHighlightedPoints = (size: number) => {
11+
return Array.from({ length: size }, () => Array.from({ length: size }, () => null));
12+
};
13+
1014
export class GoObject {
1115
// Todo: Make previous game a slimmer interface
1216
previousGame: BoardState | null = null;
1317
currentGame: BoardState = getNewBoardState(7);
1418
stats: PartialRecord<GoOpponent, OpponentStats> = {};
1519
storedCycles: number = 0;
20+
highlightedPoints: (PointHighlight | null)[][] = getEmptyHighlightedPoints(7);
1621

1722
prestigeAugmentation() {
1823
for (const opponent of getRecordKeys(Go.stats)) {
@@ -41,3 +46,8 @@ export const Go = new GoObject();
4146

4247
/** Event emitter to allow the UI to subscribe to Go gameplay updates in order to trigger rerenders properly */
4348
export const GoEvents = new EventEmitter();
49+
50+
export type PointHighlight = {
51+
color: string;
52+
text: string;
53+
};

src/Go/boardState/boardState.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
} from "../boardAnalysis/boardAnalysis";
1515
import { endGoGame } from "../boardAnalysis/scoring";
1616
import { addObstacles, resetCoordinates, rotate90Degrees } from "./offlineNodes";
17+
import { clearAllPointHighlights } from "../effects/netscriptGoImplementation";
1718

1819
/** Generates a new BoardState object with the given opponent and size. Optionally use an existing board. */
1920
export function getNewBoardState(
@@ -122,6 +123,7 @@ export function makeMove(boardState: BoardState, x: number, y: number, player: G
122123

123124
// Add move to board history
124125
boardState.previousBoards.unshift(boardStringFromBoard(boardState.board));
126+
clearAllPointHighlights();
125127

126128
point.color = player;
127129
boardState.previousPlayer = player;
@@ -139,6 +141,8 @@ export function passTurn(boardState: BoardState, player: GoColor, allowEndGame =
139141
if (boardState.previousPlayer === null || boardState.previousPlayer === player) {
140142
return;
141143
}
144+
clearAllPointHighlights();
145+
142146
boardState.previousPlayer = boardState.previousPlayer === GoColor.black ? GoColor.white : GoColor.black;
143147
boardState.passCount++;
144148

src/Go/boardState/goStyles.ts

Lines changed: 52 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,18 @@ type Point =
1010
| "filledPoint"
1111
| "emptyPoint"
1212
| "broken"
13+
| "cyberStyle"
1314
| "tradStone"
1415
| "priorStoneTrad";
15-
type Structure = "coordinates" | "liberty" | "northLiberty" | "eastLiberty" | "westLiberty" | "southLiberty";
16-
type Highlight = "hover" | "valid" | "priorPoint";
16+
type Structure =
17+
| "coordinates"
18+
| "highlightText"
19+
| "liberty"
20+
| "northLiberty"
21+
| "eastLiberty"
22+
| "westLiberty"
23+
| "southLiberty";
24+
type Highlight = "hover" | "valid" | "priorPoint" | "hack" | "hp" | "money" | "int" | "cha";
1725

1826
const fadeLoop = keyframes`
1927
0% {
@@ -29,31 +37,56 @@ export const pointStyle = makeStyles<unknown, Size | Point | Structure | Highlig
2937
hover: {},
3038
valid: {},
3139
priorPoint: {},
40+
cyberStyle: {},
41+
highlightText: {},
42+
hack: {},
43+
hp: {},
44+
money: {},
45+
int: {},
46+
cha: {},
3247
point: {
3348
position: "relative",
3449
height: "100%",
3550
width: "100%",
3651

37-
[`&.${classes.hover}.${classes.valid}:hover .${classes.innerPoint}`]: {
52+
[`&.${classes.hover}.${classes.valid}.${classes.cyberStyle}:hover .${classes.innerPoint}`]: {
3853
outlineColor: theme.colors.white,
3954
},
40-
[`&.${classes.hover}.${classes.priorPoint} .${classes.innerPoint}`]: {
55+
[`&.${classes.hover}.${classes.cyberStyle}.${classes.priorPoint} .${classes.innerPoint}`]: {
4156
outlineColor: theme.colors.white,
4257
},
43-
[`&.${classes.hover}.${classes.priorPoint} .${classes.priorStoneTrad}.${classes.blackPoint}`]: {
44-
outlineColor: theme.colors.white,
45-
display: "block",
46-
},
47-
[`&.${classes.hover}.${classes.priorPoint} .${classes.priorStoneTrad}.${classes.whitePoint}`]: {
48-
outlineColor: theme.colors.black,
49-
display: "block",
50-
},
58+
[`&.${classes.hover}.${classes.cyberStyle}.${classes.priorPoint} .${classes.priorStoneTrad}.${classes.blackPoint}`]:
59+
{
60+
outlineColor: theme.colors.white,
61+
display: "block",
62+
},
63+
[`&.${classes.hover}.${classes.cyberStyle}.${classes.priorPoint} .${classes.priorStoneTrad}.${classes.whitePoint}`]:
64+
{
65+
outlineColor: theme.colors.black,
66+
display: "block",
67+
},
5168
[`&.${classes.hover}:hover .${classes.coordinates}`]: {
5269
display: "block",
5370
},
5471
[`&:hover .${classes.broken}`]: {
5572
opacity: "0.4",
5673
},
74+
75+
[`&.${classes.hack} .${classes.innerPoint}`]: {
76+
outlineColor: theme.colors.hack,
77+
},
78+
[`&.${classes.hp} .${classes.innerPoint}`]: {
79+
outlineColor: theme.colors.hp,
80+
},
81+
[`&.${classes.money} .${classes.innerPoint}`]: {
82+
outlineColor: theme.colors.money,
83+
},
84+
[`&.${classes.int} .${classes.innerPoint}`]: {
85+
outlineColor: theme.colors.int,
86+
},
87+
[`&.${classes.cha} .${classes.innerPoint}`]: {
88+
outlineColor: theme.colors.cha,
89+
},
5790
},
5891
broken: {
5992
backgroundImage: `repeating-radial-gradient(circle at 17% 32%, ${theme.colors.white}, black 0.00085px)`,
@@ -82,7 +115,10 @@ export const pointStyle = makeStyles<unknown, Size | Point | Structure | Highlig
82115
},
83116
traditional: {
84117
[`& .${classes.innerPoint}`]: {
85-
display: "none",
118+
outlineColor: "transparent",
119+
[`& .${classes.emptyPoint}`]: {
120+
display: "none",
121+
},
86122
},
87123
[`& .${classes.broken}`]: {
88124
backgroundImage: "none",
@@ -379,6 +415,9 @@ export const pointStyle = makeStyles<unknown, Size | Point | Structure | Highlig
379415
left: "8%",
380416
zIndex: "10",
381417
userSelect: "none",
418+
[`&.${classes.highlightText}`]: {
419+
display: "block",
420+
},
382421
},
383422
priorStoneTrad: {
384423
display: "none",

src/Go/effects/netscriptGoImplementation.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { Board, BoardState, OpponentStats, Play, SimpleBoard, SimpleOpponentStat
22

33
import { Player } from "@player";
44
import { AugmentationName, GoColor, GoOpponent, GoPlayType, GoValidity } from "@enums";
5-
import { Go } from "../Go";
5+
import { getEmptyHighlightedPoints, Go, GoEvents } from "../Go";
66
import {
77
getNewBoardState,
88
getNewBoardStateFromSimpleBoard,
@@ -344,6 +344,7 @@ export function resetBoardState(
344344

345345
resetAI();
346346
Go.currentGame = getNewBoardState(boardSize, opponent, true);
347+
clearAllPointHighlights();
347348
handleNextTurn(Go.currentGame).catch((error) => exceptionAlert(error));
348349
logger(`New game started: ${opponent}, ${boardSize}x${boardSize}`);
349350
return simpleBoardFromBoard(Go.currentGame.board);
@@ -426,6 +427,21 @@ export function validateBoardState(
426427
}
427428
}
428429

430+
export function addPointHighlight(x: number, y: number, color: string, text: string) {
431+
Go.highlightedPoints[x][y] = { color, text };
432+
GoEvents.emit();
433+
}
434+
435+
export function clearPointHighlight(x: number, y: number) {
436+
Go.highlightedPoints[x][y] = { color: "", text: "" };
437+
GoEvents.emit();
438+
}
439+
440+
export function clearAllPointHighlights() {
441+
Go.highlightedPoints = getEmptyHighlightedPoints(Go.currentGame.board.length);
442+
GoEvents.emit();
443+
}
444+
429445
/**
430446
* Check that the given boardState is a valid SimpleBoard, and return it if it is.
431447
*/

src/Go/ui/GoGameboard.tsx

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,23 @@ import { GoOpponent, GoColor } from "@enums";
77
import { getSizeClass, GoPoint } from "./GoPoint";
88
import { boardStyles } from "../boardState/goStyles";
99
import { getAllValidMoves, getControlledSpace } from "../boardAnalysis/boardAnalysis";
10+
import { PointHighlight } from "../Go";
1011

1112
interface GoGameboardProps {
1213
boardState: BoardState;
1314
traditional: boolean;
1415
clickHandler: (x: number, y: number) => unknown;
1516
hover: boolean;
17+
highlightedPoints?: (PointHighlight | null)[][];
1618
}
1719

18-
export function GoGameboard({ boardState, traditional, clickHandler, hover }: GoGameboardProps): React.ReactElement {
20+
export function GoGameboard({
21+
boardState,
22+
traditional,
23+
clickHandler,
24+
hover,
25+
highlightedPoints,
26+
}: GoGameboardProps): React.ReactElement {
1927
const currentPlayer =
2028
boardState.ai !== GoOpponent.none || boardState.previousPlayer === GoColor.white ? GoColor.black : GoColor.white;
2129

@@ -52,6 +60,7 @@ export function GoGameboard({ boardState, traditional, clickHandler, hover }: Go
5260
hover={hover}
5361
valid={pointIsValid(xIndex, yIndex)}
5462
emptyPointOwner={ownedEmptyNodes[xIndex]?.[yIndex]}
63+
pointHighlight={highlightedPoints?.[xIndex]?.[yIndex]}
5564
/>
5665
</Grid>
5766
);

src/Go/ui/GoGameboardWrapper.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import { CorruptableText } from "../../ui/React/CorruptableText";
2121
import { handleNextTurn, resetAI } from "../boardAnalysis/goAI";
2222
import { GoScoreExplanation } from "./GoScoreExplanation";
2323
import { exceptionAlert } from "../../utils/helpers/exceptionAlert";
24+
import { clearAllPointHighlights } from "../effects/netscriptGoImplementation";
2425

2526
interface GoGameboardWrapperProps {
2627
showInstructions: () => void;
@@ -135,6 +136,7 @@ export function GoGameboardWrapper({ showInstructions }: GoGameboardWrapperProps
135136

136137
resetAI();
137138
Go.currentGame = getNewBoardState(newBoardSize, newOpponent, true);
139+
clearAllPointHighlights();
138140
handleNextTurn(Go.currentGame).catch((error) => exceptionAlert(error));
139141
}
140142

@@ -223,6 +225,7 @@ export function GoGameboardWrapper({ showInstructions }: GoGameboardWrapperProps
223225
traditional={traditional}
224226
clickHandler={clickHandler}
225227
hover={!showPriorMove}
228+
highlightedPoints={Go.highlightedPoints}
226229
/>
227230
</div>
228231
<Box className={classes.inlineFlexBox}>

src/Go/ui/GoPoint.tsx

Lines changed: 39 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { columnIndexes } from "../Constants";
77
import { findNeighbors } from "../boardState/boardState";
88
import { boardStyles, pointStyle } from "../boardState/goStyles";
99
import { findAdjacentLibertiesAndAlliesForPoint, getColorOnBoardString } from "../boardAnalysis/boardAnalysis";
10+
import { PointHighlight } from "../Go";
1011

1112
interface GoPointProps {
1213
state: BoardState;
@@ -15,11 +16,29 @@ interface GoPointProps {
1516
traditional: boolean;
1617
hover: boolean;
1718
valid: boolean;
18-
emptyPointOwner: GoColor;
19+
emptyPointOwner?: GoColor;
20+
pointHighlight?: PointHighlight | null;
1921
}
2022

21-
export function GoPoint({ state, x, y, traditional, hover, valid, emptyPointOwner }: GoPointProps): React.ReactElement {
23+
export function GoPoint({
24+
state,
25+
x,
26+
y,
27+
traditional,
28+
hover,
29+
valid,
30+
emptyPointOwner,
31+
pointHighlight,
32+
}: GoPointProps): React.ReactElement {
2233
const { classes } = pointStyle({});
34+
const colorClasses = {
35+
hack: classes.hack,
36+
hp: classes.hp,
37+
money: classes.money,
38+
int: classes.int,
39+
cha: classes.cha,
40+
none: "none",
41+
};
2342

2443
const currentPoint = state.board[x]?.[y];
2544
const player = currentPoint?.color;
@@ -51,9 +70,15 @@ export function GoPoint({ state, x, y, traditional, hover, valid, emptyPointOwne
5170
? classes.libertyBlack
5271
: "";
5372

54-
const mainClassName = `${classes.point} ${sizeClass} ${traditional ? classes.traditional : ""} ${
73+
const highlightClass: string = pointHighlight?.color
74+
? colorClasses[pointHighlight.color as keyof typeof colorClasses] ?? ""
75+
: "";
76+
const rawColorStyle = !highlightClass && pointHighlight?.color ? `${pointHighlight.color}` : "";
77+
const highlightText = pointHighlight?.text ?? "";
78+
79+
const mainClassName = `${classes.point} ${sizeClass} ${traditional ? classes.traditional : classes.cyberStyle} ${
5580
hover ? classes.hover : ""
56-
} ${valid ? classes.valid : ""} ${isPriorMove ? classes.priorPoint : ""}
81+
} ${valid ? classes.valid : ""} ${isPriorMove ? classes.priorPoint : ""} ${highlightClass}
5782
${isInAtari ? classes.fadeLoopAnimation : ""}`;
5883

5984
return (
@@ -64,18 +89,22 @@ export function GoPoint({ state, x, y, traditional, hover, valid, emptyPointOwne
6489
<div className={hasEastLiberty ? `${classes.eastLiberty} ${colorLiberty}` : classes.liberty}></div>
6590
<div className={hasSouthLiberty ? `${classes.southLiberty} ${colorLiberty}` : classes.liberty}></div>
6691
<div className={hasWestLiberty ? `${classes.westLiberty} ${colorLiberty}` : classes.liberty}></div>
67-
<div className={`${classes.innerPoint} `}>
92+
<div className={`${classes.innerPoint} `} style={{ outlineColor: rawColorStyle }}>
6893
<div
6994
className={`${pointClass} ${player !== GoColor.empty ? classes.filledPoint : emptyPointColorClass}`}
7095
></div>
7196
</div>
7297
<div className={`${pointClass} ${classes.tradStone}`} />
7398
{traditional ? <div className={`${pointClass} ${classes.priorStoneTrad}`}></div> : ""}
74-
<div className={classes.coordinates}>
75-
{columnIndexes[x]}
76-
{traditional ? "" : "."}
77-
{y + 1}
78-
</div>
99+
{highlightText ? (
100+
<div className={`${classes.highlightText} ${classes.coordinates}`}>{highlightText}</div>
101+
) : (
102+
<div className={classes.coordinates}>
103+
{columnIndexes[x]}
104+
{traditional ? "" : "."}
105+
{y + 1}
106+
</div>
107+
)}
79108
</>
80109
) : (
81110
<>

src/Netscript/RamCostGenerator.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,9 @@ const go = {
271271
getControlledEmptyNodes: 16,
272272
getStats: 0,
273273
resetStats: 0,
274+
highlightPoint: 0,
275+
clearPointHighlight: 0,
276+
clearAllPointHighlights: 0,
274277
},
275278
cheat: {
276279
getCheatSuccessChance: 1,

src/NetscriptFunctions/Go.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,15 @@ import { Go } from "../Go/Go";
66
import { helpers } from "../Netscript/NetscriptHelpers";
77
import { simpleBoardFromBoard } from "../Go/boardAnalysis/boardAnalysis";
88
import {
9+
addPointHighlight,
910
cheatDestroyNode,
1011
cheatPlayTwoMoves,
1112
cheatRemoveRouter,
1213
cheatRepairOfflineNode,
1314
cheatSuccessChance,
1415
checkCheatApiAccess,
16+
clearAllPointHighlights,
17+
clearPointHighlight,
1518
getChains,
1619
getControlledEmptyNodes,
1720
getCurrentPlayer,
@@ -104,6 +107,19 @@ export function NetscriptGo(): InternalAPI<NSGo> {
104107
(resetAll = false) => {
105108
resetStats(!!resetAll);
106109
},
110+
highlightPoint: (ctx) => (_x, _y, _color, _text) => {
111+
const x = helpers.number(ctx, "x", _x);
112+
const y = helpers.number(ctx, "y", _y);
113+
const color = helpers.string(ctx, "color", _color ?? "");
114+
const text = helpers.string(ctx, "text", _text ?? "");
115+
addPointHighlight(x, y, color, text);
116+
},
117+
clearPointHighlight: (ctx) => (_x, _y) => {
118+
const x = helpers.number(ctx, "x", _x);
119+
const y = helpers.number(ctx, "y", _y);
120+
clearPointHighlight(x, y);
121+
},
122+
clearAllPointHighlights: () => () => clearAllPointHighlights(),
107123
},
108124
cheat: {
109125
getCheatSuccessChance: (ctx: NetscriptContext) => (_cheatCount, playAsWhite) => {

0 commit comments

Comments
 (0)