rename references
8
references/Minesweeper/Minesweeper/.classpath
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
|
||||
<classpathentry combineaccessrules="false" kind="src" path="/WindowController"/>
|
||||
<classpathentry combineaccessrules="false" kind="src" path="/MineSweeperSolver"/>
|
||||
<classpathentry kind="output" path="bin"/>
|
||||
</classpath>
|
2
references/Minesweeper/Minesweeper/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
/bin/
|
||||
/build/
|
23
references/Minesweeper/Minesweeper/.project
Normal file
@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>Minesweeper</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>
|
@ -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
|
8
references/Minesweeper/Minesweeper/build.fxbuild
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="ASCII"?>
|
||||
<anttasks:AntTask xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:anttasks="http://org.eclipse.fx.ide.jdt/1.0" buildDirectory="${project}/build">
|
||||
<deploy>
|
||||
<application name="Minesweeper"/>
|
||||
<info/>
|
||||
</deploy>
|
||||
<signjar/>
|
||||
</anttasks:AntTask>
|
@ -0,0 +1,88 @@
|
||||
/*
|
||||
* To change this template, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package minesweeper;
|
||||
|
||||
import javafx.application.Platform;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author David
|
||||
*/
|
||||
public class Animator implements Runnable{
|
||||
|
||||
private Thread animator;
|
||||
|
||||
private ScreenController scon;
|
||||
|
||||
private boolean stopped = false;
|
||||
private long gameTime = 0;
|
||||
|
||||
public Animator(ScreenController scon) {
|
||||
|
||||
this.scon = scon;
|
||||
|
||||
// start animating the display pane - see the run method
|
||||
animator = new Thread(this, "Animator");
|
||||
|
||||
}
|
||||
|
||||
public void start() {
|
||||
|
||||
animator.start();
|
||||
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
|
||||
stopped = true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
long timeDiff, sleep, timeDelay;
|
||||
|
||||
timeDelay = 50;
|
||||
|
||||
gameTime = System.currentTimeMillis();
|
||||
|
||||
while (!stopped) {
|
||||
|
||||
Platform.runLater(new Runnable() {
|
||||
@Override public void run() {
|
||||
scon.updateTime();
|
||||
scon.moveCheck();
|
||||
scon.highlightMove();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// calculate how long the work took
|
||||
timeDiff = System.currentTimeMillis() - gameTime;
|
||||
|
||||
// pause for the ramainder of timeDelay
|
||||
sleep = timeDelay - timeDiff;
|
||||
|
||||
if (sleep < 0) {
|
||||
sleep = 2;
|
||||
}
|
||||
|
||||
try {
|
||||
Thread.sleep(sleep);
|
||||
} catch (InterruptedException e) {
|
||||
System.out.println("interrupted");
|
||||
}
|
||||
|
||||
gameTime += timeDelay;
|
||||
|
||||
}
|
||||
|
||||
System.out.println("Animator thread stopped");
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import javafx.scene.effect.*?>
|
||||
<?import javafx.scene.control.*?>
|
||||
<?import java.lang.*?>
|
||||
<?import javafx.scene.layout.*?>
|
||||
<?import javafx.scene.layout.AnchorPane?>
|
||||
|
||||
<AnchorPane fx:id="window" prefHeight="169.0" prefWidth="240.0" stylesheets="@Screen.css" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="minesweeper.CustomController">
|
||||
<children>
|
||||
<TextField fx:id="heightText" alignment="CENTER_RIGHT" layoutX="68.0" layoutY="29.0" prefHeight="25.0" prefWidth="49.0">
|
||||
<effect>
|
||||
<DropShadow />
|
||||
</effect>
|
||||
</TextField>
|
||||
<Label layoutX="15.0" layoutY="65.0" text="Width" />
|
||||
<Label layoutX="13.0" layoutY="33.0" text="Height" />
|
||||
<Label layoutX="15.0" layoutY="98.0" text="Mines" />
|
||||
<TextField fx:id="widthText" alignment="CENTER_RIGHT" layoutX="68.0" layoutY="61.0" prefHeight="25.0" prefWidth="49.0">
|
||||
<effect>
|
||||
<DropShadow />
|
||||
</effect>
|
||||
</TextField>
|
||||
<TextField fx:id="minesText" alignment="CENTER_RIGHT" layoutX="68.0" layoutY="94.0" prefHeight="25.0" prefWidth="49.0">
|
||||
<effect>
|
||||
<DropShadow />
|
||||
</effect>
|
||||
</TextField>
|
||||
<Label layoutX="13.0" layoutY="6.0" prefHeight="17.0" prefWidth="137.0" text="Choose custom settings" />
|
||||
<Button layoutX="135.0" layoutY="29.0" mnemonicParsing="false" onAction="#handleOkayButton" prefHeight="25.0" prefWidth="78.0" text="Okay" textAlignment="CENTER">
|
||||
<effect>
|
||||
<InnerShadow />
|
||||
</effect>
|
||||
</Button>
|
||||
<Button layoutX="135.0" layoutY="61.0" mnemonicParsing="false" onAction="#handleCancelButton" prefHeight="25.0" prefWidth="78.0" text="Cancel">
|
||||
<effect>
|
||||
<InnerShadow />
|
||||
</effect>
|
||||
</Button>
|
||||
<Label layoutX="11.0" layoutY="132.0" text="Game #" />
|
||||
<TextField fx:id="gameCodeText" layoutX="68.0" layoutY="128.0">
|
||||
<effect>
|
||||
<DropShadow />
|
||||
</effect>
|
||||
</TextField>
|
||||
</children>
|
||||
</AnchorPane>
|
@ -0,0 +1,230 @@
|
||||
package minesweeper;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.event.EventHandler;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.fxml.FXMLLoader;
|
||||
import javafx.fxml.Initializable;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.Parent;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.control.TextField;
|
||||
import javafx.scene.layout.AnchorPane;
|
||||
import javafx.stage.Modality;
|
||||
import javafx.stage.Stage;
|
||||
import javafx.stage.Window;
|
||||
import javafx.stage.WindowEvent;
|
||||
import minesweeper.coach.HelperController;
|
||||
import minesweeper.gamestate.GameStateModel;
|
||||
import minesweeper.settings.GameSettings;
|
||||
|
||||
public class CustomController {
|
||||
|
||||
@FXML
|
||||
private AnchorPane window;
|
||||
|
||||
@FXML private TextField heightText;
|
||||
@FXML private TextField widthText;
|
||||
@FXML private TextField minesText;
|
||||
@FXML private TextField gameCodeText;
|
||||
|
||||
|
||||
private Stage stage;
|
||||
private Scene scene;
|
||||
|
||||
private int height;
|
||||
private int width;
|
||||
private int mines;
|
||||
private GameSettings gameSettings;
|
||||
|
||||
private long gameCode;
|
||||
|
||||
private static CustomController custom;
|
||||
|
||||
private boolean wasCancelled = false;
|
||||
|
||||
/**
|
||||
* Initializes the controller class.
|
||||
*/
|
||||
/*
|
||||
@Override
|
||||
public void initialize(URL url, ResourceBundle rb) {
|
||||
|
||||
System.out.println("Entered Custom Control initialize method");
|
||||
}
|
||||
*/
|
||||
|
||||
@FXML
|
||||
void initialize() {
|
||||
System.out.println("Entered Custom Control initialize method");
|
||||
|
||||
if (heightText == null) {
|
||||
System.out.println("heightText is null");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@FXML
|
||||
private void handleOkayButton(ActionEvent event) {
|
||||
|
||||
this.mines = StringToInteger(minesText.getText(), 1, 20000, this.mines);
|
||||
this.width = StringToInteger(widthText.getText(), 2, 200, this.width);
|
||||
this.height = StringToInteger(heightText.getText(), 2, 200, this.height);
|
||||
|
||||
try {
|
||||
this.gameCode = Long.parseLong(gameCodeText.getText());
|
||||
} catch (NumberFormatException e) {
|
||||
this.gameCode = 0;
|
||||
}
|
||||
|
||||
if (mines > width * height - 1) {
|
||||
mines = width * height - 1;
|
||||
}
|
||||
|
||||
gameSettings = GameSettings.create(width, height, mines);
|
||||
|
||||
stage.close();
|
||||
|
||||
}
|
||||
|
||||
@FXML
|
||||
private void handleCancelButton(ActionEvent event) {
|
||||
|
||||
wasCancelled = true;
|
||||
stage.close();
|
||||
|
||||
}
|
||||
|
||||
|
||||
public static CustomController launch(Window owner, GameStateModel game) {
|
||||
|
||||
|
||||
|
||||
// if we have already created it then show it and return
|
||||
if (custom != null) {
|
||||
//custom.stage.show();
|
||||
custom.wasCancelled = false;
|
||||
return custom;
|
||||
}
|
||||
|
||||
if (CustomController.class.getResource("Custom.fxml") == null) {
|
||||
System.out.println("Custom.fxml not found");
|
||||
}
|
||||
|
||||
// create the helper screen
|
||||
FXMLLoader loader = new FXMLLoader(CustomController.class.getResource("Custom.fxml"));
|
||||
|
||||
Parent root = null;
|
||||
try {
|
||||
root = (Parent) loader.load();
|
||||
} catch (IOException ex) {
|
||||
System.err.println(ex.getMessage());
|
||||
}
|
||||
|
||||
custom = loader.getController();
|
||||
|
||||
//helperController = loader.getController();
|
||||
|
||||
if (custom == null) {
|
||||
System.out.println("Custom is null");
|
||||
}
|
||||
|
||||
if (root == null) {
|
||||
System.out.println("Root is null");
|
||||
}
|
||||
|
||||
custom.scene = new Scene(root);
|
||||
|
||||
custom.stage = new Stage();
|
||||
|
||||
custom.stage.setScene(custom.scene);
|
||||
custom.stage.setTitle("Custom board");
|
||||
|
||||
custom.stage.getIcons().add(Graphics.getMine());
|
||||
|
||||
custom.stage.setResizable(false);
|
||||
|
||||
custom.stage.initOwner(owner);
|
||||
custom.stage.initModality(Modality.WINDOW_MODAL);
|
||||
|
||||
custom.width = game.getWidth();
|
||||
custom.height = game.getHeight();
|
||||
custom.mines = game.getMines();
|
||||
|
||||
custom.widthText.setText(String.valueOf(custom.width));
|
||||
custom.heightText.setText(String.valueOf(custom.height));
|
||||
custom.minesText.setText(String.valueOf(custom.mines));
|
||||
|
||||
//Stage st = Minesweeper.getStage();
|
||||
//custom.stage.setX(st.getX()+ st.getWidth());
|
||||
//custom.stage.setY(st.getY());
|
||||
|
||||
custom.stage.setOnCloseRequest(new EventHandler<WindowEvent>() {
|
||||
|
||||
@Override
|
||||
public void handle(WindowEvent event) {
|
||||
System.out.println("Entered OnCloseRequest handler");
|
||||
custom.wasCancelled = true;
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
||||
return custom;
|
||||
}
|
||||
|
||||
private int StringToInteger(String text, int min, int max, int dflt) {
|
||||
|
||||
int val = dflt;
|
||||
try {
|
||||
val = Integer.parseInt(text);
|
||||
} catch (NumberFormatException e) {
|
||||
}
|
||||
|
||||
val = Math.max(val, min);
|
||||
val = Math.min(val, max);
|
||||
|
||||
return val;
|
||||
|
||||
}
|
||||
|
||||
|
||||
public static CustomController getCustomController() {
|
||||
return custom;
|
||||
}
|
||||
|
||||
public Stage getStage() {
|
||||
return this.stage;
|
||||
}
|
||||
|
||||
public GameSettings getGameSettings() {
|
||||
return this.gameSettings;
|
||||
}
|
||||
|
||||
|
||||
public int getMines() {
|
||||
return this.mines;
|
||||
}
|
||||
|
||||
public int getWidth() {
|
||||
return this.width;
|
||||
}
|
||||
|
||||
public int getHeight() {
|
||||
return this.height;
|
||||
}
|
||||
|
||||
public long getGameCode() {
|
||||
return this.gameCode;
|
||||
}
|
||||
|
||||
public boolean wasCancelled() {
|
||||
return wasCancelled;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,83 @@
|
||||
/*
|
||||
* To change this template, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package minesweeper;
|
||||
|
||||
import javafx.scene.image.Image;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author David
|
||||
*/
|
||||
public class Graphics {
|
||||
|
||||
public static final double SIZE = 50;
|
||||
|
||||
|
||||
private static final Image button;
|
||||
private static final Image mineBang;
|
||||
private static final Image flag;
|
||||
private static final Image[] number = new Image[9];
|
||||
private static final Image mine;
|
||||
|
||||
|
||||
static {
|
||||
|
||||
button = clean(new Image(Graphics.class.getResource("resources/ms_button.png").toExternalForm(), SIZE, SIZE, true, true));
|
||||
mineBang = clean(new Image(Graphics.class.getResource("resources/ms_mine_bang.png").toExternalForm(), SIZE, SIZE, true, true));
|
||||
flag = clean(new Image(Graphics.class.getResource("resources/ms_flag.png").toExternalForm(), SIZE, SIZE, true, true));
|
||||
mine = clean(new Image(Graphics.class.getResource("resources/ms_mine.png").toExternalForm(), SIZE, SIZE, true, true));
|
||||
|
||||
number[0] = clean(new Image(Graphics.class.getResource("resources/ms_zero.png").toExternalForm(), SIZE, SIZE, true, true));
|
||||
number[1] = clean(new Image(Graphics.class.getResource("resources/ms_one.png").toExternalForm(), SIZE, SIZE, true, true));
|
||||
number[2] = clean(new Image(Graphics.class.getResource("resources/ms_two.png").toExternalForm(), SIZE, SIZE, true, true));
|
||||
number[3] = clean(new Image(Graphics.class.getResource("resources/ms_three.png").toExternalForm(), SIZE, SIZE, true, true));
|
||||
number[4] = clean(new Image(Graphics.class.getResource("resources/ms_four.png").toExternalForm(), SIZE, SIZE, true, true));
|
||||
number[5] = clean(new Image(Graphics.class.getResource("resources/ms_five.png").toExternalForm(), SIZE, SIZE, true, true));
|
||||
number[6] = clean(new Image(Graphics.class.getResource("resources/ms_six.png").toExternalForm(), SIZE, SIZE, true, true));
|
||||
number[7] = clean(new Image(Graphics.class.getResource("resources/ms_seven.png").toExternalForm(), SIZE, SIZE, true, true));
|
||||
number[8] = clean(new Image(Graphics.class.getResource("resources/ms_eight.png").toExternalForm(), SIZE, SIZE, true, true));
|
||||
|
||||
|
||||
}
|
||||
|
||||
static public Image getNumber(int c) {
|
||||
|
||||
return number[c];
|
||||
|
||||
}
|
||||
|
||||
static public Image getMineBang() {
|
||||
|
||||
return mineBang;
|
||||
|
||||
}
|
||||
|
||||
static public Image getMine() {
|
||||
|
||||
return mine;
|
||||
|
||||
}
|
||||
|
||||
static public Image getFlag() {
|
||||
|
||||
return flag;
|
||||
|
||||
}
|
||||
|
||||
static public Image getButton() {
|
||||
|
||||
return button;
|
||||
|
||||
}
|
||||
|
||||
// in case we want to do some image manipulation
|
||||
static private Image clean(Image image) {
|
||||
|
||||
return image;
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,247 @@
|
||||
/*
|
||||
* To change this template, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package minesweeper;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Optional;
|
||||
|
||||
import javafx.application.Application;
|
||||
import javafx.application.Platform;
|
||||
import javafx.event.EventHandler;
|
||||
import javafx.fxml.FXMLLoader;
|
||||
import javafx.scene.Parent;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.control.Alert;
|
||||
import javafx.scene.control.Alert.AlertType;
|
||||
import javafx.scene.control.ButtonType;
|
||||
import javafx.stage.Stage;
|
||||
import javafx.stage.WindowEvent;
|
||||
import minesweeper.gamestate.GameFactory;
|
||||
import minesweeper.gamestate.GameStateModel;
|
||||
import minesweeper.gamestate.GameStateModelViewer;
|
||||
import minesweeper.gamestate.GameStateReader;
|
||||
import minesweeper.gamestate.GameStateStandardWith8;
|
||||
import minesweeper.gamestate.msx.GameStateX;
|
||||
import minesweeper.gamestate.msx.ScreenScanner;
|
||||
import minesweeper.settings.GameSettings;
|
||||
import minesweeper.settings.GameType;
|
||||
import minesweeper.solver.Solver;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author David
|
||||
*/
|
||||
public class Minesweeper extends Application {
|
||||
|
||||
public final static String VERSION = "1.04b";
|
||||
|
||||
public static final String TITLE = "Minesweeper coach (" + VERSION + ") Solver version " + Solver.VERSION;
|
||||
|
||||
private static GameStateModelViewer myGame;
|
||||
private static GameSettings gameSettings;
|
||||
|
||||
private static Stage myStage = null;
|
||||
|
||||
private static ScreenController myController;
|
||||
|
||||
|
||||
@Override
|
||||
public void start(Stage stage) throws Exception {
|
||||
|
||||
myStage = stage;
|
||||
|
||||
// this creates a hard game on start-up
|
||||
createNewGame(ScreenController.DIFFICULTY_EXPERT, GameType.STANDARD, null);
|
||||
|
||||
System.out.println("creating root");
|
||||
|
||||
FXMLLoader loader = new FXMLLoader(getClass().getResource("Screen.fxml"));
|
||||
|
||||
Parent root = (Parent) loader.load();
|
||||
|
||||
|
||||
myController = loader.getController();
|
||||
|
||||
System.out.println("root created");
|
||||
|
||||
Scene scene = new Scene(root);
|
||||
|
||||
stage.setScene(scene);
|
||||
stage.setTitle(TITLE);
|
||||
|
||||
stage.getIcons().add(Graphics.getMine());
|
||||
|
||||
stage.setX(50);
|
||||
stage.setY(50);
|
||||
|
||||
stage.setWidth(1000);
|
||||
stage.setHeight(650);
|
||||
|
||||
stage.show();
|
||||
|
||||
//stage.setResizable(false);
|
||||
|
||||
myController.newGame(ScreenController.DIFFICULTY_EXPERT);
|
||||
|
||||
stage.setOnHidden(null);
|
||||
|
||||
// actions to perform when a close request is received
|
||||
stage.setOnCloseRequest(new EventHandler<WindowEvent>() {
|
||||
@Override
|
||||
public void handle(WindowEvent event) {
|
||||
System.out.println("Minesweeper window has received a close request");
|
||||
//event.consume();
|
||||
myController.kill();
|
||||
Platform.exit();
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
// use the difficulty set in the menu system
|
||||
static public GameStateModel newGame() {
|
||||
|
||||
return createNewGame(myController.getDifficulty(), myController.getGameType(), null);
|
||||
|
||||
}
|
||||
|
||||
// force a difficulty setting
|
||||
static public GameStateModel createNewGame(int difficulty, GameType gameType, File fileSelected) {
|
||||
|
||||
long gameCode = 0;
|
||||
gameSettings = GameSettings.EXPERT;
|
||||
|
||||
switch (difficulty) {
|
||||
case ScreenController.DIFFICULTY_BEGINNER:
|
||||
gameSettings = GameSettings.BEGINNER;
|
||||
break;
|
||||
case ScreenController.DIFFICULTY_ADVANCED:
|
||||
gameSettings = GameSettings.ADVANCED;
|
||||
break;
|
||||
case ScreenController.DIFFICULTY_EXPERT:
|
||||
gameSettings = GameSettings.EXPERT;
|
||||
break;
|
||||
case ScreenController.DEFER_TO_MINESWEEPERX:
|
||||
ScreenScanner scanner = new ScreenScanner("Minesweeper X");
|
||||
if (!scanner.isValid()) {
|
||||
|
||||
System.out.println("MinsweeperX not found");
|
||||
Alert alert = new Alert(AlertType.ERROR, "MinesweeperX can't be found: ensure it is maximised and unobstructed");
|
||||
Optional<ButtonType> result = alert.showAndWait();
|
||||
if (result.isPresent() && result.get() == ButtonType.OK) {
|
||||
return myGame; // old game
|
||||
}
|
||||
|
||||
}
|
||||
myGame = new GameStateX(scanner);
|
||||
System.out.println("X = " + myGame.getWidth() + " Y =" + myGame.getHeight());
|
||||
break;
|
||||
case ScreenController.DIFFICULTY_FILE:
|
||||
GameStateModelViewer game;
|
||||
try {
|
||||
game = GameStateReader.load(fileSelected);
|
||||
myGame = game;
|
||||
} catch (Exception e) {
|
||||
Alert alert = new Alert(AlertType.ERROR, e.getLocalizedMessage());
|
||||
Optional<ButtonType> result = alert.showAndWait();
|
||||
return null;
|
||||
}
|
||||
break;
|
||||
case ScreenController.DIFFICULTY_CUSTOM:
|
||||
CustomController custom = CustomController.getCustomController();
|
||||
gameSettings = custom.getGameSettings();
|
||||
gameCode = custom.getGameCode();
|
||||
|
||||
break;
|
||||
default:
|
||||
gameSettings = GameSettings.EXPERT;
|
||||
}
|
||||
|
||||
// if we are shadowing minesweeperX then we don't need to do any more
|
||||
if (difficulty == ScreenController.DEFER_TO_MINESWEEPERX || difficulty == ScreenController.DIFFICULTY_FILE) {
|
||||
return myGame;
|
||||
}
|
||||
|
||||
|
||||
myGame = GameFactory.create(gameType, gameSettings, gameCode);
|
||||
//myGame = new GameStateStandardWith8(gameSettings);
|
||||
|
||||
/*
|
||||
switch (gameType) {
|
||||
case GameType.:
|
||||
|
||||
if (gameCode == 0) {
|
||||
myGame = new GameStateEasy(gameSettings);
|
||||
} else {
|
||||
myGame = new GameStateEasy(gameSettings, gameCode);
|
||||
}
|
||||
break;
|
||||
case ScreenController.GAMETYPE_NORMAL:
|
||||
if (gameCode == 0) {
|
||||
myGame = new GameStateStandard(gameSettings);
|
||||
} else {
|
||||
myGame = new GameStateStandard(gameSettings, gameCode);
|
||||
}
|
||||
break;
|
||||
case ScreenController.GAMETYPE_HARD:
|
||||
if (gameCode == 0) {
|
||||
myGame = new GameStateHard(gameSettings);
|
||||
} else {
|
||||
myGame = new GameStateHard(gameSettings, gameCode);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (gameCode == 0) {
|
||||
myGame = new GameStateStandard(gameSettings);
|
||||
} else {
|
||||
myGame = new GameStateStandard(gameSettings, gameCode);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
return myGame;
|
||||
|
||||
}
|
||||
|
||||
|
||||
static public GameStateModelViewer getGame() {
|
||||
return myGame;
|
||||
}
|
||||
|
||||
static public void playGame(GameStateModelViewer gs) {
|
||||
myGame = gs;
|
||||
myController.newGame(gs);
|
||||
}
|
||||
|
||||
|
||||
static public GameSettings getGameSettings() {
|
||||
return gameSettings;
|
||||
}
|
||||
|
||||
static public Stage getStage() {
|
||||
|
||||
return myStage;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
|
||||
myController.stop();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* The main() method is ignored in correctly deployed JavaFX application.
|
||||
* main() serves only as fallback in case the application can not be
|
||||
* launched through deployment artifacts, e.g., in IDEs with limited FX
|
||||
* support. NetBeans ignores main().
|
||||
*
|
||||
* @param args the command line arguments
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
launch(args);
|
||||
}
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* To change this template, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package minesweeper;
|
||||
|
||||
import javafx.scene.Node;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author David
|
||||
*/
|
||||
public class Rotator implements Runnable {
|
||||
|
||||
private Thread rotator;
|
||||
|
||||
Node object;
|
||||
|
||||
|
||||
public Rotator(Node object) {
|
||||
|
||||
this.object = object;
|
||||
|
||||
rotator = new Thread(this, "Rotator");
|
||||
|
||||
}
|
||||
|
||||
public void start() {
|
||||
|
||||
rotator.start();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
for (int i=0; i < 360; i=i+20) {
|
||||
|
||||
this.object.setRotate(i);
|
||||
|
||||
try {
|
||||
Thread.sleep(20);
|
||||
} catch (InterruptedException e) {
|
||||
System.out.println("interrupted");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
this.object.setRotate(0);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
/*
|
||||
Document : Screen
|
||||
Created on : 29-Nov-2013, 15:48:32
|
||||
Author : David
|
||||
Description:
|
||||
Purpose of the stylesheet follows.
|
||||
*/
|
||||
|
||||
.root {
|
||||
|
||||
-fx-background-color: linear-gradient(GREEN, DARKGREEN);
|
||||
|
||||
-fx-background-color: linear-gradient(#61a2b1, #2A5058);
|
||||
}
|
||||
|
||||
.menu-bar {
|
||||
|
||||
-fx-background-color: linear-gradient(#61a2b1, #2A5058);
|
||||
|
||||
}
|
||||
|
||||
|
||||
#myPane {
|
||||
|
||||
-fx-border-color: black;
|
||||
-fx-border-width: 1;
|
||||
-fx-border-style: solid outside;
|
||||
|
||||
}
|
||||
|
||||
#scoreLabel {
|
||||
|
||||
-fx-border-color: black;
|
||||
-fx-border-width: 1;
|
||||
-fx-border-style: solid outside;
|
||||
-fx-border-radius: 15;
|
||||
|
||||
}
|
||||
|
||||
#timeLabel {
|
||||
|
||||
-fx-border-color: black;
|
||||
-fx-border-width: 1;
|
||||
-fx-border-style: solid outside;
|
||||
-fx-border-radius: 15;
|
||||
|
||||
}
|
129
references/Minesweeper/Minesweeper/src/minesweeper/Screen.fxml
Normal file
@ -0,0 +1,129 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import java.lang.*?>
|
||||
<?import java.net.*?>
|
||||
<?import java.util.*?>
|
||||
<?import javafx.scene.*?>
|
||||
<?import javafx.scene.control.*?>
|
||||
<?import javafx.scene.layout.*?>
|
||||
<?import javafx.scene.shape.*?>
|
||||
<?import javafx.scene.text.*?>
|
||||
<?scenebuilder-stylesheet Screen.css?>
|
||||
|
||||
<AnchorPane id="AnchorPane" fx:id="window" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="424.0" prefWidth="591.0" style="-fx-background-color: green;" styleClass="mainFxmlClass" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="minesweeper.ScreenController">
|
||||
<children>
|
||||
<Pane fx:id="myPane" minWidth="-1.0" onMousePressed="#mouseDown" onMouseReleased="#mouseUp" pickOnBounds="true" prefHeight="261.0" prefWidth="455.0" style=" " AnchorPane.bottomAnchor="35.0" AnchorPane.leftAnchor="10.0" AnchorPane.rightAnchor="10.0" AnchorPane.topAnchor="70.0" />
|
||||
<MenuBar prefWidth="455.0" style="-fx-background-color: white;" stylesheets="@Screen.css" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<menus>
|
||||
<Menu mnemonicParsing="false" text="Game">
|
||||
<items>
|
||||
<RadioMenuItem id="easyMode" fx:id="easyMode" mnemonicParsing="false" onAction="#handleDifficulty" text="Easy (9x9x10)">
|
||||
<toggleGroup>
|
||||
<ToggleGroup fx:id="Difficulty" />
|
||||
</toggleGroup>
|
||||
</RadioMenuItem>
|
||||
<RadioMenuItem fx:id="mediumMode" mnemonicParsing="false" onAction="#handleDifficulty" text="Medium (16x16x40)" toggleGroup="$Difficulty" />
|
||||
<RadioMenuItem fx:id="hardMode" mnemonicParsing="false" onAction="#handleDifficulty" selected="true" text="Hard (30x16x99)" toggleGroup="$Difficulty" />
|
||||
<RadioMenuItem fx:id="msxMode" mnemonicParsing="false" onAction="#handleDifficulty" text="MinesweeperX" toggleGroup="$Difficulty" />
|
||||
<RadioMenuItem fx:id="fromFile" mnemonicParsing="false" onAction="#handleDifficulty" text="From file..." toggleGroup="$Difficulty" />
|
||||
<RadioMenuItem fx:id="customMode" mnemonicParsing="false" onAction="#handleDifficulty" text="Custom..." toggleGroup="$Difficulty" />
|
||||
<SeparatorMenuItem mnemonicParsing="false" text="Game type" />
|
||||
<Menu mnemonicParsing="false" text="Game type">
|
||||
<items>
|
||||
<RadioMenuItem fx:id="gameTypeEasy" mnemonicParsing="false" onAction="#handleGameType" text="Easy (zero on start)">
|
||||
<toggleGroup>
|
||||
<ToggleGroup fx:id="gameType" />
|
||||
</toggleGroup>
|
||||
</RadioMenuItem>
|
||||
<RadioMenuItem fx:id="gameTypeNormal" mnemonicParsing="false" onAction="#handleGameType" selected="true" text="Standard (safe start)" toggleGroup="$gameType" />
|
||||
<RadioMenuItem fx:id="gameTypeHard" mnemonicParsing="false" onAction="#handleGameType" text="Hard (unsafe start)" toggleGroup="$gameType" />
|
||||
</items>
|
||||
</Menu>
|
||||
<SeparatorMenuItem mnemonicParsing="false" />
|
||||
<MenuItem fx:id="saveBoard" mnemonicParsing="false" onAction="#saveBoardHandle" text="Save board..." />
|
||||
<SeparatorMenuItem mnemonicParsing="false" />
|
||||
<MenuItem mnemonicParsing="false" onAction="#exitGameHandle" text="Exit game" />
|
||||
</items>
|
||||
</Menu>
|
||||
<Menu mnemonicParsing="false" text="Coach">
|
||||
<items>
|
||||
<CheckMenuItem fx:id="showMove" mnemonicParsing="false" selected="true" text="Show best move" />
|
||||
<CheckMenuItem fx:id="showTooltips" mnemonicParsing="false" selected="true" text="Show tooltips" />
|
||||
<CheckMenuItem fx:id="acceptGuess" mnemonicParsing="false" selected="false" text="Accept guesses" />
|
||||
<CheckMenuItem fx:id="showMines" mnemonicParsing="false" onAction="#showMinesToggled" text="Show mines" />
|
||||
<CheckMenuItem fx:id="dumpTree" mnemonicParsing="false" onAction="#dumpTreeToggled" text="Dump probability tree" />
|
||||
<CheckMenuItem fx:id="probHeatMap" disable="true" mnemonicParsing="false" onAction="#probHeatMapToggled" text="Probability heat map" />
|
||||
</items>
|
||||
</Menu>
|
||||
<Menu mnemonicParsing="false" text="Options">
|
||||
<items>
|
||||
<MenuItem mnemonicParsing="false" onAction="#handleCopyToClipboard" text="Copy seed to clipboard" />
|
||||
<Menu mnemonicParsing="false" text="Play style">
|
||||
<items>
|
||||
<RadioMenuItem fx:id="psFlagging" mnemonicParsing="false" onAction="#setPlayStyle" selected="true" text="Flagging">
|
||||
<toggleGroup>
|
||||
<ToggleGroup fx:id="playStyle" />
|
||||
</toggleGroup>
|
||||
</RadioMenuItem>
|
||||
<RadioMenuItem fx:id="psNoFlagging" mnemonicParsing="false" onAction="#setPlayStyle" text="No flagging" toggleGroup="$playStyle" />
|
||||
<RadioMenuItem fx:id="psEfficiency" mnemonicParsing="false" onAction="#setPlayStyle" text="Efficiency" toggleGroup="$playStyle" />
|
||||
<RadioMenuItem fx:id="psNfEfficiency" mnemonicParsing="false" onAction="#setPlayStyle" text="No flag efficiency" toggleGroup="$playStyle" />
|
||||
</items>
|
||||
</Menu>
|
||||
<Menu mnemonicParsing="false" text="Guessing method">
|
||||
<items>
|
||||
<RadioMenuItem fx:id="standardGuess" mnemonicParsing="false" text="Safety with progress">
|
||||
<toggleGroup>
|
||||
<ToggleGroup fx:id="GuessType" />
|
||||
</toggleGroup>
|
||||
</RadioMenuItem>
|
||||
<RadioMenuItem fx:id="secondarySafetyGuess" mnemonicParsing="false" selected="true" text="Secondary safety with progress" toggleGroup="$GuessType" />
|
||||
</items>
|
||||
</Menu>
|
||||
<Menu mnemonicParsing="false" text="Random numbers">
|
||||
<items>
|
||||
<RadioMenuItem fx:id="rngJava" mnemonicParsing="false" selected="true" text="Java random numbers">
|
||||
<toggleGroup>
|
||||
<ToggleGroup fx:id="RNG" />
|
||||
</toggleGroup>
|
||||
</RadioMenuItem>
|
||||
<RadioMenuItem fx:id="rngKiss64" mnemonicParsing="false" text="KISS64 random numbers" toggleGroup="$RNG" />
|
||||
</items>
|
||||
</Menu>
|
||||
<Menu mnemonicParsing="false" text="Brute force analysis">
|
||||
<items>
|
||||
<RadioMenuItem fx:id="sol400" mnemonicParsing="false" text="400 solutions">
|
||||
<toggleGroup>
|
||||
<ToggleGroup fx:id="BFDA" />
|
||||
</toggleGroup>
|
||||
</RadioMenuItem>
|
||||
<RadioMenuItem fx:id="sol4000" mnemonicParsing="false" selected="true" text="4000 solutions" toggleGroup="$BFDA" />
|
||||
</items>
|
||||
</Menu>
|
||||
</items>
|
||||
</Menu>
|
||||
<Menu mnemonicParsing="false" text="Bulk run">
|
||||
<items>
|
||||
<MenuItem mnemonicParsing="false" onAction="#handleNewBulkRun" text="New bulk run..." />
|
||||
</items>
|
||||
</Menu>
|
||||
</menus>
|
||||
</MenuBar>
|
||||
<Label fx:id="scoreLabel" alignment="TOP_CENTER" layoutY="28.0" minHeight="24.0" prefHeight="37.0" prefWidth="56.0" style="-fx-border-color: Black; -fx-border-radius: 15; -fx-border-style: solid outside;" text="000" textAlignment="LEFT" textFill="BLACK" AnchorPane.leftAnchor="10.0">
|
||||
<font>
|
||||
<Font name="System Bold" size="24.0" fx:id="x1" />
|
||||
</font>
|
||||
</Label>
|
||||
<Label fx:id="timeLabel" alignment="TOP_CENTER" contentDisplay="LEFT" font="$x1" layoutY="28.0" prefHeight="37.0" prefWidth="56.0" style="-fx-border-color: Black; -fx-border-style: solid outside; -fx-border-radius: 15;" text="000" textAlignment="LEFT" textFill="BLACK" AnchorPane.rightAnchor="10.0" />
|
||||
<Button id="button" fx:id="automateButton" alignment="TOP_CENTER" minWidth="-Infinity" onAction="#handleAutomateButton" prefWidth="100.0" text="Automate" textAlignment="CENTER" AnchorPane.bottomAnchor="5.0" AnchorPane.leftAnchor="10.0" />
|
||||
<Circle fx:id="highlight" centerX="50.0" centerY="50.0" fill="#fff500" layoutX="281.0" layoutY="-11.0" mouseTransparent="true" opacity="0.49" radius="26.25" stroke="BLACK" strokeType="INSIDE" strokeWidth="4.0" />
|
||||
<HBox alignment="CENTER" layoutX="10.0" layoutY="28.0" minHeight="-Infinity" prefHeight="37.0" prefWidth="571.0" AnchorPane.leftAnchor="10.0" AnchorPane.rightAnchor="10.0" AnchorPane.topAnchor="28.0">
|
||||
<children>
|
||||
<Button fx:id="newGameButton" alignment="TOP_CENTER" minWidth="-Infinity" onAction="#handleNewGameButton" prefHeight="25.0" prefWidth="100.0" text="New Game" textAlignment="CENTER" />
|
||||
</children>
|
||||
</HBox>
|
||||
</children>
|
||||
<stylesheets>
|
||||
<URL value="@Screen.css" />
|
||||
</stylesheets>
|
||||
</AnchorPane>
|
@ -0,0 +1,253 @@
|
||||
package minesweeper.bulk;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.Random;
|
||||
|
||||
import javafx.application.Platform;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.event.EventHandler;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.fxml.FXMLLoader;
|
||||
import javafx.scene.Parent;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.control.CheckBox;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.ProgressBar;
|
||||
import javafx.scene.control.TextField;
|
||||
import javafx.scene.layout.AnchorPane;
|
||||
import javafx.stage.Modality;
|
||||
import javafx.stage.Stage;
|
||||
import javafx.stage.Window;
|
||||
import javafx.stage.WindowEvent;
|
||||
import minesweeper.Graphics;
|
||||
import minesweeper.gamestate.GameStateModel;
|
||||
import minesweeper.random.DefaultRNG;
|
||||
import minesweeper.settings.GameSettings;
|
||||
import minesweeper.settings.GameType;
|
||||
import minesweeper.solver.settings.SolverSettings;
|
||||
import minesweeper.structure.Location;
|
||||
|
||||
public class BulkController {
|
||||
|
||||
private final static DecimalFormat PERCENT = new DecimalFormat("#0.000%");
|
||||
|
||||
@FXML private AnchorPane window;
|
||||
|
||||
@FXML private TextField gameCount;
|
||||
@FXML private TextField gameSeed;
|
||||
@FXML private Label winPercentage;
|
||||
@FXML private ProgressBar progressRun;
|
||||
@FXML private Label progressRunLabel;
|
||||
@FXML private TextField startLocX;
|
||||
@FXML private TextField startLocY;
|
||||
@FXML private CheckBox showGames;
|
||||
@FXML private CheckBox winsOnly;
|
||||
|
||||
private Stage stage;
|
||||
private Scene scene;
|
||||
|
||||
private int gamesMax;
|
||||
private long gameGenerator;
|
||||
|
||||
private GameSettings gameSettings;
|
||||
private GameType gameType;
|
||||
private Location startLocation;
|
||||
private SolverSettings preferences;
|
||||
|
||||
//private ResultsController resultsController;
|
||||
|
||||
private BulkRunner bulkRunner;
|
||||
|
||||
private boolean wasCancelled = false;
|
||||
|
||||
|
||||
@FXML
|
||||
void initialize() {
|
||||
System.out.println("Entered Bulk Screen initialize method");
|
||||
|
||||
|
||||
}
|
||||
|
||||
@FXML
|
||||
private void handleNewSeedButton(ActionEvent event) {
|
||||
gameSeed.setText(String.valueOf(new Random().nextLong()));
|
||||
}
|
||||
|
||||
@FXML
|
||||
private void handleOkayButton(ActionEvent event) {
|
||||
|
||||
System.out.println("handleOkayButton method entered");
|
||||
|
||||
if (bulkRunner != null && !bulkRunner.isFinished()) {
|
||||
System.out.println("Previous bulk run still running");
|
||||
return;
|
||||
}
|
||||
|
||||
if (gameCount.getText().trim().isEmpty()) {
|
||||
gamesMax = 1000;
|
||||
} else {
|
||||
try {
|
||||
gamesMax = Integer.parseInt(gameCount.getText().trim());
|
||||
if (gamesMax < 1) {
|
||||
gamesMax = 1000;
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
gamesMax = 1000;
|
||||
}
|
||||
}
|
||||
|
||||
gameCount.setText(String.valueOf(gamesMax));
|
||||
|
||||
if (gameSeed.getText().trim().isEmpty()) {
|
||||
gameGenerator = new Random().nextLong();
|
||||
} else {
|
||||
try {
|
||||
gameGenerator = Long.parseLong(gameSeed.getText().trim());
|
||||
} catch (NumberFormatException e) {
|
||||
gameGenerator = new Random().nextLong();
|
||||
//gameSeed.setText("");
|
||||
}
|
||||
}
|
||||
|
||||
startLocation = null;
|
||||
if (!startLocX.getText().trim().isEmpty() && !startLocY.getText().trim().isEmpty()) {
|
||||
try {
|
||||
int startX = Integer.parseInt(startLocX.getText().trim());
|
||||
int startY = Integer.parseInt(startLocY.getText().trim());
|
||||
if (startX >= 0 && startX < gameSettings.width && startY >= 0 && startY < gameSettings.height) {
|
||||
startLocation = new Location(startX, startY);
|
||||
System.out.println("Start location set to " + startLocation.toString());
|
||||
}
|
||||
|
||||
} catch (NumberFormatException e) {
|
||||
}
|
||||
}
|
||||
|
||||
gameSeed.setText(String.valueOf(gameGenerator));
|
||||
|
||||
bulkRunner = new BulkRunner(this, gamesMax, gameSettings, gameType, gameGenerator, startLocation, showGames.isSelected(), winsOnly.isSelected(), preferences);
|
||||
|
||||
new Thread(bulkRunner, "Bulk Run").start();
|
||||
|
||||
|
||||
}
|
||||
|
||||
@FXML
|
||||
private void handleCancelButton(ActionEvent event) {
|
||||
|
||||
System.out.println("handleCancelButton method entered");
|
||||
|
||||
stage.close();
|
||||
|
||||
}
|
||||
|
||||
|
||||
public static BulkController launch(Window owner, GameSettings gameSettings, GameType gameType, SolverSettings preferences ) {
|
||||
|
||||
if (BulkController.class.getResource("BulkScreen.fxml") == null) {
|
||||
System.out.println("BulkScreen.fxml not found");
|
||||
}
|
||||
|
||||
// create the bulk runner screen
|
||||
FXMLLoader loader = new FXMLLoader(BulkController.class.getResource("BulkScreen.fxml"));
|
||||
|
||||
Parent root = null;
|
||||
try {
|
||||
root = (Parent) loader.load();
|
||||
} catch (IOException ex) {
|
||||
System.err.println(ex.getMessage());
|
||||
}
|
||||
|
||||
BulkController custom = loader.getController();
|
||||
|
||||
if (custom == null) {
|
||||
System.out.println("Custom is null");
|
||||
}
|
||||
|
||||
if (root == null) {
|
||||
System.out.println("Root is null");
|
||||
}
|
||||
|
||||
custom.gameSettings = gameSettings;
|
||||
custom.gameType = gameType;
|
||||
custom.preferences = preferences;
|
||||
|
||||
custom.scene = new Scene(root);
|
||||
|
||||
custom.stage = new Stage();
|
||||
|
||||
custom.stage.setScene(custom.scene);
|
||||
custom.stage.setTitle("Bulk run - " + gameSettings.description() + ", " + gameType.name + ", " + DefaultRNG.getRNG(1).shortname());
|
||||
|
||||
custom.stage.getIcons().add(Graphics.getMine());
|
||||
|
||||
custom.stage.setResizable(false);
|
||||
|
||||
custom.stage.initOwner(owner);
|
||||
custom.stage.initModality(Modality.WINDOW_MODAL);
|
||||
|
||||
custom.stage.setOnCloseRequest(new EventHandler<WindowEvent>() {
|
||||
|
||||
@Override
|
||||
public void handle(WindowEvent event) {
|
||||
System.out.println("Entered OnCloseRequest handler");
|
||||
|
||||
if (custom.bulkRunner != null) {
|
||||
custom.bulkRunner.forceStop();
|
||||
}
|
||||
|
||||
System.gc();
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
custom.gameCount.setText("1000");
|
||||
custom.progressRun.setProgress(0d);
|
||||
custom.progressRunLabel.setText("");
|
||||
|
||||
//custom.resultsController = ResultsController.launch(null, gameSettings, gameType);
|
||||
|
||||
|
||||
custom.getStage().show();
|
||||
|
||||
return custom;
|
||||
}
|
||||
|
||||
public Stage getStage() {
|
||||
return this.stage;
|
||||
}
|
||||
|
||||
public boolean wasCancelled() {
|
||||
return wasCancelled;
|
||||
}
|
||||
|
||||
public void update(int steps, int maxSteps, int wins) {
|
||||
|
||||
Platform.runLater(new Runnable() {
|
||||
@Override public void run() {
|
||||
double prog = (double) steps / (double) maxSteps;
|
||||
progressRun.setProgress(prog);
|
||||
|
||||
progressRunLabel.setText(steps + "(" + wins + ") /" + maxSteps);
|
||||
|
||||
double winPerc = (double) wins / (double) steps;
|
||||
|
||||
double err = Math.sqrt(winPerc * ( 1- winPerc) / (double) steps) * 1.9599d;
|
||||
|
||||
winPercentage.setText(PERCENT.format(winPerc) + " +/- " + PERCENT.format(err));
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
public void storeResult(GameStateModel gs) {
|
||||
|
||||
resultsController.update(gs);
|
||||
|
||||
}
|
||||
*/
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import javafx.scene.control.*?>
|
||||
<?import java.lang.*?>
|
||||
<?import javafx.scene.layout.*?>
|
||||
<?import javafx.scene.layout.AnchorPane?>
|
||||
|
||||
<AnchorPane prefHeight="554.0" prefWidth="446.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="minesweeper.bulk.ResultsController">
|
||||
<children>
|
||||
<Button alignment="CENTER" layoutX="379.0" layoutY="401.0" mnemonicParsing="false" onAction="#handlePlayButton" prefHeight="25.0" prefWidth="84.0" text="Play game" AnchorPane.bottomAnchor="5.0" AnchorPane.rightAnchor="20.0" />
|
||||
<TableView fx:id="resultsTable" prefHeight="414.0" prefWidth="550.0" AnchorPane.bottomAnchor="40.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<columns>
|
||||
<TableColumn fx:id="columnCount" prefWidth="79.0" style="-fx-alignment: CENTER_RIGHT;" text="Number" />
|
||||
<TableColumn fx:id="columnSeed" prefWidth="165.0" style="-fx-alignment: CENTER;" text="Seed" />
|
||||
<TableColumn fx:id="columnComplete" prefWidth="99.0" style="-fx-alignment: CENTER_RIGHT;" text="Tiles revealed" />
|
||||
<TableColumn fx:id="columnResult" prefWidth="88.0" style="-fx-alignment: CENTER;" text="Result" />
|
||||
</columns>
|
||||
</TableView>
|
||||
</children>
|
||||
</AnchorPane>
|
@ -0,0 +1,154 @@
|
||||
package minesweeper.bulk;
|
||||
|
||||
import minesweeper.gamestate.GameFactory;
|
||||
import minesweeper.gamestate.GameStateModel;
|
||||
import minesweeper.random.DefaultRNG;
|
||||
import minesweeper.random.RNG;
|
||||
import minesweeper.settings.GameSettings;
|
||||
import minesweeper.settings.GameType;
|
||||
import minesweeper.solver.Solver;
|
||||
import minesweeper.solver.settings.SolverSettings;
|
||||
import minesweeper.structure.Action;
|
||||
import minesweeper.structure.Location;
|
||||
|
||||
public class BulkRunner implements Runnable {
|
||||
|
||||
private boolean stop = false;
|
||||
private final int maxSteps;
|
||||
private final long seed;
|
||||
private final BulkController controller;
|
||||
private final GameSettings gameSettings;
|
||||
private final GameType gameType;
|
||||
private final Location startLocation;
|
||||
private final SolverSettings preferences;
|
||||
|
||||
//private final Random seeder;
|
||||
private int steps = 0;
|
||||
private int wins = 0;
|
||||
|
||||
private final RNG seeder;
|
||||
|
||||
private ResultsController resultsController;
|
||||
private boolean showGames;
|
||||
private boolean winsOnly;
|
||||
|
||||
public BulkRunner(BulkController controller, int iterations, GameSettings gameSettings, GameType gameType,
|
||||
long seed, Location startLocation, boolean showGames, boolean winsOnly, SolverSettings preferences) {
|
||||
|
||||
maxSteps = iterations;
|
||||
this.seed = seed;
|
||||
this.controller = controller;
|
||||
this.gameSettings = gameSettings;
|
||||
this.gameType = gameType;
|
||||
this.startLocation = startLocation;
|
||||
this.seeder = DefaultRNG.getRNG(seed);
|
||||
this.showGames = showGames;
|
||||
this.winsOnly = winsOnly;
|
||||
this.preferences = preferences;
|
||||
|
||||
if (startLocation != null) {
|
||||
this.preferences.setStartLocation(startLocation);
|
||||
}
|
||||
|
||||
if (showGames) {
|
||||
resultsController = ResultsController.launch(null, gameSettings, gameType);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
System.out.println("At BulkRunner run method");
|
||||
|
||||
while (!stop && steps < maxSteps) {
|
||||
|
||||
steps++;
|
||||
|
||||
GameStateModel gs = GameFactory.create(gameType, gameSettings, seeder.random(0));
|
||||
|
||||
Solver solver = new Solver(gs, preferences, false);
|
||||
|
||||
|
||||
boolean win = playGame(gs, solver);
|
||||
|
||||
if (win) {
|
||||
wins++;
|
||||
}
|
||||
|
||||
if (showGames && (win || !win && !winsOnly)) {
|
||||
if (!resultsController.update(gs)) { // this returns false if the window has been closed
|
||||
showGames = false;
|
||||
resultsController = null;
|
||||
System.out.println("Results window has been closed... will no longer send data to it");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
controller.update(steps, maxSteps, wins);
|
||||
|
||||
}
|
||||
|
||||
stop = true;
|
||||
System.out.println("BulkRunner run method ending");
|
||||
|
||||
}
|
||||
|
||||
|
||||
private boolean playGame(GameStateModel gs, Solver solver) {
|
||||
|
||||
int state;
|
||||
|
||||
play: while (true) {
|
||||
|
||||
Action[] moves;
|
||||
try {
|
||||
solver.start();
|
||||
moves = solver.getResult();
|
||||
} catch (Exception e) {
|
||||
System.out.println("Game " + gs.showGameKey() + " has thrown an exception!");
|
||||
stop = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (moves.length == 0) {
|
||||
System.err.println("No moves returned by the solver for game " + gs.showGameKey());
|
||||
stop = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// play all the moves until all done, or the game is won or lost
|
||||
for (int i=0; i < moves.length; i++) {
|
||||
|
||||
boolean result = gs.doAction(moves[i]);
|
||||
|
||||
state = gs.getGameState();
|
||||
|
||||
if (state == GameStateModel.LOST || state == GameStateModel.WON) {
|
||||
break play;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (state == GameStateModel.LOST) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public void forceStop() {
|
||||
System.out.println("Bulk run being requested to stop");
|
||||
|
||||
stop = true;
|
||||
}
|
||||
|
||||
public boolean isFinished() {
|
||||
return stop;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import javafx.scene.paint.*?>
|
||||
<?import javafx.scene.text.*?>
|
||||
<?import javafx.scene.control.*?>
|
||||
<?import java.lang.*?>
|
||||
<?import javafx.scene.layout.*?>
|
||||
<?import javafx.scene.layout.AnchorPane?>
|
||||
|
||||
<AnchorPane prefHeight="278.0" prefWidth="403.0" style="-fx-background-color: green;" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="minesweeper.bulk.BulkController">
|
||||
<children>
|
||||
<Button layoutX="317.0" layoutY="242.0" mnemonicParsing="false" onAction="#handleOkayButton" prefHeight="25.0" prefWidth="72.0" text="Start" />
|
||||
<ProgressBar fx:id="progressRun" layoutX="96.0" layoutY="171.0" prefHeight="25.0" prefWidth="293.0" progress="0.21" style="-fx-control-inner-background: palegreen; -fx-accent: darkgreen;" />
|
||||
<TextField fx:id="gameCount" layoutX="95.0" layoutY="18.0" style="-fx-background-color: silver;" />
|
||||
<Label layoutX="15.0" layoutY="132.0" prefHeight="25.0" prefWidth="72.0" text="Win rate">
|
||||
<font>
|
||||
<Font size="14.0" />
|
||||
</font></Label>
|
||||
<Label layoutX="14.0" layoutY="18.0" prefHeight="25.0" prefWidth="72.0" text="Games" textAlignment="RIGHT">
|
||||
<font>
|
||||
<Font size="14.0" />
|
||||
</font>
|
||||
</Label>
|
||||
<Label layoutX="15.0" layoutY="171.0" prefHeight="25.0" prefWidth="72.0" text="Progress" textAlignment="RIGHT">
|
||||
<font>
|
||||
<Font size="14.0" />
|
||||
</font>
|
||||
</Label>
|
||||
<Label fx:id="progressRunLabel" alignment="CENTER" layoutX="112.0" layoutY="171.0" prefHeight="25.0" prefWidth="267.0" text="590/1000">
|
||||
<font>
|
||||
<Font name="System Bold" size="16.0" />
|
||||
</font>
|
||||
</Label>
|
||||
<Label fx:id="winPercentage" layoutX="96.0" layoutY="131.0" prefHeight="27.0" prefWidth="293.0">
|
||||
<font>
|
||||
<Font name="System Bold" size="18.0" />
|
||||
</font>
|
||||
</Label>
|
||||
<Label layoutX="14.0" layoutY="57.0" prefHeight="25.0" prefWidth="72.0" text="Seed" textAlignment="RIGHT">
|
||||
<font>
|
||||
<Font size="14.0" />
|
||||
</font>
|
||||
</Label>
|
||||
<TextField fx:id="gameSeed" layoutX="95.0" layoutY="57.0" style="-fx-background-color: silver;" />
|
||||
<Button layoutX="253.0" layoutY="57.0" mnemonicParsing="false" onAction="#handleNewSeedButton" prefHeight="25.0" prefWidth="72.0" text="New seed" />
|
||||
<Label layoutX="14.0" layoutY="100.0" prefHeight="25.0" prefWidth="92.0" text="Start Loc: X=" textAlignment="RIGHT">
|
||||
<font>
|
||||
<Font size="14.0" />
|
||||
</font>
|
||||
</Label>
|
||||
<TextField fx:id="startLocX" layoutX="95.0" layoutY="100.0" prefHeight="25.0" prefWidth="43.0" style="-fx-background-color: silver;" />
|
||||
<Label layoutX="145.0" layoutY="100.0" prefHeight="25.0" prefWidth="29.0" text="Y=" textAlignment="RIGHT">
|
||||
<font>
|
||||
<Font size="14.0" />
|
||||
</font>
|
||||
</Label>
|
||||
<TextField fx:id="startLocY" layoutX="165.0" layoutY="100.0" prefHeight="25.0" prefWidth="43.0" style="-fx-background-color: silver;" />
|
||||
<CheckBox fx:id="showGames" layoutX="99.0" layoutY="211.0" mnemonicParsing="false" text="Show game results">
|
||||
<font>
|
||||
<Font size="14.0" />
|
||||
</font>
|
||||
</CheckBox>
|
||||
<CheckBox fx:id="winsOnly" layoutX="99.0" layoutY="244.0" mnemonicParsing="false" text="Wins only">
|
||||
<font>
|
||||
<Font size="14.0" />
|
||||
</font>
|
||||
</CheckBox>
|
||||
</children>
|
||||
</AnchorPane>
|
@ -0,0 +1,178 @@
|
||||
package minesweeper.bulk;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.text.DecimalFormat;
|
||||
|
||||
import javafx.application.Platform;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.event.EventHandler;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.fxml.FXMLLoader;
|
||||
import javafx.scene.Parent;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.control.TableColumn;
|
||||
import javafx.scene.control.TableView;
|
||||
import javafx.scene.control.TableView.TableViewSelectionModel;
|
||||
import javafx.scene.control.cell.PropertyValueFactory;
|
||||
import javafx.stage.Modality;
|
||||
import javafx.stage.Stage;
|
||||
import javafx.stage.Window;
|
||||
import javafx.stage.WindowEvent;
|
||||
import minesweeper.Graphics;
|
||||
import minesweeper.Minesweeper;
|
||||
import minesweeper.gamestate.GameFactory;
|
||||
import minesweeper.gamestate.GameStateModel;
|
||||
import minesweeper.gamestate.GameStateModelViewer;
|
||||
import minesweeper.settings.GameSettings;
|
||||
import minesweeper.settings.GameType;
|
||||
|
||||
public class ResultsController {
|
||||
|
||||
|
||||
|
||||
private Stage stage;
|
||||
private Scene scene;
|
||||
|
||||
@FXML private TableView<TableData> resultsTable;
|
||||
@FXML private TableColumn<TableData, Integer> columnCount;
|
||||
@FXML private TableColumn<TableData, Long> columnSeed;
|
||||
@FXML private TableColumn<TableData, Integer> columnComplete;
|
||||
@FXML private TableColumn<TableData, String> columnResult;
|
||||
|
||||
private GameSettings gameSettings;
|
||||
private GameType gameType;
|
||||
private int count = 0;
|
||||
private boolean closed = false;
|
||||
|
||||
private ObservableList<TableData> items = FXCollections.observableArrayList();
|
||||
|
||||
|
||||
@FXML
|
||||
void initialize() {
|
||||
System.out.println("Entered Bulk Result Screen initialize method");
|
||||
|
||||
|
||||
}
|
||||
|
||||
@FXML
|
||||
private void handlePlayButton(ActionEvent event) {
|
||||
|
||||
System.out.println("handlePlayButton method entered");
|
||||
|
||||
TableData selected = resultsTable.getSelectionModel().getSelectedItem();
|
||||
|
||||
long seed = selected.seedProperty().longValue();
|
||||
|
||||
System.out.println("Selected seed " + seed);
|
||||
|
||||
GameStateModelViewer gs = GameFactory.create(gameType, gameSettings, seed);
|
||||
|
||||
Minesweeper.playGame(gs);
|
||||
|
||||
}
|
||||
|
||||
|
||||
public static ResultsController launch(Window owner, GameSettings gameSettings, GameType gameType) {
|
||||
|
||||
|
||||
if (ResultsController.class.getResource("BulkScreen.fxml") == null) {
|
||||
System.out.println("BulkScreen.fxml not found");
|
||||
}
|
||||
|
||||
// create the bulk runner screen
|
||||
FXMLLoader loader = new FXMLLoader(ResultsController.class.getResource("BulkResults.fxml"));
|
||||
|
||||
Parent root = null;
|
||||
try {
|
||||
root = (Parent) loader.load();
|
||||
} catch (IOException ex) {
|
||||
System.err.println(ex.getMessage());
|
||||
}
|
||||
|
||||
ResultsController custom = loader.getController();
|
||||
|
||||
if (custom == null) {
|
||||
System.out.println("Custom is null");
|
||||
}
|
||||
|
||||
if (root == null) {
|
||||
System.out.println("Root is null");
|
||||
}
|
||||
|
||||
custom.scene = new Scene(root);
|
||||
|
||||
custom.stage = new Stage();
|
||||
|
||||
custom.stage.setScene(custom.scene);
|
||||
custom.stage.setTitle("Bulk run results");
|
||||
|
||||
custom.stage.getIcons().add(Graphics.getMine());
|
||||
|
||||
custom.stage.setResizable(false);
|
||||
|
||||
custom.stage.initOwner(owner);
|
||||
custom.stage.initModality(Modality.WINDOW_MODAL);
|
||||
|
||||
custom.stage.setOnCloseRequest(new EventHandler<WindowEvent>() {
|
||||
|
||||
@Override
|
||||
public void handle(WindowEvent event) {
|
||||
System.out.println("Entered OnCloseRequest handler for Bulk Results Screen");
|
||||
|
||||
custom.closed = true;
|
||||
custom.items.clear(); // clear down the table to encourage the items to be garbage collected
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
custom.resultsTable.setItems(custom.items);
|
||||
|
||||
custom.resultsTable.getSelectionModel();
|
||||
|
||||
custom.columnCount.setCellValueFactory(new PropertyValueFactory<TableData, Integer>("count"));
|
||||
custom.columnSeed.setCellValueFactory(new PropertyValueFactory<TableData, Long>("seed"));
|
||||
custom.columnComplete.setCellValueFactory(new PropertyValueFactory<TableData, Integer>("complete"));
|
||||
custom.columnResult.setCellValueFactory(new PropertyValueFactory<TableData, String>("result"));
|
||||
|
||||
custom.getStage().show();
|
||||
|
||||
custom.gameType = gameType;
|
||||
custom.gameSettings = gameSettings;
|
||||
|
||||
//System.out.println("Columns = " + custom.resultsTable.getColumns().size());
|
||||
|
||||
return custom;
|
||||
}
|
||||
|
||||
public Stage getStage() {
|
||||
return this.stage;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public boolean update(GameStateModel gs) {
|
||||
|
||||
if (closed) { // if the window has been closed then let anyone who calls know
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
count++;
|
||||
final TableData td = new TableData(count, gs);
|
||||
|
||||
Platform.runLater(new Runnable() {
|
||||
@Override public void run() {
|
||||
|
||||
items.add(td);
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,74 @@
|
||||
package minesweeper.bulk;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.text.DecimalFormat;
|
||||
|
||||
import javafx.beans.property.BooleanProperty;
|
||||
import javafx.beans.property.DoubleProperty;
|
||||
import javafx.beans.property.FloatProperty;
|
||||
import javafx.beans.property.IntegerProperty;
|
||||
import javafx.beans.property.LongProperty;
|
||||
import javafx.beans.property.SimpleBooleanProperty;
|
||||
import javafx.beans.property.SimpleDoubleProperty;
|
||||
import javafx.beans.property.SimpleFloatProperty;
|
||||
import javafx.beans.property.SimpleIntegerProperty;
|
||||
import javafx.beans.property.SimpleLongProperty;
|
||||
import javafx.beans.property.SimpleStringProperty;
|
||||
import javafx.beans.property.StringProperty;
|
||||
import minesweeper.gamestate.GameStateModel;
|
||||
|
||||
public class TableData {
|
||||
|
||||
private final static BigDecimal ONE_HUNDRED = BigDecimal.valueOf(100);
|
||||
private final static DecimalFormat PERCENT = new DecimalFormat("#0.000%");
|
||||
|
||||
private final IntegerProperty count;
|
||||
private final LongProperty seed;
|
||||
private final IntegerProperty complete;
|
||||
private final StringProperty result;
|
||||
|
||||
public TableData(int count, GameStateModel gs) {
|
||||
|
||||
this.count = new SimpleIntegerProperty(count);
|
||||
|
||||
seed = new SimpleLongProperty(gs.getSeed());
|
||||
|
||||
/*
|
||||
BigDecimal areaToReveal = BigDecimal.valueOf(gs.getx() * gs.gety() - gs.getMines());
|
||||
BigDecimal areaLeftToReveal = BigDecimal.valueOf(gs.getHidden() - gs.getMines());
|
||||
|
||||
BigDecimal percentageToDo = ONE_HUNDRED.multiply(BigDecimal.ONE.subtract(areaLeftToReveal.divide(areaToReveal, 6, RoundingMode.HALF_UP))).setScale(2, RoundingMode.HALF_UP);
|
||||
|
||||
System.out.println(percentageToDo + " " + (gs.getGameState() == GameStateModel.WON) + " " + areaLeftToReveal);
|
||||
*/
|
||||
|
||||
complete = new SimpleIntegerProperty(gs.getWidth() * gs.getHeight() - gs.getHidden());
|
||||
|
||||
if (gs.getGameState() == GameStateModel.WON) {
|
||||
result = new SimpleStringProperty("Won");
|
||||
} else {
|
||||
result = new SimpleStringProperty("Lost");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public LongProperty seedProperty() {
|
||||
return seed;
|
||||
}
|
||||
|
||||
public IntegerProperty completeProperty() {
|
||||
return complete;
|
||||
}
|
||||
|
||||
public StringProperty resultProperty() {
|
||||
return result;
|
||||
}
|
||||
|
||||
public IntegerProperty countProperty() {
|
||||
return count;
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import java.lang.*?>
|
||||
<?import java.net.*?>
|
||||
<?import java.util.*?>
|
||||
<?import javafx.scene.*?>
|
||||
<?import javafx.scene.control.*?>
|
||||
<?import javafx.scene.layout.*?>
|
||||
|
||||
<AnchorPane id="AnchorPane" prefHeight="300.0" prefWidth="477.0" styleClass="mainFxmlClass" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/2.2" fx:controller="minesweeper.coach.HelperController">
|
||||
<children>
|
||||
<TextArea fx:id="text" editable="false" focusTraversable="false" prefHeight="241.0" prefWidth="420.0" text="" wrapText="true" AnchorPane.bottomAnchor="25.0" AnchorPane.leftAnchor="25.0" AnchorPane.rightAnchor="25.0" AnchorPane.topAnchor="25.0" />
|
||||
</children>
|
||||
<stylesheets>
|
||||
<URL value="@helper.css" />
|
||||
</stylesheets>
|
||||
</AnchorPane>
|
@ -0,0 +1,177 @@
|
||||
/*
|
||||
* To change this template, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package minesweeper.coach;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
import javafx.application.Platform;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.fxml.FXMLLoader;
|
||||
import javafx.fxml.Initializable;
|
||||
import javafx.scene.Parent;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.control.TextArea;
|
||||
import javafx.scene.layout.AnchorPane;
|
||||
import javafx.scene.layout.Background;
|
||||
import javafx.scene.layout.BackgroundFill;
|
||||
import javafx.scene.paint.Color;
|
||||
import javafx.stage.Stage;
|
||||
import minesweeper.Graphics;
|
||||
import minesweeper.Minesweeper;
|
||||
import minesweeper.solver.Solver;
|
||||
import minesweeper.solver.coach.CoachModel;
|
||||
|
||||
/**
|
||||
* FXML Controller class
|
||||
*
|
||||
* @author David
|
||||
*/
|
||||
public class HelperController implements CoachModel, Initializable {
|
||||
|
||||
private static final Background BG_Red = new Background(new BackgroundFill(Color.RED, null, null));
|
||||
private static final Background BG_Green = new Background(new BackgroundFill(Color.GREEN, null, null));
|
||||
private static final Background BG_Orange = new Background(new BackgroundFill(Color.ORANGE, null, null));
|
||||
|
||||
@FXML
|
||||
private TextArea text;
|
||||
|
||||
//private HelperController helperController;
|
||||
public Stage stage;
|
||||
public Scene scene;
|
||||
|
||||
|
||||
/**
|
||||
* Initializes the controller class.
|
||||
*/
|
||||
@Override
|
||||
public void initialize(URL url, ResourceBundle rb) {
|
||||
|
||||
System.out.println("Entered Helper Control initialize method");
|
||||
// TODO
|
||||
}
|
||||
|
||||
/*
|
||||
public TextArea getTextArea() {
|
||||
return text;
|
||||
}
|
||||
*/
|
||||
|
||||
public void kill() {
|
||||
|
||||
stage.close();
|
||||
|
||||
System.out.println("Killing the Helper Control Object");
|
||||
|
||||
}
|
||||
|
||||
public static HelperController launch() {
|
||||
|
||||
// create the helper screen
|
||||
FXMLLoader loader = new FXMLLoader(HelperController.class.getResource("Helper.fxml"));
|
||||
|
||||
Parent root = null;
|
||||
try {
|
||||
root = (Parent) loader.load();
|
||||
} catch (IOException ex) {
|
||||
System.err.println(ex.getMessage());
|
||||
}
|
||||
|
||||
HelperController coach = loader.getController();
|
||||
|
||||
//helperController = loader.getController();
|
||||
|
||||
coach.scene = new Scene(root);
|
||||
|
||||
coach.stage = new Stage();
|
||||
|
||||
coach.stage.setScene(coach.scene);
|
||||
coach.stage.setTitle(Minesweeper.TITLE + " solver " + Solver.VERSION);
|
||||
coach.stage.getIcons().add(Graphics.getFlag());
|
||||
|
||||
coach.writeLine("Minesweeper coach dedicated to Annie");
|
||||
|
||||
//((AnchorPane) scene.getRoot()).setBackground(BG_Green);
|
||||
coach.setOkay();
|
||||
Stage st = Minesweeper.getStage();
|
||||
coach.stage.setX(st.getX()+ st.getWidth());
|
||||
coach.stage.setY(st.getY());
|
||||
|
||||
coach.align();
|
||||
|
||||
coach.stage.show();
|
||||
|
||||
return coach;
|
||||
}
|
||||
|
||||
final public void align() {
|
||||
|
||||
Stage st = Minesweeper.getStage();
|
||||
|
||||
if (st != null) {
|
||||
stage.setX(st.getX()+ st.getWidth());
|
||||
stage.setY(st.getY());
|
||||
}
|
||||
|
||||
stage.setHeight(500);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
final public void setOkay() {
|
||||
setColor(BG_Green);
|
||||
}
|
||||
|
||||
@Override
|
||||
final public void setWarn() {
|
||||
setColor(BG_Orange);
|
||||
}
|
||||
|
||||
@Override
|
||||
final public void setError() {
|
||||
setColor(BG_Red);
|
||||
}
|
||||
|
||||
private void setColor(Background c) {
|
||||
|
||||
((AnchorPane) scene.getRoot()).setBackground(c);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearScreen() {
|
||||
|
||||
Platform.runLater(new Runnable() {
|
||||
@Override public void run() {
|
||||
text.clear();
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeLine(String line) {
|
||||
|
||||
Platform.runLater(new Runnable() {
|
||||
@Override public void run() {
|
||||
String textLine = text.getText();
|
||||
if (textLine.equals("")) {
|
||||
textLine = line;
|
||||
} else {
|
||||
textLine = textLine + "\n" + line;
|
||||
}
|
||||
text.setText(textLine);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean analyseFlags() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
/*
|
||||
* Empty Stylesheet file.
|
||||
*/
|
||||
|
||||
.mainFxmlClass {
|
||||
|
||||
}
|
@ -0,0 +1,160 @@
|
||||
package minesweeper.gamestate.msx;
|
||||
|
||||
import minesweeper.gamestate.GameStateModel;
|
||||
import minesweeper.gamestate.GameStateModelViewer;
|
||||
import minesweeper.settings.GameSettings;
|
||||
import minesweeper.structure.Location;
|
||||
|
||||
public class GameStateX extends GameStateModelViewer {
|
||||
|
||||
private ScreenScanner scanner;
|
||||
|
||||
public GameStateX(ScreenScanner scanner) {
|
||||
super(GameSettings.create(scanner.getColumns(), scanner.getRows(), scanner.getMines()));
|
||||
|
||||
this.scanner = scanner;
|
||||
|
||||
doAutoComplete = false; // minesweeperX will do this itself
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void placeFlagHandle(Location m) {
|
||||
scanner.flag(m.x, m.y);
|
||||
|
||||
// give it time to set the flag
|
||||
try {
|
||||
Thread.sleep(20);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
try {
|
||||
scanner.updateField();
|
||||
} catch (Exception e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean clearSquareHitMine(Location m) {
|
||||
|
||||
scanner.clear(m.x, m.y);
|
||||
|
||||
try {
|
||||
Thread.sleep(20);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
try {
|
||||
scanner.updateField();
|
||||
} catch (Exception e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
// since the click could have expanded more areas we need to allow for that
|
||||
for (int x=0; x < scanner.getColumns(); x++) {
|
||||
for (int y=0; y < scanner.getRows(); y++) {
|
||||
if (scanner.getValue(x, y) != ScreenScanner.HIDDEN && scanner.getValue(x, y) != ScreenScanner.FLAG) {
|
||||
setRevealed(x,y);
|
||||
}
|
||||
|
||||
// if a flag has been revealed by minesweeperX then place that in the model (this happens at the end of a game)
|
||||
if (scanner.getValue(x, y) == ScreenScanner.FLAG && this.query(new Location(x,y)) == HIDDEN) {
|
||||
setFlag(x,y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return scanner.isGameLost();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void startHandle(Location m) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int queryHandle(int x, int y) {
|
||||
|
||||
int value = scanner.getValue(x, y);
|
||||
|
||||
if (value == ScreenScanner.HIDDEN) {
|
||||
System.out.println("value at (" + x + "," + y + ") is hidden and yet queried!");
|
||||
}
|
||||
if (value == ScreenScanner.FLAG) {
|
||||
System.out.println("value at (" + x + "," + y + ") is a flag and yet queried!");
|
||||
}
|
||||
|
||||
|
||||
if (value == ScreenScanner.HIDDEN) {
|
||||
return GameStateModel.HIDDEN;
|
||||
} else if (value == ScreenScanner.EMPTY) {
|
||||
return 0;
|
||||
} else if (value == ScreenScanner.FLAG) {
|
||||
return GameStateModel.HIDDEN;
|
||||
} else if (value == ScreenScanner.BOMB) {
|
||||
return GameStateModel.MINE;
|
||||
} else if (value == ScreenScanner.EXPLODED_BOMB) {
|
||||
return GameStateModel.EXPLODED_MINE;
|
||||
} else {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
/**
|
||||
* No privileged access since MinesweeperX can't show it
|
||||
*/
|
||||
public int privilegedQuery(Location m, boolean showMines) {
|
||||
return query(m);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean clearSurroundHandle(Location m) {
|
||||
|
||||
scanner.clearAll(m.x, m.y);
|
||||
|
||||
try {
|
||||
Thread.sleep(20);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
try {
|
||||
scanner.updateField();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
// since the click could have expanded more areas we need to allow for that
|
||||
for (int x=0; x < scanner.getColumns(); x++) {
|
||||
for (int y=0; y < scanner.getRows(); y++) {
|
||||
if (scanner.getValue(x, y) != ScreenScanner.HIDDEN && scanner.getValue(x, y) != ScreenScanner.FLAG) {
|
||||
setRevealed(x,y);
|
||||
}
|
||||
|
||||
// if a flag has been revealed by minesweeperX then place that in the model (this happens at the end of a game)
|
||||
if (scanner.getValue(x, y) == ScreenScanner.FLAG && this.query(new Location(x,y)) == HIDDEN) {
|
||||
setFlag(x,y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String showGameKey() {
|
||||
return "Minesweeper X";
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package minesweeper.gamestate.msx;
|
||||
|
||||
public class ScreenLocation {
|
||||
|
||||
public int topX, topY, botX, botY;
|
||||
|
||||
public boolean found = false;
|
||||
|
||||
final int botOffsetX=15;
|
||||
final int botOffsetY=15;
|
||||
final int offsetX=15;
|
||||
final int offsetY=-101;
|
||||
|
||||
int width;
|
||||
int height;
|
||||
|
||||
}
|
@ -0,0 +1,477 @@
|
||||
package minesweeper.gamestate.msx;
|
||||
|
||||
import java.awt.AWTException;
|
||||
import java.awt.MouseInfo;
|
||||
import java.awt.Point;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.Robot;
|
||||
import java.awt.event.InputEvent;
|
||||
import java.awt.image.BufferedImage;
|
||||
|
||||
import window.controller.GetWindowRect;
|
||||
|
||||
public class ScreenScanner {
|
||||
|
||||
public static final int EXPLODED_BOMB = -4;
|
||||
public static final int BOMB = -2;
|
||||
public static final int HIDDEN = 0;
|
||||
public static final int EMPTY = -1;
|
||||
public static final int FLAG = -3;
|
||||
|
||||
private final static int[] digitCheckX = new int[] {6, 2, 10, 6, 2, 10, 6};
|
||||
private final static int[] digitCheckY = new int[] {3, 6, 6, 10, 16, 16, 20};
|
||||
|
||||
private class DigitCheck {
|
||||
|
||||
private boolean checks[];
|
||||
private int value;
|
||||
|
||||
private DigitCheck(int value, boolean... checks) {
|
||||
this.value = value;
|
||||
this.checks = checks;
|
||||
}
|
||||
|
||||
private boolean matches(boolean[] test) {
|
||||
for (int i = 0; i < checks.length; i++ ) {
|
||||
if (checks[i] != test[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private final DigitCheck DIGIT_ZERO = new DigitCheck(0, true, true, true, false, true, true, true);
|
||||
private final DigitCheck DIGIT_ONE = new DigitCheck(1, false, false, true, false, false, true, false);
|
||||
private final DigitCheck DIGIT_TWO = new DigitCheck(2, true, false, true, true, true, false, true);
|
||||
private final DigitCheck DIGIT_THREE = new DigitCheck(3, true, false, true, true, false, true, true);
|
||||
private final DigitCheck DIGIT_FOUR = new DigitCheck(4, false, true, true, true, false, true, false);
|
||||
private final DigitCheck DIGIT_FIVE = new DigitCheck(5, true, true, false, true, false, true, true);
|
||||
private final DigitCheck DIGIT_SIX = new DigitCheck(6, true, true, false, true, true, true, true);
|
||||
private final DigitCheck DIGIT_SEVEN = new DigitCheck(7, true, false, true, false, false, true, false);
|
||||
private final DigitCheck DIGIT_EIGHT = new DigitCheck(8, true, true, true, true, true, true, true);
|
||||
private final DigitCheck DIGIT_NINE = new DigitCheck(9, true, true, true, true, false, true, true);
|
||||
|
||||
private final DigitCheck[] DIGIT_LIST = new DigitCheck[] {DIGIT_ZERO, DIGIT_ONE, DIGIT_TWO, DIGIT_THREE, DIGIT_FOUR, DIGIT_FIVE, DIGIT_SIX, DIGIT_SEVEN, DIGIT_EIGHT, DIGIT_NINE};
|
||||
|
||||
|
||||
private String windowName;
|
||||
private ScreenLocation location;
|
||||
|
||||
final int offsetX=15;
|
||||
final int offsetY=-101;
|
||||
|
||||
final int botOffsetX=15;
|
||||
final int botOffsetY=15;
|
||||
|
||||
private Robot clicker;
|
||||
|
||||
|
||||
private int[][] field;
|
||||
private int rows;
|
||||
private int columns;
|
||||
private int mines;
|
||||
|
||||
private int numHidden;
|
||||
private int numEmpty;
|
||||
|
||||
private boolean dead = false;
|
||||
|
||||
public ScreenScanner(String windowName) {
|
||||
this.windowName = windowName;
|
||||
|
||||
try {
|
||||
clicker = new Robot();
|
||||
} catch (AWTException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
//System.out.println("Locate");
|
||||
locate();
|
||||
|
||||
// if we can't find the minesweeperX game then return
|
||||
if (!location.found) {
|
||||
return;
|
||||
}
|
||||
|
||||
//System.out.println("Start MSX " + columns + " by " + rows);
|
||||
startMinesweeperX(); // get focus
|
||||
startMinesweeperX(); // start
|
||||
|
||||
try {
|
||||
Thread.sleep(50);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
//System.out.println("Get mines");
|
||||
try {
|
||||
mines = getMineCount();
|
||||
} catch (AWTException e) {
|
||||
System.out.println("Failed to parse the mine counter");
|
||||
location.found = false;
|
||||
return;
|
||||
}
|
||||
|
||||
//System.out.println("update field");
|
||||
try {
|
||||
updateField();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void locate() {
|
||||
|
||||
location = new ScreenLocation();
|
||||
|
||||
//System.out.println("Locating minesweeper window... \nPlease do not move the window.");
|
||||
|
||||
int[] rect;
|
||||
|
||||
try {
|
||||
rect = GetWindowRect.getRect(windowName);
|
||||
//System.out.println("corner locations for minesweeper: \n"+ windowName+ Arrays.toString(rect));
|
||||
location.topX = rect[0];
|
||||
location.topY = rect[1];
|
||||
location.botX = rect[2];
|
||||
location.botY = rect[3];
|
||||
|
||||
int height = (location.botY - botOffsetY) - (location.topY - offsetY);
|
||||
int width = (location.botX - botOffsetX) - (location.topX + offsetX);
|
||||
|
||||
rows = height/16;
|
||||
columns = width/16;
|
||||
|
||||
if (rows < 1 || columns < 1) {
|
||||
location.found = false;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
} catch (GetWindowRect.WindowNotFoundException e){
|
||||
System.out.println("Please open minesweeper and try again");
|
||||
location.found = false;
|
||||
return;
|
||||
} catch (GetWindowRect.GetWindowRectException e){
|
||||
System.out.println(e.getMessage());
|
||||
location.found = false;
|
||||
return;
|
||||
}
|
||||
|
||||
location.found = true;
|
||||
|
||||
}
|
||||
|
||||
private int getMineCount() throws AWTException
|
||||
{
|
||||
int height = 22;
|
||||
int width = 38;
|
||||
|
||||
//System.out.println("window of size: " +width +"x" + height + "found");
|
||||
|
||||
Rectangle window = new Rectangle(location.topX + 20, location.topY + 62, width, height);
|
||||
Robot robot = new Robot();
|
||||
|
||||
BufferedImage screenShot = robot.createScreenCapture(window);
|
||||
|
||||
int d1 = getDigit(screenShot, 0);
|
||||
int d2 = getDigit(screenShot, 12);
|
||||
int d3 = getDigit(screenShot, 26);
|
||||
|
||||
int mines = d1 * 100 + d2 * 10 + d3;
|
||||
|
||||
System.out.println("mines = " + mines);
|
||||
|
||||
return mines;
|
||||
|
||||
}
|
||||
|
||||
private int getDigit(BufferedImage screenShot, int position) {
|
||||
|
||||
boolean[] results = new boolean[7];
|
||||
for (int i=0; i < digitCheckX.length; i++) {
|
||||
|
||||
int red = getRed(screenShot, position + digitCheckX[i], digitCheckY[i]);
|
||||
if (red == 255) {
|
||||
results[i] = true;
|
||||
} else {
|
||||
results[i] = false;
|
||||
}
|
||||
//System.out.println(" at " + digitCheckX[i] + ", " + digitCheckY[i] + " red is " + getRed(screenShot, digitCheckX[i], digitCheckY[i]));
|
||||
}
|
||||
|
||||
int integer = -1;
|
||||
for (DigitCheck dc: DIGIT_LIST) {
|
||||
if (dc.matches(results)) {
|
||||
integer = dc.value;
|
||||
}
|
||||
}
|
||||
|
||||
//System.out.println(integer);
|
||||
|
||||
return integer;
|
||||
|
||||
}
|
||||
|
||||
|
||||
private int getRed(BufferedImage screenShot, int x, int y) {
|
||||
|
||||
int rgb = screenShot.getRGB(x, y);
|
||||
final int red = (rgb & 0x00ff0000) >> 16;
|
||||
//final int green = (rgb & 0x0000ff00) >> 8;
|
||||
//final int blue = (rgb & 0x000000ff);
|
||||
|
||||
return red;
|
||||
|
||||
}
|
||||
|
||||
private BufferedImage getFieldImage() throws AWTException
|
||||
{
|
||||
int height = (location.botY - botOffsetY) - (location.topY - offsetY);
|
||||
int width = (location.botX - botOffsetX) - (location.topX + offsetX);
|
||||
|
||||
//System.out.println("window of size: " +width +"x" + height + "found");
|
||||
|
||||
Rectangle window = new Rectangle(location.topX + offsetX, location.topY - offsetY, width, height);
|
||||
Robot robot = new Robot();
|
||||
|
||||
BufferedImage screenShot = robot.createScreenCapture(window);
|
||||
|
||||
//rows = screenShot.getHeight()/16;
|
||||
//columns = screenShot.getWidth()/16;
|
||||
|
||||
field = new int[columns][rows];
|
||||
|
||||
return screenShot;
|
||||
|
||||
}
|
||||
|
||||
public void updateField() throws Exception
|
||||
{
|
||||
numHidden=0;
|
||||
//System.out.println("-UPDATING FIELD-");
|
||||
|
||||
BufferedImage screenShot = getFieldImage();
|
||||
|
||||
for(int x=0; x < columns; x++)
|
||||
for(int y=0; y < rows; y++)
|
||||
{
|
||||
//System.out.println("row: "+y+" of " + rows + ", column: "+x + " of " +columns);
|
||||
if(field[x][y]==HIDDEN || field[x][y] == FLAG) {
|
||||
field[x][y]=readTile(screenShot, x , y);
|
||||
if(field[x][y]==HIDDEN) {
|
||||
numHidden++;
|
||||
}
|
||||
} else if(field[x][y]==EMPTY)
|
||||
numEmpty++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void printField()
|
||||
{
|
||||
for(int y=rows+1;y>=0;y--)
|
||||
{
|
||||
System.out.print("[");
|
||||
for(int x=0;x<columns+2;x++)
|
||||
{
|
||||
//System.out.println("column: "+x+" row: "+y);
|
||||
System.out.print(field[x][y]+", ");
|
||||
}
|
||||
System.out.println("]");
|
||||
}
|
||||
}
|
||||
|
||||
private int readTile(BufferedImage image, int x, int y)
|
||||
{
|
||||
int tileType=0;//0=unknown,-1=empty -2=bomb, 1-8 are numbers
|
||||
|
||||
//System.out.println("tile to read: " + x + ", " + y);
|
||||
|
||||
int pixelX=(x)*16;
|
||||
//int pixelY=(rows-(y+1))*16;
|
||||
int pixelY=(y)*16;
|
||||
|
||||
//System.out.println("checking pixel color at: " + pixelX + ", "+pixelY);
|
||||
|
||||
String color="";
|
||||
|
||||
int n=1;
|
||||
do
|
||||
{
|
||||
color=getPixelColor(image, pixelX+8,pixelY+n);
|
||||
switch(color)
|
||||
{
|
||||
case("white"): {tileType=HIDDEN; n=16;} break;
|
||||
case("flag"): {tileType=FLAG; n=16;} break;
|
||||
case("blue"): {tileType=1; n=16;} break;
|
||||
case("green"): {tileType=2; n=16;} break;
|
||||
case("red"): {tileType=3; n=16;} break;
|
||||
case("purple"): {tileType=4; n=16;} break;
|
||||
case("brown"): {tileType=5; n=16;} break;
|
||||
case("teal"): {tileType=6; n=16;} break;
|
||||
case("black"): {tileType=7; n=16;} break;
|
||||
case("gray"): {tileType=8; n=16;} break;
|
||||
case("bomb"): {tileType=BOMB; n=16;} break;
|
||||
case("exp_bomb"): {tileType=EXPLODED_BOMB; n=16;} break;
|
||||
default: {tileType=EMPTY;} break;
|
||||
}
|
||||
n++;
|
||||
|
||||
}while(n<15);
|
||||
|
||||
//System.out.println("checking pixel color at: " + pixelX + ", "+pixelY + " x = " + x + " y = " + y + " colour " + color + " tiletype = " + tileType);
|
||||
|
||||
return tileType;
|
||||
}
|
||||
|
||||
private String getPixelColor(BufferedImage image, int x, int y)//get pixel color
|
||||
{
|
||||
String color = "empty";
|
||||
|
||||
final int clr = image.getRGB(x, y);
|
||||
final int red = (clr & 0x00ff0000) >> 16;
|
||||
final int green = (clr & 0x0000ff00) >> 8;
|
||||
final int blue = (clr & 0x000000ff);
|
||||
|
||||
if(red==255 && green==255 && blue==255) {
|
||||
//int flagCheckColor = (image.getRGB(x-2, y+12) & 0x00ffffff);
|
||||
//System.out.println("flag check = " + getRed(image, x, y+8));
|
||||
if (getRed(image, x, y+8) == 0) { // flag
|
||||
color = "flag";
|
||||
} else {
|
||||
color = "white";
|
||||
}
|
||||
}
|
||||
|
||||
else if(blue==255 && red==0 && green==0)
|
||||
color = "blue";
|
||||
else if(green==128 && red==0 && blue==0)
|
||||
color = "green";
|
||||
else if(red==255 && green==0 && blue==0)
|
||||
{
|
||||
color = "red";
|
||||
int deadCheckColor = (image.getRGB(x-4, y+8) & 0x00ffffff);
|
||||
if(deadCheckColor==0)
|
||||
{
|
||||
dead=true;
|
||||
color="exp_bomb";
|
||||
}
|
||||
}
|
||||
else if(blue==128 && red==0 && green==0)
|
||||
color = "purple";
|
||||
else if(red==128 && green==0 && blue==0)
|
||||
color = "brown";
|
||||
else if(red==0 && green==128 && blue==128)
|
||||
color = "teal";
|
||||
else if(red==0 && green==0 && blue==0)
|
||||
{
|
||||
color = "black";
|
||||
|
||||
int deadCheckColor = (image.getRGB(x-4, y+8) & 0x00ffffff);
|
||||
|
||||
//System.out.println(deadCheckColor);
|
||||
if(deadCheckColor==0)
|
||||
{
|
||||
dead=true;
|
||||
color="bomb";
|
||||
}
|
||||
}
|
||||
else if(red==128 && green==128 && blue==128)
|
||||
color = "gray";
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
|
||||
private void click(int x, int y, int mask)
|
||||
{
|
||||
//int mask;
|
||||
|
||||
Point p = MouseInfo.getPointerInfo().getLocation();
|
||||
|
||||
//System.out.println("CLICKING - "+ x +", "+y);
|
||||
|
||||
/*
|
||||
if(flag)
|
||||
mask = InputEvent.BUTTON1_DOWN_MASK;
|
||||
else
|
||||
mask = InputEvent.BUTTON3_DOWN_MASK;
|
||||
*/
|
||||
|
||||
// release the mouse (to remove the human click if there was one)
|
||||
clicker.mouseRelease(InputEvent.BUTTON1_DOWN_MASK | InputEvent.BUTTON3_DOWN_MASK);
|
||||
|
||||
int pixelX=(x*16)+8;
|
||||
//int pixelY=Math.abs((rows-y - 1 )*16)+8;
|
||||
int pixelY=(y*16)+8;
|
||||
|
||||
pixelX+= location.topX + offsetX;
|
||||
pixelY+= location.topY - offsetY;
|
||||
|
||||
clicker.mouseMove(pixelX, pixelY);
|
||||
|
||||
clicker.mousePress(mask);
|
||||
|
||||
clicker.mouseRelease(mask);
|
||||
|
||||
|
||||
// move mouse back again
|
||||
clicker.mouseMove(p.x, p.y);
|
||||
|
||||
}
|
||||
|
||||
public boolean isValid() {
|
||||
return this.location.found;
|
||||
}
|
||||
|
||||
public int getColumns() {
|
||||
return columns;
|
||||
}
|
||||
|
||||
public int getRows() {
|
||||
return rows;
|
||||
}
|
||||
|
||||
public int getMines() {
|
||||
return mines;
|
||||
}
|
||||
|
||||
public int getValue(int x, int y) {
|
||||
return field[x][y];
|
||||
}
|
||||
|
||||
public void clear(int x, int y) {
|
||||
click(x, y, InputEvent.BUTTON1_DOWN_MASK);
|
||||
}
|
||||
|
||||
public void flag(int x, int y) {
|
||||
click(x, y, InputEvent.BUTTON3_DOWN_MASK);
|
||||
}
|
||||
|
||||
public void clearAll(int x, int y) {
|
||||
click(x, y, InputEvent.BUTTON1_DOWN_MASK | InputEvent.BUTTON3_DOWN_MASK);
|
||||
}
|
||||
|
||||
public int getHiddenCount() {
|
||||
return numHidden;
|
||||
}
|
||||
|
||||
public boolean isGameLost() {
|
||||
return dead;
|
||||
}
|
||||
|
||||
public void startMinesweeperX() {
|
||||
|
||||
int x = columns / 2;
|
||||
int y = - 2;
|
||||
|
||||
click(x, y, InputEvent.BUTTON1_DOWN_MASK);
|
||||
|
||||
}
|
||||
}
|
After Width: | Height: | Size: 779 B |
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 5.8 KiB |
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 978 B |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 2.3 KiB |
After Width: | Height: | Size: 2.3 KiB |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 2.7 KiB |
After Width: | Height: | Size: 495 B |