diff --git a/src/Documentation/doc/programming/go_algorithms.md b/src/Documentation/doc/programming/go_algorithms.md index a8da245e4..c9a660536 100644 --- a/src/Documentation/doc/programming/go_algorithms.md +++ b/src/Documentation/doc/programming/go_algorithms.md @@ -169,7 +169,7 @@ That info can be used to make decisions about where to place routers. In order to expand the area that is controlled by the player's networks, connecting to friendly routers (when possible) is a strong move. This can be done with a very similar implementation to `getRandomMove()`, with the additional check of looking for a neighboring friendly router. For each point on the board: -``` +```text Detect expansion moves: For each point on the board: * If the empty point is a valid move, and @@ -207,7 +207,7 @@ If the opposing faction's network is down to its last open port, placing a route To find out what networks are in danger of capture, `ns.go.analysis.getLiberties()` shows how many empty nodes / open ports each network has. As with `getBoardState()` and `getValidMoves()` , the number of liberties (open ports) for a given point's network can be retrieved via its coordinates `[x][y]` on the grid returned by `getLiberties()` -``` +```text Detect moves to capture the opponent's routers: For each point on the board: * If the empty point is a valid move, and @@ -223,7 +223,7 @@ Detect moves to capture the opponent's routers: `getLiberties()` can also be used to detect your own networks that are in danger of being captured, and look for moves to try and save it. -``` +```text Detect moves to defend a threatened network: For each point on the board: * If the empty point is a valid move, and @@ -264,6 +264,15 @@ This is similar to the logic for defending your networks from immediate capture. ### Move option: Encircling space to control empty nodes +A key part of the strategy of Go is fully encircling groups of empty nodes. The examples at the start of this doc simply leave out specific nodes and hope they stay empty, but this can be done in much better ways. + +As a simple approach, look for possible moves that are: + +- adjacent to two separate empty nodes (open areas it will divide up) +- adjacent a friendly piece and the edge of a board (or a second friendly piece from a different chain than the first) + +This will find moves which are connecting your chains together, or connecting to the edge of the board, and dividing up empty space in the process. This allows you to control space, making it harder to capture your chains in the process. +   ### Choosing a good move option @@ -301,3 +310,13 @@ There are a lot of strong shapes in Go, that are worth attempting to re-create. If a single network fully encloses two different disconnected empty nodes, it can never be taken. (If it only had one inner airspace, the opponent could eventually surround and then fill it to capture the network. If there is two, however, the suicide rule prevents them from filling either inner empty space.) Detecting moves that make figure-8 type shapes, or split an encircled empty node chain into two smaller ones, are very strong. In addition, if the opponent has only a single such move, playing there first to block it is often extremely disruptive, and can even lead to their network being captured. + +  + +A deeper dive into this idea will involve making your own code to identify chains of pieces (and continuous empty nodes). + +- Find all moves that divide up empty space and connect two chains or a chain and the edge as in the 'encircling empty space' idea above +- Apply the move on a sample board in memory, one at a time +- Identify all chains and continuous groups of empty nodes in the resulting board, and which color pieces surround the new empty node groups +- Prioritize the move that makes the most empty node groups fully surrounded by your player color. +- Alternatively, count how many empty node groups each friendly chain is touching, and prioritize moves that create a second of these "eyes" for friendly chains diff --git a/src/Go/boardState/goStyles.ts b/src/Go/boardState/goStyles.ts index 4e5c0b2c8..649153dbf 100644 --- a/src/Go/boardState/goStyles.ts +++ b/src/Go/boardState/goStyles.ts @@ -576,8 +576,8 @@ export const boardStyles = makeStyles((theme: Theme) => }, instructionsBlurb: { width: "60%", - minWidth: "500px", - marginRight: "20px", + minWidth: "300px", + marginRight: "15px", }, translucent: { opacity: 0.6, diff --git a/src/Go/effects/effect.ts b/src/Go/effects/effect.ts index 5452a587d..63ba58385 100644 --- a/src/Go/effects/effect.ts +++ b/src/Go/effects/effect.ts @@ -14,7 +14,7 @@ export function CalculateEffect(nodes: number, faction: opponents): number { const power = getEffectPowerForFaction(faction); const sourceFileBonus = Player.sourceFileLvl(14) ? 1.25 : 1; return ( - 1 + Math.log(nodes + 1) * Math.pow(nodes + 1, 0.33) * 0.005 * power * currentNodeMults.GoPower * sourceFileBonus + 1 + Math.log(nodes + 1) * Math.pow(nodes + 1, 0.3) * 0.004 * power * currentNodeMults.GoPower * sourceFileBonus ); } diff --git a/src/Go/effects/netscriptGoImplementation.ts b/src/Go/effects/netscriptGoImplementation.ts index e6a1de498..5232db943 100644 --- a/src/Go/effects/netscriptGoImplementation.ts +++ b/src/Go/effects/netscriptGoImplementation.ts @@ -41,6 +41,11 @@ export async function makePlayerMove(logger: (s: string) => void, x: number, y: if (validity !== validityReason.valid || !result) { await sleep(500); logger(`ERROR: Invalid move: ${validity}`); + + if (validity === validityReason.notYourTurn) { + logger("Do you have multiple scripts running, or did you forget to await makeMove() ?"); + } + return Promise.resolve(invalidMoveResponse); } diff --git a/src/Go/ui/GoInstructionsPage.tsx b/src/Go/ui/GoInstructionsPage.tsx index f0ab6f194..b7f43ed29 100644 --- a/src/Go/ui/GoInstructionsPage.tsx +++ b/src/Go/ui/GoInstructionsPage.tsx @@ -212,8 +212,8 @@ export const GoInstructionsPage = (): React.ReactElement => {
* If a network surrounds a single empty node, the opponent can eventually capture it by filling in that node. However, if your network has two separate empty nodes inside of it, the suicide rule prevents the - opponent from filling up either of them. This means your network cannot be captured! Try to place your - networks surround several different empty nodes, and avoid filling in your network's empty nodes when + opponent from filling up either of them. This means your network cannot be captured! Try to build your + networks to surround several different empty nodes, and avoid filling in your network's empty nodes when possible.

diff --git a/src/ScriptEditor/NetscriptDefinitions.d.ts b/src/ScriptEditor/NetscriptDefinitions.d.ts index 06bb9c4b8..6b3740ab2 100644 --- a/src/ScriptEditor/NetscriptDefinitions.d.ts +++ b/src/ScriptEditor/NetscriptDefinitions.d.ts @@ -4138,7 +4138,7 @@ export interface Go { x1: number, y1: number, x2: number, - x2: number, + y2: number, ): Promise<{ type: "invalid" | "move" | "pass" | "gameOver"; x: number;