Add References to git
This commit is contained in:
@ -0,0 +1,888 @@
|
||||
package minesweeper.solver;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import minesweeper.gamestate.GameStateModel;
|
||||
import minesweeper.gamestate.MoveMethod;
|
||||
import minesweeper.solver.BoardStateCache.AdjacentSquares;
|
||||
import minesweeper.solver.BoardStateCache.Cache;
|
||||
import minesweeper.solver.utility.Logger;
|
||||
import minesweeper.solver.utility.Logger.Level;
|
||||
import minesweeper.structure.Action;
|
||||
import minesweeper.structure.Area;
|
||||
import minesweeper.structure.Location;
|
||||
|
||||
public class BoardState {
|
||||
|
||||
private final static int[] DX = {0, 1, 1, 1, 0, -1, -1, -1};
|
||||
private final static int[] DY = {-1, -1, 0, 1, 1, 1, 0, -1};
|
||||
|
||||
//private AdjacentSquares[][] adjacentLocations1;
|
||||
//private AdjacentSquares[][] adjacentLocations2;
|
||||
|
||||
private int[][] board;
|
||||
private boolean[][] revealed;
|
||||
private boolean[][] confirmedMine;
|
||||
private boolean[][] flagOnBoard;
|
||||
|
||||
//private int[][] clearAll;
|
||||
|
||||
private int[][] adjFlagsConfirmed;
|
||||
private int[][] adjFlagsOnBoard;
|
||||
private int[][] adjUnrevealed;
|
||||
|
||||
// this holds the actions made against each location and a list of actions generated this turn
|
||||
private Action[][] action;
|
||||
private List<Action> actionList = new ArrayList<Action>();
|
||||
|
||||
private final GameStateModel myGame;
|
||||
private final Solver solver;
|
||||
private final int height;
|
||||
private final int width;
|
||||
|
||||
private int totalFlags = 0;
|
||||
private int confirmedMinesTotal = 0;
|
||||
private int numOfHidden = 0;
|
||||
|
||||
private int[] unplayedMoves;
|
||||
|
||||
private int testMoveBalance = 0;
|
||||
|
||||
private Set<Location> livingWitnesses = new HashSet<>();
|
||||
|
||||
private final Cache cache;
|
||||
|
||||
public BoardState(Solver solver) {
|
||||
|
||||
this.solver = solver;
|
||||
this.myGame = solver.getGame();
|
||||
this.width = myGame.getWidth();
|
||||
this.height = myGame.getHeight();
|
||||
|
||||
confirmedMine = new boolean[myGame.getWidth()][myGame.getHeight()];
|
||||
adjFlagsConfirmed = new int[myGame.getWidth()][myGame.getHeight()];
|
||||
adjUnrevealed = new int[myGame.getWidth()][myGame.getHeight()];
|
||||
revealed = new boolean[myGame.getWidth()][myGame.getHeight()];
|
||||
board = new int[myGame.getWidth()][myGame.getHeight()];
|
||||
|
||||
flagOnBoard = new boolean[myGame.getWidth()][myGame.getHeight()];
|
||||
adjFlagsOnBoard = new int[myGame.getWidth()][myGame.getHeight()];
|
||||
|
||||
action = new Action[myGame.getWidth()][myGame.getHeight()];
|
||||
|
||||
// look up the adjacent squares details
|
||||
cache = BoardStateCache.getInstance().getAdjacentSquares1(myGame.getWidth(), myGame.getHeight());
|
||||
//adjacentLocations1 = cache.adjacentLocations1;
|
||||
//adjacentLocations2 = cache.adjacentLocations2;
|
||||
|
||||
|
||||
final int bottom = myGame.getHeight() - 1;
|
||||
final int right = myGame.getWidth() - 1;
|
||||
|
||||
// set up how many adjacent locations there are to each square - they are all unrevealed to start with
|
||||
for (int x=0; x < width; x++) {
|
||||
for (int y=0; y < height; y++) {
|
||||
|
||||
int adjacent = 8;
|
||||
// corners
|
||||
if (x == 0 && y == 0 || x == 0 && y == bottom || x == right && y == 0 || x == right && y == bottom) {
|
||||
adjacent = 3;
|
||||
// the edge
|
||||
} else if (x == 0 || y == 0 || x == right || y == bottom){
|
||||
adjacent = 5;
|
||||
}
|
||||
|
||||
adjUnrevealed[x][y] = adjacent;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public void process() {
|
||||
|
||||
totalFlags = 0;
|
||||
confirmedMinesTotal = 0;
|
||||
numOfHidden = 0;
|
||||
|
||||
// clear down this array, which is a lot faster then defining it fresh
|
||||
for (int i=0; i < width; i++) {
|
||||
for (int j=0; j < height; j++) {
|
||||
adjFlagsOnBoard[i][j] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// clear down the moves we collected last turn
|
||||
actionList.clear();
|
||||
|
||||
// load up what we can see on the board
|
||||
for (int i=0; i < width; i++) {
|
||||
for (int j=0; j < height; j++) {
|
||||
|
||||
Location location = getLocation(i, j);
|
||||
|
||||
flagOnBoard[i][j] = false; // until proven otherwise
|
||||
int info = myGame.query(location);
|
||||
|
||||
Action act = action[i][j];
|
||||
|
||||
// if the move isn't a certainty then don't bother with it. The opening book is a certainty on the first move, but isn't really if the player plays somewhere else.
|
||||
if (act != null && (!act.isCertainty() || act.getMoveMethod() == MoveMethod.BOOK)) {
|
||||
action[i][j] = null;
|
||||
act = null;
|
||||
}
|
||||
|
||||
if (info != GameStateModel.HIDDEN) {
|
||||
if (info == GameStateModel.FLAG) {
|
||||
totalFlags++;
|
||||
flagOnBoard[i][j] = true;
|
||||
|
||||
// inform its neighbours they have a flag on the board
|
||||
for (int k=0; k < DX.length; k++) {
|
||||
if (i + DX[k] >= 0 && i + DX[k] < width && j + DY[k] >= 0 && j + DY[k] < height) {
|
||||
adjFlagsOnBoard[i + DX[k]][j + DY[k]]++;
|
||||
}
|
||||
}
|
||||
|
||||
if (confirmedMine[i][j]) { // mine found by solver
|
||||
confirmedMinesTotal++;
|
||||
} else {
|
||||
numOfHidden++; // flag on the board but we can't confirm it
|
||||
}
|
||||
|
||||
// if the board is a flag, but we are 100% sure its a clear then remove the flag
|
||||
// then clear the square
|
||||
if (act != null && act.getAction() == Action.CLEAR && act.isCertainty()) {
|
||||
actionList.add(new Action(act, Action.FLAG, MoveMethod.CORRECTION, "Remove flag", BigDecimal.ONE, 0));
|
||||
actionList.add(act);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// if this is a new unrevealed location then set it up and inform it's neighbours they have one less unrevealed adjacent location
|
||||
if (!revealed[i][j]) {
|
||||
|
||||
livingWitnesses.add(location); // add this to living witnesses
|
||||
//display("Location (" + i + "," + j + ") is revealed");
|
||||
|
||||
revealed[i][j] = true;
|
||||
board[i][j] = info;
|
||||
|
||||
for (int k=0; k < DX.length; k++) {
|
||||
if (i + DX[k] >= 0 && i + DX[k] < width && j + DY[k] >= 0 && j + DY[k] < height) {
|
||||
adjUnrevealed[i + DX[k]][j + DY[k]]--;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
} else {
|
||||
if ((solver.getPlayStyle().flagless || solver.getPlayStyle().efficiency) && confirmedMine[i][j]) { // if we are playing flags free then all confirmed mines are consider to be flagged
|
||||
confirmedMinesTotal++;
|
||||
totalFlags++;
|
||||
} else {
|
||||
numOfHidden++;
|
||||
}
|
||||
|
||||
// if we have an action against this location which we are 100% sure about then do it
|
||||
if (act != null && act.isCertainty()) {
|
||||
if ((solver.getPlayStyle().flagless || solver.getPlayStyle().efficiency) && act.getAction() == Action.FLAG) {
|
||||
// unless the we are playing flag free and it's a flag
|
||||
} else {
|
||||
actionList.add(act);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
List<Location> toRemove = new ArrayList<>();
|
||||
for (Location wit: livingWitnesses) {
|
||||
if (this.countAdjacentUnrevealed(wit) == 0) {
|
||||
//display("Location " + wit.display() + " is now a dead witness");
|
||||
toRemove.add(wit);
|
||||
}
|
||||
}
|
||||
livingWitnesses.removeAll(toRemove);
|
||||
|
||||
|
||||
// this sorts the moves by when they were discovered
|
||||
Collections.sort(actionList, Action.SORT_BY_MOVE_NUMBER);
|
||||
|
||||
unplayedMoves = new int[MoveMethod.values().length];
|
||||
|
||||
// accumulate how many unplayed moves there are by method
|
||||
for (Action a: actionList) {
|
||||
unplayedMoves[a.getMoveMethod().ordinal()]++;
|
||||
}
|
||||
|
||||
getLogger().log(Level.INFO, "Moves left to play is %d", actionList.size());
|
||||
for (int i=0; i < unplayedMoves.length; i++) {
|
||||
if (unplayedMoves[i] != 0) {
|
||||
getLogger().log(Level.INFO, " %s has %d moves unplayed",MoveMethod.values()[i], unplayedMoves[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
protected int getGameWidth() {
|
||||
return width;
|
||||
}
|
||||
|
||||
protected int getGameHeight() {
|
||||
return height;
|
||||
}
|
||||
|
||||
protected int getMines() {
|
||||
return this.myGame.getMines();
|
||||
}
|
||||
|
||||
|
||||
//public void setAction(Action a) {
|
||||
// setAction(a, true);
|
||||
//}
|
||||
|
||||
/**
|
||||
* Register the action against the location(x,y);
|
||||
* Optionally add the action to the list of actions to play this turn
|
||||
*/
|
||||
public void setAction(Action a) {
|
||||
|
||||
//display("Setting action at " + a.display());
|
||||
|
||||
if (action[a.x][a.y] != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
action[a.x][a.y] = a;
|
||||
|
||||
if (a.getAction() == Action.FLAG) {
|
||||
setMineFound(a);
|
||||
}
|
||||
|
||||
if ((solver.getPlayStyle().flagless || solver.getPlayStyle().efficiency) && a.getAction() == Action.FLAG) {
|
||||
// if it is flag free or efficiency and we have discovered a mine then don't flag it
|
||||
} else if (isFlagOnBoard(a) && a.getAction() == Action.FLAG) {
|
||||
// if the flag is already on the board then nothing to do
|
||||
} else if (isFlagOnBoard(a) && a.getAction() == Action.CLEAR) {
|
||||
// if a flag is blocking the clear move then remove the flag first
|
||||
actionList.add(new Action(a, Action.FLAG, MoveMethod.CORRECTION, "Remove flag", BigDecimal.ONE, 0));
|
||||
actionList.add(a);
|
||||
} else {
|
||||
actionList.add(a);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
protected boolean alreadyActioned(Location l) {
|
||||
return alreadyActioned(l.x, l.y);
|
||||
}
|
||||
|
||||
protected boolean alreadyActioned(int x, int y) {
|
||||
return (action[x][y] != null);
|
||||
}
|
||||
|
||||
|
||||
protected List<Action> getActions() {
|
||||
return this.actionList;
|
||||
}
|
||||
|
||||
/**
|
||||
* This will consider chords when returning the moves to play
|
||||
*/
|
||||
/*
|
||||
protected List<Action> getActionsWithChords() {
|
||||
|
||||
// if we aren't using chords or none are available then skip all this expensive processing
|
||||
if (chordLocations.isEmpty() || !solver.isPlayChords()) {
|
||||
return getActions();
|
||||
}
|
||||
|
||||
List<Action> actions = new ArrayList<>();
|
||||
boolean[][] processed = new boolean[myGame.getWidth()][myGame.getHeight()];
|
||||
|
||||
// sort the most beneficial chords to the top
|
||||
Collections.sort(chordLocations, ChordLocation.SORT_BY_BENEFIT_DESC);
|
||||
|
||||
List<ChordLocation> toDelete = new ArrayList<>();
|
||||
|
||||
for (ChordLocation cl: chordLocations) {
|
||||
|
||||
int benefit = 0;
|
||||
int cost = 0;
|
||||
|
||||
for (Location l: getAdjacentSquaresIterable(cl)) {
|
||||
// flag not yet on board
|
||||
if (!processed[l.x][l.y] && isConfirmedFlag(l) && !isFlagOnBoard(l)) {
|
||||
cost++;
|
||||
}
|
||||
if (!processed[l.x][l.y] && isUnrevealed(l)) {
|
||||
benefit++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (benefit - cost > 1) {
|
||||
|
||||
for (Location l: getAdjacentSquaresIterable(cl)) {
|
||||
// flag not yet on board
|
||||
if (!processed[l.x][l.y] && isConfirmedFlag(l) && !isFlagOnBoard(l)) {
|
||||
actions.add(new Action(l, Action.FLAG, MoveMethod.TRIVIAL, "Place flag", BigDecimal.ONE, 0));
|
||||
}
|
||||
// flag on board in error
|
||||
if (!processed[l.x][l.y] && !isConfirmedFlag(l) && isFlagOnBoard(l)) {
|
||||
actions.add(new Action(l, Action.FLAG, MoveMethod.CORRECTION, "Remove flag", BigDecimal.ONE, 0));
|
||||
}
|
||||
processed[l.x][l.y] = true;
|
||||
}
|
||||
// now add the clear all
|
||||
actions.add(new Action(cl, Action.CLEARALL, MoveMethod.TRIVIAL, "Clear All", BigDecimal.ONE, 1));
|
||||
|
||||
} else {
|
||||
//toDelete.add(cl);
|
||||
}
|
||||
}
|
||||
|
||||
chordLocations.removeAll(toDelete);
|
||||
|
||||
// now add the the actions that haven't been resolved by a chord play
|
||||
for (Action act: actionList) {
|
||||
if (!processed[act.x][act.y]) {
|
||||
processed[act.x][act.y] = true;
|
||||
}
|
||||
actions.add(act);
|
||||
}
|
||||
|
||||
return actions;
|
||||
}
|
||||
*/
|
||||
/**
|
||||
* Get the probability of a mine being in this square (based upon the actions still pending)
|
||||
*/
|
||||
protected BigDecimal getProbability(int x, int y) {
|
||||
|
||||
for (Action act: actionList) {
|
||||
if (act.x == x && act.y== y) {
|
||||
if (act.getAction() == Action.FLAG) {
|
||||
return BigDecimal.ZERO;
|
||||
} else if (act.getAction() == Action.CLEAR) {
|
||||
return act.getBigProb();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
|
||||
//protected int getActionsCount() {
|
||||
// return this.actionList.size();
|
||||
//}
|
||||
|
||||
/**
|
||||
* Add a isolated dead tile
|
||||
*/
|
||||
//protected void addIsolatedDeadTile(Location loc) {
|
||||
// isolatedDeadTiles.add(loc);
|
||||
//}
|
||||
|
||||
//public int getIsolatedDeadTileCount() {
|
||||
// return this.isolatedDeadTiles.size();
|
||||
//}
|
||||
|
||||
/**
|
||||
* Returns and removes the first Isolated Dead Tile in the set
|
||||
*/
|
||||
//public Location getIsolatedDeadTile() {
|
||||
// for (Location loc: isolatedDeadTiles) {
|
||||
// //isolatedDeadTiles.remove(loc);
|
||||
// return loc;
|
||||
// }
|
||||
// return null;
|
||||
//}
|
||||
|
||||
protected List<Location> getWitnesses(Collection<? extends Location> square) {
|
||||
return new ArrayList<Location>(getWitnessesArea(square).getLocations());
|
||||
}
|
||||
|
||||
/**
|
||||
* From the given locations, generate all the revealed squares that can witness these locations
|
||||
*/
|
||||
protected Area getWitnessesArea(Collection<? extends Location> square) {
|
||||
|
||||
Set<Location> work = new HashSet<>(10);
|
||||
|
||||
for (Location loc: square) {
|
||||
|
||||
for (Location adj: this.getAdjacentSquaresIterable(loc)) {
|
||||
// determine the number of distinct witnesses
|
||||
if (isRevealed(adj)) {
|
||||
work.add(adj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new Area(work);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* From the given locations, generate an area containing all the un-revealed squares around them
|
||||
*/
|
||||
protected Area getUnrevealedArea(List<? extends Location> witnesses) {
|
||||
return new Area(getUnrevealedSquaresDo(witnesses));
|
||||
}
|
||||
|
||||
/**
|
||||
* From the given locations, generate all the un-revealed squares around them
|
||||
*/
|
||||
protected List<Location> getUnrevealedSquares(List<? extends Location> witnesses) {
|
||||
return new ArrayList<Location>(getUnrevealedSquaresDo(witnesses));
|
||||
}
|
||||
|
||||
|
||||
private Set<Location> getUnrevealedSquaresDo(List<? extends Location> witnesses) {
|
||||
|
||||
Set<Location> work = new HashSet<>(witnesses.size() * 3);
|
||||
|
||||
for (Location loc: witnesses) {
|
||||
|
||||
for (Location adj: this.getAdjacentSquaresIterable(loc)) {
|
||||
|
||||
if (isUnrevealed(adj)) {
|
||||
work.add(adj);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return work;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all the unrevealed Locations on the board
|
||||
*/
|
||||
protected List<Location> getAllUnrevealedSquares() {
|
||||
|
||||
ArrayList<Location> work = new ArrayList<>(width * height);
|
||||
|
||||
for (int i=0; i < width; i++) {
|
||||
for (int j=0; j < height; j++) {
|
||||
if (isUnrevealed(i,j)) {
|
||||
work.add(getLocation(i,j));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return work;
|
||||
}
|
||||
|
||||
protected List<Location> getAllLivingWitnesses() {
|
||||
return new ArrayList<>(livingWitnesses);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return a list of Unrevealed Locations adjacent to this one
|
||||
*/
|
||||
protected List<Location> getAdjacentUnrevealedSquares(Location loc) {
|
||||
|
||||
return getAdjacentUnrevealedSquares(loc, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an Area of un-revealed Locations adjacent to this one
|
||||
*/
|
||||
protected Area getAdjacentUnrevealedArea(Location loc) {
|
||||
|
||||
return new Area(getAdjacentUnrevealedSquares(loc, 1));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return a list of Unrevealed Locations adjacent to this one
|
||||
*/
|
||||
protected List<Location> getAdjacentUnrevealedSquares(Location loc, int size ) {
|
||||
|
||||
ArrayList<Location> work = new ArrayList<>();
|
||||
|
||||
for (Location a: getAdjacentSquaresIterable(loc, size)) {
|
||||
if (isUnrevealed(a)) {
|
||||
work.add(a);
|
||||
}
|
||||
}
|
||||
|
||||
return work;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Location for this position, avoids having to instantiate one
|
||||
*/
|
||||
protected Location getLocation(int x, int y) {
|
||||
if (x < 0 || x >= this.width || y < 0 || y >= this.height) {
|
||||
return null;
|
||||
} else {
|
||||
return cache.getLocation(x, y);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This returns the adjacent squares to a depth of size away. So (l,2) returns the 24 squares 2 deep surrounding l.
|
||||
*/
|
||||
protected Iterable<Location> getAdjacentSquaresIterable(Location loc, int size) {
|
||||
if (size == 1) {
|
||||
return getAdjacentSquaresIterable(loc);
|
||||
} else {
|
||||
return cache.adjacentLocations2[loc.x][loc.y];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected Iterable<Location> getAdjacentSquaresIterable(Location loc) {
|
||||
return cache.adjacentLocations1[loc.x][loc.y];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Done as part of validating Locations, must be undone using clearWitness()
|
||||
*/
|
||||
protected void setWitnessValue(Location l, int value) {
|
||||
board[l.x][l.y] = value;
|
||||
revealed[l.x][l.y] = true;
|
||||
|
||||
testMoveBalance++;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Done as part of validating Locations
|
||||
*/
|
||||
protected void clearWitness(Location l) {
|
||||
board[l.x][l.y] = 0;
|
||||
revealed[l.x][l.y] = false;
|
||||
|
||||
testMoveBalance--;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to read our own array of reveal values.
|
||||
*/
|
||||
protected int getWitnessValue(Location l) {
|
||||
return getWitnessValue(l.x, l.y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to read our own array of reveal values.
|
||||
*/
|
||||
protected int getWitnessValue(int x, int y) {
|
||||
if (isUnrevealed(x,y)) {
|
||||
throw new RuntimeException("Trying to get a witness value for an unrevealed square");
|
||||
}
|
||||
return board[x][y];
|
||||
}
|
||||
|
||||
/**
|
||||
* indicates a flag is on the board, but the solver can't confirm it
|
||||
*/
|
||||
protected boolean isUnconfirmedFlag(Location l) {
|
||||
return isUnconfirmedFlag(l.x, l.y);
|
||||
}
|
||||
|
||||
/**
|
||||
* indicates a flag is on the board, but the solver can't confirm it
|
||||
*/
|
||||
protected boolean isUnconfirmedFlag(int x, int y) {
|
||||
return flagOnBoard[x][y] && !confirmedMine[x][y];
|
||||
}
|
||||
|
||||
/**
|
||||
* indicates a flag is on the board
|
||||
*/
|
||||
protected boolean isFlagOnBoard(Location l) {
|
||||
return isFlagOnBoard(l.x, l.y);
|
||||
}
|
||||
|
||||
/**
|
||||
* indicates a flag is on the board
|
||||
*/
|
||||
protected boolean isFlagOnBoard(int x, int y) {
|
||||
return flagOnBoard[x][y];
|
||||
}
|
||||
|
||||
|
||||
protected void setFlagOnBoard(Location l) {
|
||||
setFlagOnBoard(l.x, l.y);
|
||||
}
|
||||
|
||||
protected void setFlagOnBoard(int x, int y) {
|
||||
flagOnBoard[x][y] = true;
|
||||
}
|
||||
|
||||
protected void setMineFound(Location loc) {
|
||||
|
||||
if (isConfirmedMine(loc)) {
|
||||
return;
|
||||
}
|
||||
|
||||
confirmedMinesTotal++;
|
||||
confirmedMine[loc.x][loc.y] = true;
|
||||
|
||||
// if the flag isn't already on the board then this is also another on the total of all flags
|
||||
if (!flagOnBoard[loc.x][loc.y]) {
|
||||
totalFlags++;
|
||||
}
|
||||
|
||||
// let all the adjacent squares know they have one more flag next to them and one less unrevealed location
|
||||
for (Location a: getAdjacentSquaresIterable(loc)) {
|
||||
adjFlagsConfirmed[a.x][a.y]++;
|
||||
adjUnrevealed[a.x][a.y]--;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected void unsetMineFound(Location loc) {
|
||||
|
||||
if (!isConfirmedMine(loc)) {
|
||||
return;
|
||||
}
|
||||
|
||||
confirmedMinesTotal--;
|
||||
confirmedMine[loc.x][loc.y] = false;
|
||||
|
||||
|
||||
// if the flag isn't already on the board then this is also another on the total of all flags
|
||||
if (!flagOnBoard[loc.x][loc.y]) {
|
||||
totalFlags--;
|
||||
}
|
||||
|
||||
// let all the adjacent squares know they have one less mine next to them and one more unrevealed location
|
||||
for (Location a: getAdjacentSquaresIterable(loc)) {
|
||||
adjFlagsConfirmed[a.x][a.y]--;
|
||||
adjUnrevealed[a.x][a.y]++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Since Flag Free is a thing, we can't rely on the GameState to tell us where the flags are,
|
||||
* so this replaces that.
|
||||
*/
|
||||
protected boolean isConfirmedMine(Location l) {
|
||||
return isConfirmedMine(l.x, l.y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Since Flag Free is a thing, we can't rely on the GameState to tell us where the flags are,
|
||||
* so this replaces that.
|
||||
*/
|
||||
protected boolean isConfirmedMine(int x, int y) {
|
||||
return confirmedMine[x][y];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the location is revealed
|
||||
*/
|
||||
protected boolean isRevealed(Location l) {
|
||||
return isRevealed(l.x, l.y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the location is revealed
|
||||
*/
|
||||
protected boolean isRevealed(int x, int y) {
|
||||
return revealed[x][y];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the location is unrevealed (neither revealed nor a confirmed flag)
|
||||
*/
|
||||
protected boolean isUnrevealed(Location l) {
|
||||
return isUnrevealed(l.x, l.y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the location is unrevealed (neither revealed nor a confirmed flag)
|
||||
*/
|
||||
protected boolean isUnrevealed(int x, int y) {
|
||||
return !confirmedMine[x][y] && !revealed[x][y];
|
||||
}
|
||||
|
||||
/**
|
||||
* count how many confirmed flags are adjacent to this square
|
||||
*/
|
||||
protected int countAdjacentConfirmedFlags(Location l) {
|
||||
return countAdjacentConfirmedFlags(l.x, l.y);
|
||||
}
|
||||
|
||||
/**
|
||||
* count how many confirmed flags are adjacent to this square
|
||||
*/
|
||||
protected int countAdjacentConfirmedFlags(int x, int y) {
|
||||
|
||||
return adjFlagsConfirmed[x][y];
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* count how many flags are adjacent to this square on the board
|
||||
*/
|
||||
protected int countAdjacentFlagsOnBoard(Location l) {
|
||||
return countAdjacentFlagsOnBoard(l.x, l.y);
|
||||
}
|
||||
|
||||
/**
|
||||
* count how many flags are adjacent to this square on the board
|
||||
*/
|
||||
protected int countAdjacentFlagsOnBoard(int x, int y) {
|
||||
|
||||
return adjFlagsOnBoard[x][y];
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* count how many confirmed and unconfirmed flags are adjacent to this square
|
||||
*/
|
||||
protected int countAllFlags(int x, int y) {
|
||||
|
||||
int result = 0;
|
||||
|
||||
for (int i=0; i < DX.length; i++) {
|
||||
if (x + DX[i] >= 0 && x + DX[i] < width && y + DY[i] >= 0 && y + DY[i] < height) {
|
||||
if (confirmedMine[x + DX[i]][y + DY[i]] || flagOnBoard[x + DX[i]][y + DY[i]]) {
|
||||
result++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* count how many adjacent squares are neither flags nor revealed
|
||||
*/
|
||||
protected int countAdjacentUnrevealed(Location l) {
|
||||
|
||||
return countAdjacentUnrevealed(l.x, l.y);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* count how many adjacent squares are neither confirmed flags nor revealed
|
||||
*/
|
||||
protected int countAdjacentUnrevealed(int x, int y) {
|
||||
|
||||
return adjUnrevealed[x][y];
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* count how many squares are neither confirmed flags nor revealed
|
||||
*/
|
||||
protected int getTotalUnrevealedCount() {
|
||||
|
||||
return numOfHidden;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of mines the solver knows the location of
|
||||
*/
|
||||
protected int getConfirmedMineCount() {
|
||||
|
||||
return confirmedMinesTotal;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Number of flags on the board both confirmed and unconfirmed
|
||||
*/
|
||||
protected int getTotalFlagCount() {
|
||||
return this.totalFlags;
|
||||
}
|
||||
|
||||
protected int getUnplayedMoves(MoveMethod method) {
|
||||
return unplayedMoves[method.ordinal()];
|
||||
}
|
||||
|
||||
|
||||
// check for flags which can be determined to be wrong
|
||||
protected boolean validateData() {
|
||||
|
||||
for (int i=0; i < width; i++) {
|
||||
for (int j=0; j < height; j++) {
|
||||
|
||||
// if there is an unconfirmed flag on the board but the solver
|
||||
// thinks it is clear then the flag is wrong
|
||||
if (isUnconfirmedFlag(i,j) && action[i][j] != null && action[i][j].getAction() == Action.CLEAR) {
|
||||
getLogger().log(Level.INFO, "Flag in Error at (%d, %d) confirmed CLEAR", i, j);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isRevealed(i,j) && getWitnessValue(i,j) != 0) {
|
||||
int flags = countAllFlags(i,j);
|
||||
|
||||
// if we have too many flags by a revealed square then a mistake has been made
|
||||
if (getWitnessValue(i,j) < flags) {
|
||||
getLogger().log(Level.INFO, "Flag in Error at witness (%d, %d) Overloads: Flags %d" ,i, j, flags);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the board is consider high mine density
|
||||
* @return
|
||||
*/
|
||||
public boolean isHighDensity() {
|
||||
|
||||
int minesLeft = getMines() - getConfirmedMineCount();
|
||||
int tilesLeft = getTotalUnrevealedCount();
|
||||
|
||||
return (minesLeft * 5 > tilesLeft * 2) && Solver.CONSIDER_HIGH_DENSITY_STRATEGY;
|
||||
}
|
||||
|
||||
|
||||
public int getTestMoveBalance() {
|
||||
return this.testMoveBalance;
|
||||
}
|
||||
|
||||
protected Logger getLogger() {
|
||||
return solver.logger;
|
||||
}
|
||||
|
||||
//protected void display(String text) {
|
||||
// solver.display(text);
|
||||
//}
|
||||
|
||||
protected Solver getSolver() {
|
||||
return solver;
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user