Skip to content

Commit

Permalink
Be explicit about what tile is best. Try and provide info on why a bo…
Browse files Browse the repository at this point in the history
…ard is invalid. Tidy up the console log messages and make them more readable.
  • Loading branch information
DavidNHill committed Oct 31, 2023
1 parent 719b659 commit 1149e59
Show file tree
Hide file tree
Showing 9 changed files with 110 additions and 33 deletions.
2 changes: 1 addition & 1 deletion .vs/VSWorkspaceState.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@
"\\Minesweeper\\client",
"\\Minesweeper\\Utility"
],
"SelectedNode": "\\index.html",
"SelectedNode": "\\Minesweeper\\client\\main.js",
"PreviewInSolutionExplorer": false
}
Binary file modified .vs/slnx.sqlite
Binary file not shown.
18 changes: 14 additions & 4 deletions Minesweeper/client/Board.js
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,7 @@ class Board {
// optionally treat flags as mines (e.g. in analysis mode but not playing or replay)
// place mines when they are trivially found
// The idea is to get the board into a state as pobability engine friendly as possible
// If an invalid tile is found returns it to be reported
resetForAnalysis(flagIsMine, findObviousMines) {

for (let i = 0; i < this.tiles.length; i++) {
Expand All @@ -265,7 +266,7 @@ class Board {
}

if (!findObviousMines) {
return;
return null;
}

for (let i = 0; i < this.tiles.length; i++) {
Expand All @@ -285,19 +286,28 @@ class Board {
if (adjTile.isCovered()) {
coveredCount++;
}
if (adjTile.isFlagged()) {
flagCount++;
}
}

if (coveredCount > 0 && tile.getValue() == flagCount + coveredCount) { // can place all flags
if (coveredCount > 0 && tile.getValue() == coveredCount) { // can place all flags
for (let j = 0; j < adjTiles.length; j++) {
const adjTile = adjTiles[j];
if (adjTile.isCovered() ) { // if covered
if (adjTile.isCovered()) { // if covered
adjTile.setFoundBomb(); // Must be a bomb
}
}
}
} else if (tile.getValue() < flagCount) {
console.log(tile.asText() + " is over flagged");
} else if (tile.getValue() > coveredCount) {
console.log(tile.asText() + " has an invalid value");
return tile;
}

}

return null;
}

getHashValue() {
Expand Down
5 changes: 4 additions & 1 deletion Minesweeper/client/BruteForceAnalysis.js
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,11 @@ class BruteForceAnalysis {
this.currentNode = top;

// this is the best tile to guess (or the best we've calculated if incomplete). "Tile" class.
if (top.bestLiving != null) {
if (top.bestLiving != null) { // processing possible
this.bestTile = BruteForceGlobal.allTiles[top.bestLiving.index];

} else { // all dead - so just pick the first
this.bestTile = BruteForceGlobal.allTiles[0];
}


Expand Down
14 changes: 7 additions & 7 deletions Minesweeper/client/Brute_force.js
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ class WitnessWebIterator {
// if rotation is not - 1 then this locks the first 'cog' in that position and iterates the remaining cogs. This allows parallel processing based on the position of the first 'cog'
constructor(pe, allCoveredTiles, rotation) {

console.log("Creating Iterator");
//console.log("Creating Iterator");

this.sample = []; // int array

Expand Down Expand Up @@ -228,10 +228,10 @@ class WitnessWebIterator {

this.tiles = loc;

console.log("Mines left " + this.probabilityEngine.minesLeft);
console.log("Independent Mines " + indMines);
console.log("Tiles left " + this.probabilityEngine.tilesLeft);
console.log("Independent tiles " + indSquares);
//console.log("Mines left " + this.probabilityEngine.minesLeft);
//console.log("Independent Mines " + indMines);
//console.log("Tiles left " + this.probabilityEngine.tilesLeft);
//console.log("Independent tiles " + indSquares);


// if there are more mines left then squares then no solution is possible
Expand All @@ -240,7 +240,7 @@ class WitnessWebIterator {
|| indMines > this.probabilityEngine.minesLeft) {
this.done = true;
this.top = 0;
console.log("Nothing to do in this iterator");
//console.log("Nothing to do in this iterator");
return;
}

Expand Down Expand Up @@ -272,7 +272,7 @@ class WitnessWebIterator {
}
}

console.log("Iterations needed " + this.cycles);
//console.log("Iterations needed " + this.cycles);

}

Expand Down
37 changes: 35 additions & 2 deletions Minesweeper/client/SolutionCounter.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,14 @@ class SolutionCounter {
this.localClears = [];

this.validWeb = true;
this.invalidReasons = [];

this.recursions = 0;

// can't have less than zero mines
if (minesLeft < 0) {
this.validWeb = false;
this.invalidReasons.push("Not enough mines left to complete the board.");
return;
}

Expand All @@ -53,7 +55,13 @@ class SolutionCounter {
var boxWit = new BoxWitness(this.board, wit);

// can't have too many or too few mines
if (boxWit.minesToFind < 0 || boxWit.minesToFind > boxWit.tiles.length) {
if (boxWit.minesToFind < 0) {
this.invalidReasons.push("Tile " + wit.asText() + " value '" + wit.getValue() + "' is too small? Or a neighbour too large?");
this.validWeb = false;
}

if (boxWit.minesToFind > boxWit.tiles.length) {
this.invalidReasons.push("Tile " + wit.asText() + " value '" + wit.getValue() + "' is too large? Or a neighbour too small?");
this.validWeb = false;
}

Expand All @@ -64,6 +72,12 @@ class SolutionCounter {
var w = this.boxWitnesses[j];

if (w.equivalent(boxWit)) {

if (w.tile.getValue() - board.adjacentFoundMineCount(w.tile) != boxWit.tile.getValue() - board.adjacentFoundMineCount(boxWit.tile)) {
this.invalidReasons.push("Tiles " + w.tile.asText() + " and " + boxWit.tile.asText() + " are contradictory.");
this.validWeb = false;
}

duplicate = true;
break;
}
Expand Down Expand Up @@ -125,6 +139,11 @@ class SolutionCounter {
//console.log("Witness " + boxWit.tile.asText() + " is adjacent to " + boxWit.boxes.length + " boxes and has " + boxWit.minesToFind + " mines to find");
}

// show all the reasons the web is invalid
//for (let msg of this.invalidReasons) {
// console.log(msg);
//}

Object.seal(this) // prevent new properties being created
}

Expand All @@ -134,7 +153,7 @@ class SolutionCounter {

// if the board isn't valid then solution count is zero
if (!this.validWeb) {
console.log("Web is invalid");
//console.log("Web is invalid");
this.finalSolutionsCount = BigInt(0);
this.clearCount = 0;
return;
Expand Down Expand Up @@ -162,6 +181,14 @@ class SolutionCounter {

this.workingProbs = this.mergeProbabilities(nextWitness);

// if we have no solutions then report where it happened
if (this.workingProbs.length == 0) {
//console.log("Board invalid near " + nextWitness.boxWitness.tile.asText());
this.invalidReasons.push("Problem near " + nextWitness.boxWitness.tile.asText() + "?");
this.heldProbs = [];
break;
}

nextWitness = this.findNextWitness(nextWitness);

}
Expand Down Expand Up @@ -273,6 +300,7 @@ class SolutionCounter {
if (nw.newBoxes.length - index == 1) {
// if there are too many for this box then the probability can't be valid
if (nw.newBoxes[index].maxMines < missingMines) {
this.invalidReasons.push("Not enough mines left to complete the board.");
//console.log("Abandon (1)");
return result;
}
Expand Down Expand Up @@ -405,6 +433,7 @@ class SolutionCounter {

// if result is empty this is an impossible position
if (result.length == 0) {
this.invalidReasons.push(this.minesLeft + " mines left is not enough to complete the board?");
return;
}

Expand Down Expand Up @@ -603,6 +632,10 @@ class SolutionCounter {

}

if (totalTally == 0) {
this.invalidReasons.push(this.minesLeft + " mines left is too many to place on the board?");
}

// count how many clears we have
if (totalTally > 0) {
for (let i = 0; i < this.boxes.length; i++) {
Expand Down
19 changes: 15 additions & 4 deletions Minesweeper/client/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ async function startup() {
board.setStarted();
}

//bulkRun(21, 12500); // seed '21' Played 12500 won 5195
//bulkRun(21, 12500); // seed '21' Played 12500 won 5192
//bulkRun(321, 10000); // seed 321 played 10000 won 4123

showMessage("Welcome to minesweeper solver dedicated to Annie");
Expand Down Expand Up @@ -1934,7 +1934,7 @@ async function doAnalysis() {
canvasLocked = true;
}

console.log(docAnalysisParm.value);
//console.log(docAnalysisParm.value);
let compressed = "";
if (docAnalysisParm.value == "full") {
compressed = board.getCompressedData(false);
Expand Down Expand Up @@ -1978,6 +1978,7 @@ async function doAnalysis() {
}

options.guessPruning = guessAnalysisPruning;
options.fullBFDA = true;

const solve = await solver(board, options); // look for solutions
const hints = solve.actions;
Expand Down Expand Up @@ -2023,7 +2024,12 @@ async function checkBoard() {
console.log("Checking board with hash " + currentBoardHash);

// this will set all the obvious mines which makes the solution counter a lot more efficient on very large boards
board.resetForAnalysis(true, true);
const badTile = board.resetForAnalysis(true, true);
if (badTile != null) {
analysisButton.disabled = true;
showMessage("The board is in an invalid state. Tile " + badTile.asText() + " is invalid.");
return;
}

const solutionCounter = await solver.countSolutions(board);
board.resetForAnalysis(true, false);
Expand All @@ -2041,8 +2047,13 @@ async function checkBoard() {
showMessage("The board is valid. " + board.getFlagsPlaced() + " Mines placed. " + logicText + formatSolutions(solutionCounter.finalSolutionsCount));

} else {
let msg = "";
if (solutionCounter.invalidReasons.length > 0) {
msg = solutionCounter.invalidReasons[0];
}
analysisButton.disabled = true;
showMessage("The board is in an invalid state. " + board.getFlagsPlaced() + " Mines placed. ");
//showMessage("The board is in an invalid state. " + msg + " " + board.getFlagsPlaced() + " Mines placed. ");
showMessage("The board is in an invalid state. " + msg);
}

}
Expand Down
Loading

0 comments on commit 1149e59

Please sign in to comment.