From d7c147b2be065daf31d2d15179731cb7304a33cc Mon Sep 17 00:00:00 2001 From: Zikoat Date: Mon, 12 Aug 2024 00:25:23 +0200 Subject: [PATCH] Fix chording with open mine --- src/Field.test.ts | 108 +++++++++++++++++++++++++++++++++++++++++++--- src/Field.ts | 32 +++++++++----- 2 files changed, 122 insertions(+), 18 deletions(-) diff --git a/src/Field.test.ts b/src/Field.test.ts index d133a74..0fbd6b0 100644 --- a/src/Field.test.ts +++ b/src/Field.test.ts @@ -329,13 +329,13 @@ test("Chunk should get cell", () => { test("should be able to chord flag, chord open and chord open should also chord flag", () => { const field = new Field(0.08, 1, "test1", "testSeed"); - field.setCell(4, 1, { isMine: true }); - field.setCell(7, 2, { isMine: true }); - field.setCell(1, 3, { isMine: true }); - field.setCell(8, 4, { isMine: true }); - field.setCell(5, 5, { isMine: true }); - field.setCell(6, 5, { isMine: true }); - field.setCell(2, 6, { isMine: true }); + field._setCell(4, 1, { isMine: true }); + field._setCell(7, 2, { isMine: true }); + field._setCell(1, 3, { isMine: true }); + field._setCell(8, 4, { isMine: true }); + field._setCell(5, 5, { isMine: true }); + field._setCell(6, 5, { isMine: true }); + field._setCell(2, 6, { isMine: true }); field.open(3, 3); @@ -403,6 +403,100 @@ x100013. ); }); +test("An opened mine should be handled like a flag when chord opening", () => { + // shit todo, we should be able to pass a visual field, and it should set the field like that. + + const field = new Field(0, 2, "test1", "testSeed"); + field._setCell(2, 1, { isMine: true }); + field._setCell(5, 2, { isMine: true }); + field._setCell(6, 2, { isMine: true }); + field._setCell(1, 4, { isMine: true }); + field._setCell(7, 5, { isMine: true }); + field._setCell(4, 6, { isMine: true }); + const view = () => fieldViewToString(field, 1, 1, 8, 6); + + // Open 0 to reveal + field.open(3, 3); + // Open mine on corner + field.open(5, 2); + + assertFieldViewEquals( + view(), + `.x...... +.111Xx.. +.10122.. +x10001.. +.11111x. +...x....`, + ); + + // Chord open 2 below mine, which should flag the other mine + field.open(5, 3); + + assertFieldViewEquals( + view(), + `.x...... +.111XF.. +.10122.. +x10001.. +.11111x. +...x....`, + ); + + // Chord open the next 2, which should open the 3 tiles to the right + field.open(6, 3); + + assertFieldViewEquals( + view(), + `.x...... +.111XF1. +.101221. +x100011. +.11111x. +...x....`, + ); +}); +test("An opened mine should be handled like a flag when chord flagging", () => { + // shit todo, we should be able to pass a visual field, and it should set the field like that. + + const field = new Field(0, 2, "test1", "testSeed"); + field._setCell(2, 1, { isMine: true }); + field._setCell(5, 2, { isMine: true }); + field._setCell(6, 2, { isMine: true }); + field._setCell(1, 4, { isMine: true }); + field._setCell(7, 5, { isMine: true }); + field._setCell(4, 6, { isMine: true }); + const view = () => fieldViewToString(field, 1, 1, 8, 6); + + // Open 0 to reveal + field.open(3, 3); + // Open mine on corner + field.open(5, 2); + + assertFieldViewEquals( + view(), + `.x...... +.111Xx.. +.10122.. +x10001.. +.11111x. +...x....`, + ); + + // Chord flag 2 below mine, which should flag the other mine + field.flag(5, 3); + + assertFieldViewEquals( + view(), + `.x...... +.111XF.. +.10122.. +x10001.. +.11111x. +...x....`, + ); +}); + function cellToObject(cell: Cell): { isFlagged: boolean; isOpen: boolean; diff --git a/src/Field.ts b/src/Field.ts index 4068ca0..13b0be3 100644 --- a/src/Field.ts +++ b/src/Field.ts @@ -75,13 +75,18 @@ export class Field extends PIXI.EventEmitter { if (cell.isOpen) { const neighbors = this.getNeighbors(x, y); - const flaggedNeighbors = neighbors.filter((cell) => cell.isFlagged); - const closedNeighbors = neighbors.filter((cell) => !cell.isOpen); + const closedUnflaggedNeighbors = neighbors.filter( (cell) => !cell.isFlagged && !cell.isOpen, ); + const value = this.value(x, y); const changedCells = []; + + const flaggedNeighbors = neighbors.filter( + (cell) => cell.isFlagged || (cell.isOpen && cell.isMine), // Open mines should be treated as flags when chording + ); + if (flaggedNeighbors.length === value) { for (const closedUnflaggedNeighbor of closedUnflaggedNeighbors) { const newOpenedCells = this.open( @@ -91,7 +96,13 @@ export class Field extends PIXI.EventEmitter { changedCells.push(...newOpenedCells); } return changedCells; - } else if (closedNeighbors.length === value) { + } + + const closedNeighbors = neighbors.filter( + (cell) => !cell.isOpen || (cell.isOpen && cell.isMine), + ); + + if (closedNeighbors.length === value) { for (const closedUnflaggedNeighbor of closedUnflaggedNeighbors) { const newFlaggedCells = this.flag( closedUnflaggedNeighbor.x, @@ -109,10 +120,10 @@ export class Field extends PIXI.EventEmitter { if (cell.isMine === undefined) { cell.isMine = this.rng() < this.probability; - this.setCell(cell.x, cell.y, cell); + this._setCell(cell.x, cell.y, cell); } - this.setCell(x, y, { isOpen: true }); + this._setCell(x, y, { isOpen: true }); cell = this.getCell(x, y); if (cell.isMine) { @@ -128,7 +139,7 @@ export class Field extends PIXI.EventEmitter { const neighbor = neighbors[i]; if (neighbor.isMine === undefined) { neighbor.isMine = this.rng() < this.probability; - this.setCell(neighbor.x, neighbor.y, neighbor); + this._setCell(neighbor.x, neighbor.y, neighbor); // this.generateCell(neighbors[i].x, neighbors[i].y); } } @@ -168,13 +179,13 @@ export class Field extends PIXI.EventEmitter { const cell = this.getCell(x, y); if (!cell.isOpen) { cell.isFlagged = !cell.isFlagged; - this.setCell(x, y, cell); + this._setCell(x, y, cell); // todo remove this, we should base on return value of flag. this.emit("cellChanged", cell); return [cell]; } else { const closedNeighbors = this.getNeighbors(x, y).filter( - (cell) => !cell.isOpen, + (cell) => !cell.isOpen || (cell.isMine && cell.isOpen), ); if (closedNeighbors.length === this.value(x, y)) { for (const closedNeighbor of closedNeighbors) { @@ -256,7 +267,6 @@ export class Field extends PIXI.EventEmitter { return output; } - private setSafeCells(x0: number, y0: number) { // initiate the field with a circle of cells that aren't mines this.pristine = false; @@ -269,14 +279,14 @@ export class Field extends PIXI.EventEmitter { const x = x0 + dx; const y = y0 + dy; // we generate the cell, and overwrite the isMine state - this.setCell(x, y, { isFlagged: false, isMine: false }); + this._setCell(x, y, { isFlagged: false, isMine: false }); // this.generateCell(x, y, false, false); } } } } - public setCell(x: number, y: number, cell: Partial) { + public _setCell(x: number, y: number, cell: Partial) { const gottenCell = this.cellData.get(x, y); if (cell.isMine !== undefined) gottenCell.isMine = cell.isMine; if (cell.isFlagged !== undefined) gottenCell.isFlagged = cell.isFlagged;