rename references

This commit is contained in:
2023-09-28 20:24:18 +08:00
parent 50b5f8c2c1
commit 0be2781d70
274 changed files with 0 additions and 0 deletions

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry combineaccessrules="false" kind="src" path="/MineSweeperSolver"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="output" path="bin"/>
</classpath>

View File

@ -0,0 +1 @@
/bin/

View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>MinesweeperBulk</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.xtext.ui.shared.xtextBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.xtext.ui.shared.xtextNature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

View File

@ -0,0 +1,11 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
org.eclipse.jdt.core.compiler.compliance=1.8
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
org.eclipse.jdt.core.compiler.debug.localVariable=generate
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.source=1.8

View File

@ -0,0 +1,79 @@
package minesweeperbulk;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import minesweeper.gamestate.GameStateModel;
import minesweeper.solver.bulk.BulkRequest;
import minesweeper.solver.bulk.GamePostListener;
public class EfficiencyMonitor extends GamePostListener {
private final Map<Integer, Integer> table = new HashMap<>();
private int eff100 = 0;
private int wins = 0;
private int played = 0;
private int announcementCount = 0;
private int clicks = 0;
private final double reportThreshold;
public EfficiencyMonitor(double reportThreshold) {
this.reportThreshold = reportThreshold;
}
@Override
public void postAction(BulkRequest request) {
GameStateModel game = request.getGame();
played++;
clicks = clicks + game.getActionCount();
if (game.getGameState() == GameStateModel.WON) {
wins++;
double efficiency = 100 * ((double) game.getTotal3BV() / (double) game.getActionCount());
if (efficiency >= reportThreshold) {
announcementCount++;
System.out.println(announcementCount + ") " + game.getSeed() + " has 3BV " + game.getTotal3BV() + " efficiency " + efficiency);
}
int inteff = (int) Math.floor(efficiency);
if (inteff >= 100) {
eff100++;
}
if (inteff >= 0) {
if (table.containsKey(inteff)) {
int tally = table.get(inteff);
tally++;
table.put(inteff, tally);
} else {
table.put(inteff, 1);
}
}
}
}
public void postResults() {
int clicksPerEff100 = 0;
if (eff100 > 0) {
clicksPerEff100 = clicks / eff100;
}
System.out.println("Efficiency >= 100% : " + eff100 + " from " + wins + " wins out of " + played + " played, clicks " + clicks + ", clicks/eff100 " + clicksPerEff100);
List<Integer> results = new ArrayList<>(table.keySet());
results.sort(null);
for (int key: results) {
System.out.println("Efficiency " + key + " occurs " + table.get(key));
}
}
}

View File

@ -0,0 +1,119 @@
package minesweeperbulk;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import minesweeper.gamestate.GameStateModel;
import minesweeper.solver.bulk.BulkRequest;
import minesweeper.solver.bulk.GamePostListener;
public class GuessMonitor extends GamePostListener {
private static final DecimalFormat MASK = new DecimalFormat("#0.000");
private class GuessData {
private int total;
private int sum3BV;
private int[] values = new int[9];
}
private final Map<Integer, GuessData> winTable = new HashMap<>();
private final Map<Integer, GuessData> loseTable = new HashMap<>();
private int wins = 0;
private int played = 0;
private int eights = 0;
private int ng8 = 0;
@Override
public void postAction(BulkRequest request) {
GameStateModel game = request.getGame();
played++;
Map<Integer, GuessData> table;
if (game.getGameState() == GameStateModel.WON) {
table = winTable;
wins++;
} else {
table = loseTable;
}
int guesses = request.getGuesses();
eights = eights + request.getGame().getValueCount(8);
if (request.getGame().getGameState() == GameStateModel.WON && request.getGuesses() == 0) {
ng8 = ng8 + + request.getGame().getValueCount(8);
}
if (table.containsKey(guesses)) {
GuessData gd = table.get(guesses);
gd.total++;
gd.sum3BV = gd.sum3BV + request.getGame().getTotal3BV();
for (int i=0; i < gd.values.length; i++) {
gd.values[i] += request.getGame().getValueCount(i);
}
table.put(guesses, gd);
} else {
GuessData gd = new GuessData();
gd.total = 1;
gd.sum3BV = request.getGame().getTotal3BV();
table.put(guesses, gd);
}
}
@Override
public void postResults() {
System.out.println(wins + " wins out of " + played + " played");
System.out.println(eights + " Eights, of which " + ng8 + " in no-guess games");
List<Integer> winResults = new ArrayList<>(winTable.keySet());
winResults.sort(null);
int winWeight = 0;
System.out.println("Histogram of guesses to win");
for (int key: winResults) {
GuessData gd = winTable.get(key);
double avg3BV = (double) gd.sum3BV / (double) gd.total;
System.out.println("guesses " + key + " occurs " + gd.total + " average 3bv " + MASK.format(avg3BV) + " number of 8's " + gd.values[8]);
winWeight = winWeight + gd.total * key;
}
if (wins != 0) {
double avgGuessesToWin = (double) winWeight / (double) wins;
System.out.println("Average guesses to win " + MASK.format(avgGuessesToWin));
}
List<Integer> loseResults = new ArrayList<>(loseTable.keySet());
loseResults.sort(null);
int loseWeight = 0;
System.out.println("Histogram of guesses to lose");
for (int key: loseResults) {
GuessData gd = loseTable.get(key);
double avg3BV = (double) gd.sum3BV / (double) gd.total;
System.out.println("guesses " + key + " occurs " + gd.total + " average 3bv " + MASK.format(avg3BV) + " number of 8's " + gd.values[8]);
loseWeight = loseWeight + gd.total * key;
}
if (wins != 0) {
double avgGuessesToLose = (double) loseWeight / (double) (played - wins) ;
System.out.println("Average guesses to lose " + MASK.format(avgGuessesToLose));
}
}
}

View File

@ -0,0 +1,195 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package minesweeperbulk;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import minesweeper.settings.GameSettings;
import minesweeper.settings.GameType;
import minesweeper.solver.bulk.BulkEvent;
import minesweeper.solver.bulk.BulkListener;
import minesweeper.solver.bulk.BulkPlayer;
import minesweeper.solver.bulk.GamePostListener;
import minesweeper.solver.settings.PlayStyle;
import minesweeper.solver.settings.SettingsFactory;
import minesweeper.solver.settings.SettingsFactory.Setting;
import minesweeper.solver.settings.SolverSettings;
import minesweeper.solver.utility.Timer;
import minesweeper.structure.Action;
import minesweeper.structure.Location;
/**
*
* @author David
*/
public class MinesweeperBulk {
private static final DecimalFormat MASK = new DecimalFormat("#0.000");
private static final DecimalFormat MASK5DP = new DecimalFormat("#0.000000");
public static void main(String[] args) {
// pick a random seed or override with a previously used seed to play the same sequence of games again.
long seed = (new Random()).nextInt();
seed = 1449234571;
//seed = 662429271; // expert 10,000,000 run
System.out.println("Seed is " + seed);
Random seeder = new Random(seed);
GameSettings gameSettings = GameSettings.EXPERT;
//GameSettings gameSettings = GameSettings.create(100, 100, 2400);
SolverSettings settings = SettingsFactory.GetSettings(Setting.SMALL_ANALYSIS);
settings.setSingleThread(true);
//settings.setStartLocation(new Location(15,7));
//settings.set5050Check(false);
//settings.setTieBreak(false);
//settings.setTestMode(true);
//settings.setLongTermSafety(false);
//settings.setProgressContribution(new BigDecimal("0.02"));
final long bulkSeed = seed;
BulkPlayer controller = new BulkPlayer(seeder, 100000, GameType.STANDARD, gameSettings, settings, 10, 10000);
controller.setPlayStyle(PlayStyle.NO_FLAG);
// this is executed before the game is passed to the solver
//controller.registerPreGameListener(new StartStrategyResign(middle4CornerStart(gameSettings), 5));
//controller.registerPreGameListener(new StartStrategy(fourCornerStart(gameSettings), 5));
//RandomGuesser random = new RandomGuesser(gameSettings);
//controller.registerPreGameListener(random);
//EfficiencyMonitor monitor = new EfficiencyMonitor(140);
GamePostListener monitor = new GuessMonitor();
controller.registerPostGameListener(monitor);
controller.registerEventListener(new BulkListener() {
@Override
public void intervalAction(BulkEvent event) {
//double p = (double) event.getGamesWon() / (double) event.getGamesPlayed();
double p = event.getTotalGamesValue().doubleValue() / (double) event.getGamesPlayed();
double err = Math.sqrt(p * ( 1- p) / (double) event.getGamesPlayed()) * 1.9599d;
System.out.println("Seed: " + bulkSeed + ", Played " + event.getGamesPlayed() + " of " + event.getGamesToPlay() + ", failed to start " + event.getFailedToStart() + ", won " + event.getTotalGamesValue().setScale(4, RoundingMode.HALF_UP) +
", without guessing " + event.getNoGuessWins() + ", guesses " + event.getTotalGuesses() + ", actions " + event.getTotalActions() + ", solved 3BV " + event.getTotal3BVSolved() +
", fairness " + MASK5DP.format(event.getFairness()) + ", win streak " + event.getWinStreak() + ", mastery " + event.getMastery() +
", win percentage " + MASK.format(p * 100) + " +/- " + MASK.format(err * 100) + ", Time left " + Timer.humanReadable(event.getEstimatedTimeLeft()) );
}
});
controller.run();
// 4394503940621334 3495601381446703 2878438628482118
// 3bv 5 ==> 3507948847220847 2378685257559362 732083917567661 3393825076821824 1423288336267551
{
BulkEvent event = controller.getResults();
double p = (double) event.getGamesWon() / (double) event.getGamesPlayed();
double err = Math.sqrt(p * ( 1- p) / (double) event.getGamesPlayed()) * 1.9599d;
int apw;
if (event.getGamesWon() != 0) {
apw = event.getTotalActions() / event.getGamesWon();
} else {
apw = 0;
}
double bpw;
if (event.getGamesWon() != 0) {
bpw = (double) event.getTotal3BVSolved() / (double) event.getGamesWon();
} else {
bpw = 0;
}
double average3BV = (double) event.getTotal3BV() / (double) event.getGamesPlayed();
System.out.println("Seed: " + bulkSeed + " ==> Board " + gameSettings + " ==> Played " + event.getGamesPlayed() + ", failed to start " + event.getFailedToStart() + ", won " + event.getGamesWon() +
", without guessing " + event.getNoGuessWins() + ", guesses " + event.getTotalGuesses() + ", actions " + event.getTotalActions() + ", apw " + apw +
", avg 3BV " + MASK.format(average3BV) + ", Solved 3BV/win " + MASK.format(bpw) +
", fairness " + MASK5DP.format(event.getFairness()) + ", win streak " + event.getWinStreak() + ", mastery " + event.getMastery() +
", win percentage " + MASK.format(p * 100) + " +/- " + MASK.format(err * 100) + ", Duration " + Timer.humanReadable(event.getTimeSoFar()) );
}
monitor.postResults();
//random.displayTable();
}
static private List<Action> twoCornerStart(GameSettings gameSettings) {
List<Action> preactions = new ArrayList<>();
preactions.add(new Action(0, 0, Action.CLEAR));
preactions.add(new Action(0, gameSettings.height - 1, Action.CLEAR));
//preactions.add(new Action(gameSettings.width - 1, 0, Action.CLEAR));
//preactions.add(new Action(gameSettings.width - 1, gameSettings.height - 1, Action.CLEAR));
return preactions;
}
static private List<Action> threeCornerStart(GameSettings gameSettings) {
List<Action> preactions = new ArrayList<>();
preactions.add(new Action(0, 0, Action.CLEAR));
preactions.add(new Action(0, gameSettings.height - 1, Action.CLEAR));
preactions.add(new Action(gameSettings.width - 1, 0, Action.CLEAR));
//preactions.add(new Action(gameSettings.width - 1, gameSettings.height - 1, Action.CLEAR));
return preactions;
}
static private List<Action> fourCornerStart(GameSettings gameSettings) {
List<Action> preactions = new ArrayList<>();
preactions.add(new Action(0, 0, Action.CLEAR));
preactions.add(new Action(0, gameSettings.height - 1, Action.CLEAR));
preactions.add(new Action(gameSettings.width - 1, 0, Action.CLEAR));
preactions.add(new Action(gameSettings.width - 1, gameSettings.height - 1, Action.CLEAR));
return preactions;
}
static private List<Action> middle4CornerStart(GameSettings gameSettings) {
List<Action> preactions = new ArrayList<>();
preactions.add(new Action(gameSettings.width / 2, gameSettings.height / 2, Action.CLEAR));
preactions.add(new Action(0, 0, Action.CLEAR));
preactions.add(new Action(0, gameSettings.height - 1, Action.CLEAR));
preactions.add(new Action(gameSettings.width - 1, 0, Action.CLEAR));
preactions.add(new Action(gameSettings.width - 1, gameSettings.height - 1, Action.CLEAR));
return preactions;
}
static private List<Action> flagClickChord(GameSettings gameSettings) {
List<Action> preactions = new ArrayList<>();
preactions.add(new Action(1, 3, Action.FLAG));
preactions.add(new Action(1, 2, Action.CLEAR));
preactions.add(new Action(1, 2, Action.CLEARALL));
preactions.add(new Action(1, 3, Action.FLAG));
return preactions;
}
}

View File

@ -0,0 +1,30 @@
package minesweeperbulk;
import java.util.List;
import minesweeper.gamestate.GameStateModel;
import minesweeper.solver.bulk.GamePreListener;
import minesweeper.structure.Action;
public class PreActions extends GamePreListener {
private List<Action> preActions;
public PreActions(List<Action> preActions) {
this.preActions = preActions;
}
@Override
public void preAction(GameStateModel game) {
for (Action a: preActions) {
game.doAction(a);
if (game.getGameState() == GameStateModel.LOST || game.getGameState() == GameStateModel.WON) {
break;
}
}
}
}

View File

@ -0,0 +1,131 @@
package minesweeperbulk;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import minesweeper.gamestate.GameStateModel;
import minesweeper.settings.GameSettings;
import minesweeper.solver.bulk.GamePreListener;
import minesweeper.structure.Action;
public class RandomGuesser extends GamePreListener {
final private GameSettings settings;
final private int border = 1;
final List<Action> interior = new ArrayList<>();
final Action[][] board;
private int eights = 0;
private int clicks = 0;
private int played = 0;
public RandomGuesser(GameSettings settings) {
this.settings = settings;
board = new Action[settings.width][settings.height];
for (int i=border; i < settings.width - border; i++) {
for (int j=border; j < settings.height - border; j++) {
Action a = new Action(i,j, Action.CLEAR);
interior.add(a);
board[i][j] = a;
}
}
}
@Override
public void preAction(GameStateModel game) {
played++;
// tiles we can guess shuffled
List<Action> available = new ArrayList<>(interior);
Collections.shuffle(available);
boolean[][] processed = new boolean[settings.width][settings.height];
// first guess
Action guess = available.get(0);
// while we have moves and the game hasn't blasted
while (true) {
clicks++;
game.doAction(guess);
// if we've lost stop
if (game.getGameState() == GameStateModel.LOST) {
break;
}
if (game.query(guess) == 8) {
eights++;
}
// remove guesses near cleared tiles
for (int i=border; i < settings.width - border; i++) {
for (int j=border; j < settings.height - border; j++) {
if (!processed[i][j]) {
if (game.query(board[i][j]) != GameStateModel.HIDDEN) {
//System.out.println(i + " " + j + " is not hidden");
processed[i][j] = true;
int offset;
if (game.query(guess) < 3) {
offset = 2;
} else {
offset = 1;
}
// remove tiles adjacent to an open area
Iterator<Action> iterator = available.iterator();
while (iterator.hasNext()) {
Action a = iterator.next();
if (distance(a.x, a.y, i, j) <= offset) {
iterator.remove();
}
}
}
}
}
}
if (available.isEmpty()) {
//System.out.println("No guesses left");
break;
}
// next guess
guess = available.get(0);
}
}
private int distance(int x1, int y1, int x2, int y2) {
int dx = Math.abs(x1 - x2);
int dy = Math.abs(y1 - y2);
return Math.max(dx, dy);
}
public void displayTable() {
System.out.println(eights + " eights out of " + played + " played and " + clicks + " clicks");
}
}

View File

@ -0,0 +1,54 @@
package minesweeperbulk;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import minesweeper.gamestate.GameStateModel;
import minesweeper.solver.bulk.BulkRequest;
import minesweeper.solver.bulk.GamePostListener;
public class RemainingMonitor extends GamePostListener {
private final Map<Integer, Integer> table = new HashMap<>();
private int wins = 0;
private int played = 0;
@Override
public void postAction(BulkRequest request) {
GameStateModel game = request.getGame();
played++;
if (game.getGameState() == GameStateModel.WON) {
wins++;
}
int bbvLeft = game.getTotal3BV() - game.getCleared3BV();
int tilesLeft = game.getHidden() - game.getMines();
if (table.containsKey(tilesLeft)) {
int tally = table.get(tilesLeft);
tally++;
table.put(tilesLeft, tally);
} else {
table.put(tilesLeft, 1);
}
}
public void postResults() {
System.out.println(wins + " wins out of " + played + " played");
List<Integer> results = new ArrayList<>(table.keySet());
results.sort(null);
for (int key: results) {
System.out.println("Tiles left to clear " + key + " occurs " + table.get(key));
}
}
}

View File

@ -0,0 +1,46 @@
package minesweeperbulk;
import java.util.List;
import minesweeper.gamestate.GameStateModel;
import minesweeper.solver.bulk.GamePreListener;
import minesweeper.structure.Action;
public class StartStrategy extends GamePreListener {
private List<Action> preActions;
private int requiredZeros;
/**
* Play the strategy until the required number of zeros has been found
*/
public StartStrategy(List<Action> preActions, int requiredZeros) {
this.preActions = preActions;
this.requiredZeros = requiredZeros;
}
@Override
public void preAction(GameStateModel game) {
int zeros = 0;
int actionCount = 0;
for (Action a: preActions) {
game.doAction(a);
actionCount++;
if (game.getGameState() == GameStateModel.LOST || game.getGameState() == GameStateModel.WON) {
break;
}
if (game.query(a) == 0) {
zeros++;
if (zeros >= requiredZeros) {
break;
}
}
}
}
}

View File

@ -0,0 +1,50 @@
package minesweeperbulk;
import java.util.List;
import minesweeper.gamestate.GameStateModel;
import minesweeper.solver.bulk.GamePreListener;
import minesweeper.structure.Action;
public class StartStrategyResign extends GamePreListener {
private List<Action> preActions;
private int requiredZeros;
/**
* Play the strategy until the required number of zeros has been found. If first guess isn't a zero then resign
*/
public StartStrategyResign(List<Action> preActions, int requiredZeros) {
this.preActions = preActions;
this.requiredZeros = requiredZeros;
}
@Override
public void preAction(GameStateModel game) {
int zeros = 0;
int actionCount = 0;
for (Action a: preActions) {
game.doAction(a);
actionCount++;
if (game.getGameState() == GameStateModel.LOST || game.getGameState() == GameStateModel.WON) {
break;
}
if (actionCount == 1 && game.query(a) != 0) {
game.resign();
break;
}
if (game.query(a) == 0) {
zeros++;
if (zeros >= requiredZeros) {
break;
}
}
}
}
}