Initial commit
commit
1d806f85a3
|
|
@ -0,0 +1,38 @@
|
||||||
|
target/
|
||||||
|
!.mvn/wrapper/maven-wrapper.jar
|
||||||
|
!**/src/main/**/target/
|
||||||
|
!**/src/test/**/target/
|
||||||
|
|
||||||
|
### IntelliJ IDEA ###
|
||||||
|
.idea/modules.xml
|
||||||
|
.idea/jarRepositories.xml
|
||||||
|
.idea/compiler.xml
|
||||||
|
.idea/libraries/
|
||||||
|
*.iws
|
||||||
|
*.iml
|
||||||
|
*.ipr
|
||||||
|
|
||||||
|
### Eclipse ###
|
||||||
|
.apt_generated
|
||||||
|
.classpath
|
||||||
|
.factorypath
|
||||||
|
.project
|
||||||
|
.settings
|
||||||
|
.springBeans
|
||||||
|
.sts4-cache
|
||||||
|
|
||||||
|
### NetBeans ###
|
||||||
|
/nbproject/private/
|
||||||
|
/nbbuild/
|
||||||
|
/dist/
|
||||||
|
/nbdist/
|
||||||
|
/.nb-gradle/
|
||||||
|
build/
|
||||||
|
!**/src/main/**/build/
|
||||||
|
!**/src/test/**/build/
|
||||||
|
|
||||||
|
### VS Code ###
|
||||||
|
.vscode/
|
||||||
|
|
||||||
|
### Mac OS ###
|
||||||
|
.DS_Store
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings" defaultProject="true" />
|
||||||
|
</project>
|
||||||
Binary file not shown.
|
|
@ -0,0 +1,182 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<groupId>de.hs_mannheim.informatik.backend</groupId>
|
||||||
|
<artifactId>HitoriFinal</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<maven.compiler.source>20</maven.compiler.source>
|
||||||
|
<maven.compiler.target>20</maven.compiler.target>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
<javafx.version>20.0.2</javafx.version>
|
||||||
|
<java.version>20</java.version>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<repositories>
|
||||||
|
<repository>
|
||||||
|
<id>central</id>
|
||||||
|
<url>https://repo.maven.apache.org/maven2</url>
|
||||||
|
</repository>
|
||||||
|
</repositories>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit.jupiter</groupId>
|
||||||
|
<artifactId>junit-jupiter-api</artifactId>
|
||||||
|
<version>5.8.1</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit.jupiter</groupId>
|
||||||
|
<artifactId>junit-jupiter-engine</artifactId>
|
||||||
|
<version>5.8.1</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.logging.log4j</groupId>
|
||||||
|
<artifactId>log4j-core</artifactId>
|
||||||
|
<version>2.24.2</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- JavaFX Dependencies -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.openjfx</groupId>
|
||||||
|
<artifactId>javafx-controls</artifactId>
|
||||||
|
<version>${javafx.version}</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.openjfx</groupId>
|
||||||
|
<artifactId>javafx-fxml</artifactId>
|
||||||
|
<version>${javafx.version}</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.openjfx</groupId>
|
||||||
|
<artifactId>javafx-base</artifactId>
|
||||||
|
<version>${javafx.version}</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- JUnit for Testing -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>junit</groupId>
|
||||||
|
<artifactId>junit</artifactId>
|
||||||
|
<version>4.13.2</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<!-- Compiler -->
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<version>3.13.0</version>
|
||||||
|
<configuration>
|
||||||
|
<source>${maven.compiler.source}</source>
|
||||||
|
<target>${maven.compiler.target}</target>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.openjfx</groupId>
|
||||||
|
<artifactId>javafx-maven-plugin</artifactId>
|
||||||
|
<version>0.0.1</version>
|
||||||
|
<configuration>
|
||||||
|
<mainClass>Main.MainMethod</mainClass>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- JAR creation -->
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-shade-plugin</artifactId>
|
||||||
|
<version>3.6.0</version>
|
||||||
|
<configuration>
|
||||||
|
<createDependencyReducedPom>false</createDependencyReducedPom>
|
||||||
|
</configuration>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<phase>package</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>shade</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<transformers>
|
||||||
|
<transformer
|
||||||
|
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
|
||||||
|
<mainClass>Main.MainMethod</mainClass>
|
||||||
|
</transformer>
|
||||||
|
</transformers>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
<!-- Code coverage, cf.: target/site/jacoco -->
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.jacoco</groupId>
|
||||||
|
<artifactId>jacoco-maven-plugin</artifactId>
|
||||||
|
<version>0.8.12</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<goals>
|
||||||
|
<goal>prepare-agent</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
<execution>
|
||||||
|
<id>report</id>
|
||||||
|
<phase>test</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>report</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
<!-- Static code analysis, cf: target/site/pmd.html -->
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-pmd-plugin</artifactId>
|
||||||
|
<version>3.26.0</version>
|
||||||
|
<configuration>
|
||||||
|
<failOnViolation>false</failOnViolation>
|
||||||
|
<printFailingErrors>true</printFailingErrors>
|
||||||
|
</configuration>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<phase>verify</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>check</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
<reporting>
|
||||||
|
<plugins>
|
||||||
|
<!-- generate Javadocs via "mvn site" and find them in the site
|
||||||
|
folder -->
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-javadoc-plugin</artifactId>
|
||||||
|
<version>3.11.2</version>
|
||||||
|
<configuration>
|
||||||
|
<show>private</show>
|
||||||
|
<nohelp>true</nohelp>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-checkstyle-plugin</artifactId>
|
||||||
|
<version>3.6.0</version>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</reporting>
|
||||||
|
</project>
|
||||||
|
|
@ -0,0 +1,221 @@
|
||||||
|
package GUI;
|
||||||
|
|
||||||
|
import domain.*;
|
||||||
|
import GUI.HitoriDialogManager;
|
||||||
|
import javafx.application.Platform;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class GameUIController {
|
||||||
|
private final HitoriGameMoves gameMoves;
|
||||||
|
private final GameSolver gameSolver;
|
||||||
|
private final domain.HitoriGameTimer gameTimer;
|
||||||
|
private final HitoriGameScores gameScores;
|
||||||
|
private final GUI.HitoriDialogManager dialogManager;
|
||||||
|
private final GUI.HitoriBoardPanel boardPanel;
|
||||||
|
private final GUI.HitoriControlPanel controlPanel;
|
||||||
|
private final GUI.HitoriScorePanel scorePanel;
|
||||||
|
private Timer guiTimer;
|
||||||
|
private boolean isPaused;
|
||||||
|
|
||||||
|
public GameUIController(int[][] initialBoard, HitoriDialogManager dialogManager) {
|
||||||
|
this.gameMoves = new HitoriGameMoves(initialBoard);
|
||||||
|
this.gameSolver = new GameSolver(initialBoard);
|
||||||
|
this.gameTimer = new domain.HitoriGameTimer();
|
||||||
|
this.gameScores = new HitoriGameScores();
|
||||||
|
this.dialogManager = dialogManager;
|
||||||
|
this.isPaused = false;
|
||||||
|
|
||||||
|
this.boardPanel = new GUI.HitoriBoardPanel(gameMoves, gameSolver, this);
|
||||||
|
this.controlPanel = new GUI.HitoriControlPanel(this);
|
||||||
|
this.scorePanel = new GUI.HitoriScorePanel(this);
|
||||||
|
|
||||||
|
startTimer();
|
||||||
|
loadHighScores();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void handleLeftClick(int row, int col) {
|
||||||
|
gameMoves.markCellAsBlack(row, col);
|
||||||
|
updateUI();
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void handleRightClick(int row, int col) {
|
||||||
|
gameMoves.markCellAsWhite(row, col);
|
||||||
|
updateUI();
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void togglePause() {
|
||||||
|
isPaused = !isPaused;
|
||||||
|
if (isPaused) {
|
||||||
|
gameTimer.pauseTimer();
|
||||||
|
controlPanel.setPauseButtonText("Resume");
|
||||||
|
boardPanel.setDisable(true);
|
||||||
|
} else {
|
||||||
|
gameTimer.startTimer();
|
||||||
|
controlPanel.setPauseButtonText("Pause");
|
||||||
|
boardPanel.setDisable(false);
|
||||||
|
}
|
||||||
|
updateTimerLabel();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void resetGame() {
|
||||||
|
gameMoves.reset();
|
||||||
|
gameTimer.resetTimer();
|
||||||
|
updateUI();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void undo() {
|
||||||
|
if (gameMoves.undo()) {
|
||||||
|
updateUI();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void redo() {
|
||||||
|
if (gameMoves.redo()) {
|
||||||
|
updateUI();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void newGame() {
|
||||||
|
stopTimer();
|
||||||
|
// Notify main application to show board selection
|
||||||
|
}
|
||||||
|
|
||||||
|
public void checkSolution() {
|
||||||
|
if (gameSolver.isSolved()) {
|
||||||
|
handleWin();
|
||||||
|
} else {
|
||||||
|
dialogManager.showAlert("Not Solved", "The current solution is not correct. Keep trying!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void showErrors() {
|
||||||
|
List<int[]> errors = gameSolver.findIncorrectBlackMarks();
|
||||||
|
if (errors.isEmpty()) {
|
||||||
|
dialogManager.showAlert("No Errors", "No rule violations found in current black markings.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
boardPanel.showErrors();
|
||||||
|
StringBuilder message = new StringBuilder("Found " + errors.size() + " error(s):\n");
|
||||||
|
for (int[] pos : errors) {
|
||||||
|
message.append(String.format("Row %d, Column %d\n", pos[0] + 1, pos[1] + 1));
|
||||||
|
}
|
||||||
|
dialogManager.showAlert("Errors Found", message.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void saveGame() {
|
||||||
|
// Implementation for saving game state
|
||||||
|
dialogManager.showAlert("Game Saved", "Your game has been saved successfully.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void deleteHighScores() {
|
||||||
|
if (dialogManager.confirmDeleteHighScores()) {
|
||||||
|
gameScores.deleteHighScores();
|
||||||
|
updateHighScoreDisplay();
|
||||||
|
dialogManager.showAlert("High Scores Deleted", "All high scores have been deleted successfully.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleWin() {
|
||||||
|
stopTimer();
|
||||||
|
Optional<String> playerName = dialogManager.askForPlayerName();
|
||||||
|
if (playerName.isPresent() && !playerName.get().trim().isEmpty()) {
|
||||||
|
gameScores.addHighScore(playerName.get(), gameTimer.getElapsedTimeInSeconds(), gameMoves.getMistakeCount());
|
||||||
|
updateHighScoreDisplay();
|
||||||
|
dialogManager.showAlert("Congratulations!", String.format(
|
||||||
|
"You've solved the puzzle!\nTime: %ds\nMistakes: %d",
|
||||||
|
gameTimer.getElapsedTimeInSeconds(),
|
||||||
|
gameMoves.getMistakeCount()
|
||||||
|
));
|
||||||
|
|
||||||
|
isPaused = false;
|
||||||
|
boardPanel.setDisable(false);
|
||||||
|
controlPanel.setPauseButtonText("Pause");
|
||||||
|
|
||||||
|
if (dialogManager.confirmNewGame()) {
|
||||||
|
newGame();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void startTimer() {
|
||||||
|
if (guiTimer != null) {
|
||||||
|
guiTimer.cancel();
|
||||||
|
}
|
||||||
|
gameTimer.startTimer();
|
||||||
|
guiTimer = new Timer(true);
|
||||||
|
guiTimer.scheduleAtFixedRate(new TimerTask() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
Platform.runLater(() -> {
|
||||||
|
if (!isPaused) {
|
||||||
|
updateTimerLabel();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, 0, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void stopTimer() {
|
||||||
|
if (guiTimer != null) {
|
||||||
|
guiTimer.cancel();
|
||||||
|
guiTimer = null;
|
||||||
|
}
|
||||||
|
gameTimer.stopTimer();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateUI() {
|
||||||
|
boardPanel.updateBoard();
|
||||||
|
updateMistakeLabel();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateTimerLabel() {
|
||||||
|
controlPanel.updateTimerLabel(gameTimer.getElapsedTimeInSeconds());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateMistakeLabel() {
|
||||||
|
controlPanel.updateMistakeLabel(gameMoves.getMistakeCount());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateHighScoreDisplay() {
|
||||||
|
scorePanel.updateHighScores(String.join("\n", gameScores.getHighScoresWithAverage()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadHighScores() {
|
||||||
|
gameScores.loadHighScoresFromFile();
|
||||||
|
updateHighScoreDisplay();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<String> convertErrorsToSet(List<int[]> errors) {
|
||||||
|
Set<String> errorPositions = new HashSet<>();
|
||||||
|
for (int[] pos : errors) {
|
||||||
|
errorPositions.add(pos[0] + "," + pos[1]);
|
||||||
|
}
|
||||||
|
return errorPositions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isPaused() {
|
||||||
|
return isPaused;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cleanup() {
|
||||||
|
stopTimer();
|
||||||
|
saveGame();
|
||||||
|
}
|
||||||
|
|
||||||
|
public HitoriBoardPanel getBoardPanel() {
|
||||||
|
return boardPanel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HitoriControlPanel getControlPanel() {
|
||||||
|
return controlPanel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HitoriScorePanel getScorePanel() {
|
||||||
|
return scorePanel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,94 @@
|
||||||
|
package GUI;
|
||||||
|
|
||||||
|
import domain.GameSolver;
|
||||||
|
import domain.HitoriGameMoves;
|
||||||
|
import javafx.geometry.Insets;
|
||||||
|
import javafx.scene.control.Button;
|
||||||
|
import javafx.scene.input.MouseButton;
|
||||||
|
import javafx.scene.layout.GridPane;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class HitoriBoardPanel extends GridPane {
|
||||||
|
private final HitoriGameMoves gameMoves;
|
||||||
|
private final GameSolver gameSolver;
|
||||||
|
private final GameUIController controller;
|
||||||
|
|
||||||
|
public HitoriBoardPanel(HitoriGameMoves gameMoves, GameSolver gameSolver, GameUIController controller) {
|
||||||
|
this.gameMoves = gameMoves;
|
||||||
|
this.gameSolver = gameSolver;
|
||||||
|
this.controller = controller;
|
||||||
|
|
||||||
|
setHgap(5);
|
||||||
|
setVgap(5);
|
||||||
|
setPadding(new Insets(10));
|
||||||
|
|
||||||
|
updateBoard();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateBoard() {
|
||||||
|
getChildren().clear();
|
||||||
|
int[][] boardState = gameMoves.getBoard();
|
||||||
|
boolean[][] blackCells = gameMoves.getBlackCells();
|
||||||
|
boolean[][] whiteCells = gameMoves.getWhiteCells();
|
||||||
|
|
||||||
|
for (int row = 0; row < boardState.length; row++) {
|
||||||
|
for (int col = 0; col < boardState[row].length; col++) {
|
||||||
|
Button cellButton = createCellButton(row, col, boardState[row][col],
|
||||||
|
blackCells[row][col], whiteCells[row][col]);
|
||||||
|
add(cellButton, col, row);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void showErrors() {
|
||||||
|
var errors = gameSolver.findIncorrectBlackMarks();
|
||||||
|
Set<String> errorPositions = controller.convertErrorsToSet(errors);
|
||||||
|
|
||||||
|
getChildren().clear();
|
||||||
|
int[][] boardState = gameMoves.getBoard();
|
||||||
|
boolean[][] blackCells = gameMoves.getBlackCells();
|
||||||
|
boolean[][] whiteCells = gameMoves.getWhiteCells();
|
||||||
|
|
||||||
|
for (int row = 0; row < boardState.length; row++) {
|
||||||
|
for (int col = 0; col < boardState[row].length; col++) {
|
||||||
|
Button cellButton = createCellButton(row, col, boardState[row][col],
|
||||||
|
blackCells[row][col], whiteCells[row][col]);
|
||||||
|
|
||||||
|
if (errorPositions.contains(row + "," + col) && blackCells[row][col]) {
|
||||||
|
cellButton.setStyle("-fx-background-color: red; -fx-text-fill: white;");
|
||||||
|
}
|
||||||
|
|
||||||
|
add(cellButton, col, row);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Button createCellButton(int row, int col, int value, boolean isBlack, boolean isWhite) {
|
||||||
|
Button cellButton = new Button(String.valueOf(value));
|
||||||
|
cellButton.setPrefSize(50, 50);
|
||||||
|
styleCellButton(cellButton, isBlack, isWhite);
|
||||||
|
|
||||||
|
cellButton.setOnMouseClicked(event -> {
|
||||||
|
if (!controller.isPaused()) {
|
||||||
|
if (event.getButton() == MouseButton.PRIMARY) {
|
||||||
|
controller.handleLeftClick(row, col);
|
||||||
|
} else if (event.getButton() == MouseButton.SECONDARY) {
|
||||||
|
controller.handleRightClick(row, col);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return cellButton;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void styleCellButton(Button button, boolean isBlack, boolean isWhite) {
|
||||||
|
if (isBlack) {
|
||||||
|
button.setStyle("-fx-background-color: black; -fx-text-fill: white;");
|
||||||
|
} else if (isWhite) {
|
||||||
|
button.setStyle("-fx-background-color: white; -fx-text-fill: black; -fx-border-color: gray;");
|
||||||
|
} else {
|
||||||
|
button.setStyle("-fx-background-color: lightgray; -fx-text-fill: black;");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,67 @@
|
||||||
|
package GUI;
|
||||||
|
|
||||||
|
|
||||||
|
import javafx.geometry.Insets;
|
||||||
|
import javafx.geometry.Pos;
|
||||||
|
import javafx.scene.control.Button;
|
||||||
|
import javafx.scene.control.Label;
|
||||||
|
import javafx.scene.layout.HBox;
|
||||||
|
import javafx.scene.layout.VBox;
|
||||||
|
|
||||||
|
public class HitoriControlPanel extends VBox {
|
||||||
|
private final GameUIController controller;
|
||||||
|
private final Label timerLabel;
|
||||||
|
private final Label mistakeLabel;
|
||||||
|
private final Button pauseButton;
|
||||||
|
|
||||||
|
public HitoriControlPanel(GameUIController controller) {
|
||||||
|
this.controller = controller;
|
||||||
|
|
||||||
|
// Timer box setup
|
||||||
|
HBox timerBox = new HBox(10);
|
||||||
|
timerLabel = new Label("Time: 0s");
|
||||||
|
mistakeLabel = new Label("Mistakes: 0");
|
||||||
|
pauseButton = new Button("Pause");
|
||||||
|
timerBox.getChildren().addAll(timerLabel, mistakeLabel, pauseButton);
|
||||||
|
timerBox.setAlignment(Pos.CENTER);
|
||||||
|
|
||||||
|
// Button box setup
|
||||||
|
HBox buttonBox = new HBox(10);
|
||||||
|
Button resetButton = new Button("Reset");
|
||||||
|
Button undoButton = new Button("Undo");
|
||||||
|
Button redoButton = new Button("Redo");
|
||||||
|
Button checkButton = new Button("Check Solution");
|
||||||
|
Button newGameButton = new Button("New Game");
|
||||||
|
Button showErrorsButton = new Button("Show Errors");
|
||||||
|
|
||||||
|
buttonBox.getChildren().addAll(resetButton, undoButton, redoButton,
|
||||||
|
checkButton, newGameButton, showErrorsButton);
|
||||||
|
buttonBox.setAlignment(Pos.CENTER);
|
||||||
|
|
||||||
|
// Event handlers
|
||||||
|
pauseButton.setOnAction(e -> controller.togglePause());
|
||||||
|
resetButton.setOnAction(e -> controller.resetGame());
|
||||||
|
undoButton.setOnAction(e -> controller.undo());
|
||||||
|
redoButton.setOnAction(e -> controller.redo());
|
||||||
|
newGameButton.setOnAction(e -> controller.newGame());
|
||||||
|
checkButton.setOnAction(e -> controller.checkSolution());
|
||||||
|
showErrorsButton.setOnAction(e -> controller.showErrors());
|
||||||
|
|
||||||
|
// Layout setup
|
||||||
|
getChildren().addAll(timerBox, buttonBox);
|
||||||
|
setPadding(new Insets(10));
|
||||||
|
setSpacing(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateTimerLabel(long seconds) {
|
||||||
|
timerLabel.setText("Time: " + seconds + "s");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateMistakeLabel(int mistakes) {
|
||||||
|
mistakeLabel.setText("Mistakes: " + mistakes);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPauseButtonText(String text) {
|
||||||
|
pauseButton.setText(text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,116 @@
|
||||||
|
package GUI;
|
||||||
|
|
||||||
|
import domain.HitoriBoardLoader;
|
||||||
|
import javafx.scene.Scene;
|
||||||
|
import javafx.scene.control.*;
|
||||||
|
import javafx.scene.layout.VBox;
|
||||||
|
import javafx.stage.Modality;
|
||||||
|
import javafx.stage.Window;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
|
||||||
|
public class HitoriDialogManager {
|
||||||
|
private final Window owner;
|
||||||
|
|
||||||
|
public HitoriDialogManager(Window owner) {
|
||||||
|
this.owner = owner;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<String> showBoardSelectionDialog(HitoriBoardLoader boardLoader) {
|
||||||
|
Dialog<String> dialog = new Dialog<>();
|
||||||
|
dialog.setTitle("Select Hitori Board");
|
||||||
|
dialog.setHeaderText("Choose a board to play:");
|
||||||
|
|
||||||
|
if (owner != null && owner.getScene() != null) {
|
||||||
|
dialog.initOwner(owner);
|
||||||
|
dialog.initModality(Modality.APPLICATION_MODAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
ButtonType selectButtonType = new ButtonType("Play", ButtonBar.ButtonData.OK_DONE);
|
||||||
|
ButtonType randomButtonType = new ButtonType("Random", ButtonBar.ButtonData.OTHER);
|
||||||
|
dialog.getDialogPane().getButtonTypes().addAll(selectButtonType, randomButtonType, ButtonType.CANCEL);
|
||||||
|
|
||||||
|
ChoiceBox<String> boardChoice = new ChoiceBox<>();
|
||||||
|
boardChoice.getItems().addAll(boardLoader.getAvailableBoardNames());
|
||||||
|
if (!boardChoice.getItems().isEmpty()) {
|
||||||
|
boardChoice.setValue(boardChoice.getItems().get(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
VBox content = new VBox(10);
|
||||||
|
content.getChildren().add(boardChoice);
|
||||||
|
dialog.getDialogPane().setContent(content);
|
||||||
|
|
||||||
|
dialog.setResultConverter(dialogButton -> {
|
||||||
|
if (dialogButton == selectButtonType) {
|
||||||
|
return boardChoice.getValue();
|
||||||
|
} else if (dialogButton == randomButtonType) {
|
||||||
|
int random = (int) (Math.random() * boardChoice.getItems().size());
|
||||||
|
return boardChoice.getItems().get(random);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
|
||||||
|
return dialog.showAndWait();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void showAlert(String title, String message) {
|
||||||
|
Alert alert = new Alert(Alert.AlertType.INFORMATION);
|
||||||
|
alert.setTitle(title);
|
||||||
|
alert.setHeaderText(null);
|
||||||
|
alert.setContentText(message);
|
||||||
|
alert.initOwner(owner);
|
||||||
|
alert.showAndWait();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<String> askForPlayerName() {
|
||||||
|
TextInputDialog dialog = new TextInputDialog();
|
||||||
|
dialog.setTitle("High Score");
|
||||||
|
dialog.setHeaderText("Congratulations! Enter your name:");
|
||||||
|
dialog.setContentText("Name:");
|
||||||
|
dialog.initOwner(owner);
|
||||||
|
return dialog.showAndWait();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean confirmDeleteHighScores() {
|
||||||
|
Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
|
||||||
|
alert.setTitle("Delete High Scores");
|
||||||
|
alert.setHeaderText("Are you sure?");
|
||||||
|
alert.setContentText("This will permanently delete all high scores.");
|
||||||
|
alert.initOwner(owner);
|
||||||
|
|
||||||
|
Optional<ButtonType> result = alert.showAndWait();
|
||||||
|
return result.isPresent() && result.get() == ButtonType.OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean confirmNewGame() {
|
||||||
|
Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
|
||||||
|
alert.setTitle("Game Complete");
|
||||||
|
alert.setHeaderText("Would you like to start a new game?");
|
||||||
|
alert.setContentText("Choose whether to start a new game or continue viewing this one.");
|
||||||
|
|
||||||
|
ButtonType buttonTypeNew = new ButtonType("New Game");
|
||||||
|
ButtonType buttonTypeStay = new ButtonType("Stay Here", ButtonBar.ButtonData.CANCEL_CLOSE);
|
||||||
|
|
||||||
|
alert.getButtonTypes().setAll(buttonTypeNew, buttonTypeStay);
|
||||||
|
alert.initOwner(owner);
|
||||||
|
|
||||||
|
Optional<ButtonType> result = alert.showAndWait();
|
||||||
|
return result.isPresent() && result.get() == buttonTypeNew;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean confirmLoadSavedGame() {
|
||||||
|
Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
|
||||||
|
alert.setTitle("Saved Game Found");
|
||||||
|
alert.setHeaderText("Would you like to continue your saved game?");
|
||||||
|
alert.setContentText("Choose whether to load the saved game or start a new one.");
|
||||||
|
|
||||||
|
ButtonType buttonTypeYes = new ButtonType("Load Saved Game");
|
||||||
|
ButtonType buttonTypeNo = new ButtonType("Start New Game");
|
||||||
|
|
||||||
|
alert.getButtonTypes().setAll(buttonTypeYes, buttonTypeNo);
|
||||||
|
alert.initOwner(owner);
|
||||||
|
|
||||||
|
Optional<ButtonType> result = alert.showAndWait();
|
||||||
|
return result.isPresent() && result.get() == buttonTypeYes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
package GUI;
|
||||||
|
|
||||||
|
import GUI.GameUIController;
|
||||||
|
import javafx.geometry.Insets;
|
||||||
|
import javafx.geometry.Pos;
|
||||||
|
import javafx.scene.control.Button;
|
||||||
|
import javafx.scene.control.Label;
|
||||||
|
import javafx.scene.control.TextArea;
|
||||||
|
import javafx.scene.layout.VBox;
|
||||||
|
|
||||||
|
public class HitoriScorePanel extends VBox {
|
||||||
|
private final GameUIController controller;
|
||||||
|
private final TextArea highScoreArea;
|
||||||
|
|
||||||
|
public HitoriScorePanel(GameUIController controller) {
|
||||||
|
this.controller = controller;
|
||||||
|
|
||||||
|
setPadding(new Insets(10));
|
||||||
|
setAlignment(Pos.TOP_CENTER);
|
||||||
|
|
||||||
|
Label highScoreLabel = new Label("High Scores");
|
||||||
|
highScoreArea = new TextArea();
|
||||||
|
highScoreArea.setEditable(false);
|
||||||
|
highScoreArea.setPrefRowCount(10);
|
||||||
|
highScoreArea.setPrefColumnCount(30);
|
||||||
|
|
||||||
|
Button saveButton = new Button("Save Game");
|
||||||
|
Button deleteHighScoresButton = new Button("Delete High Scores");
|
||||||
|
|
||||||
|
saveButton.setOnAction(e -> controller.saveGame());
|
||||||
|
deleteHighScoresButton.setOnAction(e -> controller.deleteHighScores());
|
||||||
|
|
||||||
|
getChildren().addAll(highScoreLabel, highScoreArea, saveButton, deleteHighScoresButton);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateHighScores(String highScores) {
|
||||||
|
highScoreArea.setText(highScores);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,96 @@
|
||||||
|
package Main;
|
||||||
|
|
||||||
|
|
||||||
|
import domain.HitoriGameMain;
|
||||||
|
import domain.HitoriBoardLoader;
|
||||||
|
import GUI.GameUIController;
|
||||||
|
import GUI.HitoriDialogManager;
|
||||||
|
import javafx.application.Application;
|
||||||
|
import javafx.scene.Scene;
|
||||||
|
import javafx.scene.layout.BorderPane;
|
||||||
|
import javafx.stage.Stage;
|
||||||
|
|
||||||
|
public class MainMethod extends Application {
|
||||||
|
private HitoriBoardLoader boardLoader;
|
||||||
|
private GameUIController controller;
|
||||||
|
private HitoriDialogManager dialogManager;
|
||||||
|
private String currentBoardName;
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
launch(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void start(Stage primaryStage) {
|
||||||
|
boardLoader = new HitoriBoardLoader();
|
||||||
|
dialogManager = new HitoriDialogManager(primaryStage);
|
||||||
|
|
||||||
|
checkSavedGame(primaryStage);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkSavedGame(Stage primaryStage) {
|
||||||
|
HitoriGameMain savedGame = HitoriGameMain.loadGameState();
|
||||||
|
if (savedGame != null) {
|
||||||
|
if (dialogManager.confirmLoadSavedGame()) {
|
||||||
|
initializeGame(savedGame.getBoard(), primaryStage);
|
||||||
|
} else {
|
||||||
|
showBoardSelectionDialog(primaryStage);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
showBoardSelectionDialog(primaryStage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showBoardSelectionDialog(Stage primaryStage) {
|
||||||
|
dialogManager.showBoardSelectionDialog(boardLoader).ifPresentOrElse(
|
||||||
|
boardName -> {
|
||||||
|
currentBoardName = boardName;
|
||||||
|
int[][] selectedBoard = boardLoader.getBoard(boardName);
|
||||||
|
if (selectedBoard != null) {
|
||||||
|
initializeGame(selectedBoard, primaryStage);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
() -> System.exit(0)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initializeGame(int[][] board, Stage primaryStage) {
|
||||||
|
controller = new GameUIController(board, dialogManager);
|
||||||
|
createGameUI(primaryStage);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createGameUI(Stage primaryStage) {
|
||||||
|
primaryStage.setTitle("Hitori Game - " + currentBoardName);
|
||||||
|
|
||||||
|
BorderPane mainLayout = new BorderPane();
|
||||||
|
mainLayout.setCenter(controller.getBoardPanel());
|
||||||
|
mainLayout.setTop(controller.getControlPanel());
|
||||||
|
mainLayout.setRight(controller.getScorePanel());
|
||||||
|
|
||||||
|
Scene scene = new Scene(mainLayout, 800, 600);
|
||||||
|
primaryStage.setScene(scene);
|
||||||
|
|
||||||
|
// Window state listeners
|
||||||
|
primaryStage.iconifiedProperty().addListener((observable, oldValue, newValue) -> {
|
||||||
|
if (newValue && !controller.isPaused()) {
|
||||||
|
controller.togglePause();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
primaryStage.focusedProperty().addListener((observable, oldValue, newValue) -> {
|
||||||
|
if (!newValue && !controller.isPaused()) {
|
||||||
|
controller.togglePause();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
primaryStage.setOnCloseRequest(event -> controller.cleanup());
|
||||||
|
primaryStage.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void stop() {
|
||||||
|
if (controller != null) {
|
||||||
|
controller.cleanup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
package domain;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
public class GameBase implements Serializable {
|
||||||
|
|
||||||
|
protected int[][] board;
|
||||||
|
public boolean[][] blackCells;
|
||||||
|
public boolean[][] whiteCells;
|
||||||
|
protected int mistakeCount;
|
||||||
|
|
||||||
|
public GameBase(int[][] initialBoard) {
|
||||||
|
this.board = new int[initialBoard.length][initialBoard[0].length];
|
||||||
|
for (int i = 0; i < initialBoard.length; i++) {
|
||||||
|
this.board[i] = Arrays.copyOf(initialBoard[i], initialBoard[i].length);
|
||||||
|
}
|
||||||
|
this.blackCells = new boolean[board.length][board[0].length];
|
||||||
|
this.whiteCells = new boolean[board.length][board[0].length];
|
||||||
|
this.mistakeCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reset() {
|
||||||
|
blackCells = new boolean[board.length][board[0].length];
|
||||||
|
whiteCells = new boolean[board.length][board[0].length];
|
||||||
|
mistakeCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int[][] getBoard() {
|
||||||
|
return board;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int[][] getCurrentState() {
|
||||||
|
return board;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean[][] getBlackCells() {
|
||||||
|
return blackCells;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean[][] getWhiteCells() {
|
||||||
|
return whiteCells;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMistakeCount() {
|
||||||
|
return mistakeCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,123 @@
|
||||||
|
package domain;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class GameSolver extends domain.HitoriGameMoves {
|
||||||
|
|
||||||
|
public GameSolver(int[][] initialBoard) {
|
||||||
|
super(initialBoard);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSolved() {
|
||||||
|
|
||||||
|
for (int i = 0; i < board.length; i++) {
|
||||||
|
for (int j = 0; j < board[0].length; j++) {
|
||||||
|
if (!blackCells[i][j] && !whiteCells[i][j]) {
|
||||||
|
return false; // Found an unmarked cell
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
for (int i = 0; i < board.length; i++) {
|
||||||
|
for (int j = 0; j < board[0].length; j++) {
|
||||||
|
if (blackCells[i][j] && !isValidBlackMark(i, j)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
for (int i = 0; i < board.length; i++) {
|
||||||
|
Set<Integer> seenInRow = new HashSet<>();
|
||||||
|
Set<Integer> seenInCol = new HashSet<>();
|
||||||
|
|
||||||
|
for (int j = 0; j < board[0].length; j++) {
|
||||||
|
|
||||||
|
if (!blackCells[i][j]) {
|
||||||
|
if (seenInRow.contains(board[i][j])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
seenInRow.add(board[i][j]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (!blackCells[j][i]) {
|
||||||
|
if (seenInCol.contains(board[j][i])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
seenInCol.add(board[j][i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check connectivity of white cells
|
||||||
|
return isOrthogonallyConnected();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isValidBlackMark(int row, int col) {
|
||||||
|
if (row > 0 && blackCells[row-1][col] ||
|
||||||
|
row < board.length-1 && blackCells[row+1][col] ||
|
||||||
|
col > 0 && blackCells[row][col-1] ||
|
||||||
|
col < board[0].length-1 && blackCells[row][col+1]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isOrthogonallyConnected() {
|
||||||
|
if (board.length == 0) return true;
|
||||||
|
|
||||||
|
boolean[][] visited = new boolean[board.length][board[0].length];
|
||||||
|
int[] start = findFirstWhiteCell();
|
||||||
|
if (start == null) return true;
|
||||||
|
|
||||||
|
dfs(start[0], start[1], visited);
|
||||||
|
|
||||||
|
for (int i = 0; i < board.length; i++) {
|
||||||
|
for (int j = 0; j < board[0].length; j++) {
|
||||||
|
if (!blackCells[i][j] && !visited[i][j]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int[] findFirstWhiteCell() {
|
||||||
|
for (int i = 0; i < board.length; i++) {
|
||||||
|
for (int j = 0; j < board[0].length; j++) {
|
||||||
|
if (!blackCells[i][j]) {
|
||||||
|
return new int[]{i, j};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void dfs(int row, int col, boolean[][] visited) {
|
||||||
|
if (row < 0 || row >= board.length || col < 0 || col >= board[0].length ||
|
||||||
|
visited[row][col] || blackCells[row][col]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
visited[row][col] = true;
|
||||||
|
|
||||||
|
dfs(row - 1, col, visited);
|
||||||
|
dfs(row + 1, col, visited);
|
||||||
|
dfs(row, col - 1, visited);
|
||||||
|
dfs(row, col + 1, visited);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<int[]> findIncorrectBlackMarks() {
|
||||||
|
List<int[]> incorrectMarks = new ArrayList<>();
|
||||||
|
for (int i = 0; i < board.length; i++) {
|
||||||
|
for (int j = 0; j < board[0].length; j++) {
|
||||||
|
if (blackCells[i][j] && !isValidBlackMark(i, j)) {
|
||||||
|
incorrectMarks.add(new int[]{i, j});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return incorrectMarks;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,124 @@
|
||||||
|
package domain;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class HitoriBoardLoader {
|
||||||
|
private Map<String, int[][]> availableBoards;
|
||||||
|
private Map<String, List<int[]>> solutions;
|
||||||
|
|
||||||
|
public HitoriBoardLoader() {
|
||||||
|
availableBoards = new HashMap<>();
|
||||||
|
solutions = new HashMap<>();
|
||||||
|
loadAllBoards();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadAllBoards() {
|
||||||
|
try {
|
||||||
|
// Define all board file names
|
||||||
|
String[] boardFiles = {
|
||||||
|
"Hitori4x4_leicht.csv",
|
||||||
|
"Hitori5x5leicht.csv",
|
||||||
|
"Hitori8x8leicht.csv",
|
||||||
|
"Hitori8x8medium.csv",
|
||||||
|
"Hitori10x10medium.csv",
|
||||||
|
"Hitori15x15_medium.csv"
|
||||||
|
};
|
||||||
|
|
||||||
|
// Try to load each board
|
||||||
|
for (String fileName : boardFiles) {
|
||||||
|
try {
|
||||||
|
InputStream is = getClass().getResourceAsStream("/META-INF/" + fileName);
|
||||||
|
if (is == null) {
|
||||||
|
is = getClass().getResourceAsStream("/" + fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is != null) {
|
||||||
|
loadBoard(fileName, is);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.out.println("Failed to load board: " + fileName);
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (availableBoards.isEmpty()) {
|
||||||
|
System.out.println("No board files found. Please ensure .csv files are in the resources folder.");
|
||||||
|
} else {
|
||||||
|
System.out.println("Successfully loaded " + availableBoards.size() + " boards.");
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadBoard(String fileName, InputStream inputStream) throws IOException {
|
||||||
|
try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {
|
||||||
|
List<String> lines = new ArrayList<>();
|
||||||
|
String line;
|
||||||
|
while ((line = reader.readLine()) != null) {
|
||||||
|
lines.add(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find where the solution starts
|
||||||
|
int solutionIndex = -1;
|
||||||
|
for (int i = 0; i < lines.size(); i++) {
|
||||||
|
if (lines.get(i).contains("//")) {
|
||||||
|
solutionIndex = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse the board
|
||||||
|
List<String[]> boardRows = new ArrayList<>();
|
||||||
|
for (int i = 0; i < (solutionIndex == -1 ? lines.size() : solutionIndex); i++) {
|
||||||
|
line = lines.get(i).trim();
|
||||||
|
if (!line.isEmpty()) {
|
||||||
|
boardRows.add(line.split(","));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!boardRows.isEmpty()) {
|
||||||
|
int rows = boardRows.size();
|
||||||
|
int cols = boardRows.get(0).length;
|
||||||
|
int[][] board = new int[rows][cols];
|
||||||
|
|
||||||
|
for (int i = 0; i < rows; i++) {
|
||||||
|
for (int j = 0; j < cols; j++) {
|
||||||
|
board[i][j] = Integer.parseInt(boardRows.get(i)[j].trim());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
availableBoards.put(fileName, board);
|
||||||
|
|
||||||
|
// Parse the solution if available
|
||||||
|
List<int[]> solutionCoordinates = new ArrayList<>();
|
||||||
|
if (solutionIndex != -1) {
|
||||||
|
for (int i = solutionIndex + 1; i < lines.size(); i++) {
|
||||||
|
line = lines.get(i).trim();
|
||||||
|
if (!line.isEmpty() && !line.startsWith("//")) {
|
||||||
|
String[] coords = line.split(",");
|
||||||
|
solutionCoordinates.add(new int[]{
|
||||||
|
Integer.parseInt(coords[0].trim()) - 1,
|
||||||
|
Integer.parseInt(coords[1].trim()) - 1
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
solutions.put(fileName, solutionCoordinates);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<String> getAvailableBoardNames() {
|
||||||
|
return availableBoards.keySet();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int[][] getBoard(String boardName) {
|
||||||
|
return availableBoards.get(boardName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<int[]> getSolution(String boardName) {
|
||||||
|
return solutions.get(boardName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,85 @@
|
||||||
|
package domain;
|
||||||
|
|
||||||
|
import domain.GameSolver;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
|
||||||
|
public class HitoriGameMain extends GameSolver {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
private final domain.HitoriGameTimer timer;
|
||||||
|
private final domain.HitoriGameScores scores;
|
||||||
|
|
||||||
|
public HitoriGameMain(int[][] initialBoard) {
|
||||||
|
super(initialBoard);
|
||||||
|
this.timer = new domain.HitoriGameTimer();
|
||||||
|
this.scores = new HitoriGameScores();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Timer delegation methods
|
||||||
|
public void startTimer() {
|
||||||
|
timer.startTimer();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void pauseTimer() {
|
||||||
|
timer.pauseTimer();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stopTimer() {
|
||||||
|
timer.stopTimer();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void resetTimer() {
|
||||||
|
timer.resetTimer();
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getElapsedTimeInSeconds() {
|
||||||
|
return timer.getElapsedTimeInSeconds();
|
||||||
|
}
|
||||||
|
|
||||||
|
// High score delegation methods
|
||||||
|
public void addHighScore(String playerName, long timeInSeconds) {
|
||||||
|
scores.addHighScore(playerName, timeInSeconds, getMistakeCount());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void deleteHighScores() {
|
||||||
|
scores.deleteHighScores();
|
||||||
|
}
|
||||||
|
|
||||||
|
public java.util.List<String> getHighScoresWithAverage() {
|
||||||
|
return scores.getHighScoresWithAverage();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void loadHighScoresFromFile() {
|
||||||
|
scores.loadHighScoresFromFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void saveHighScoresToFile() {
|
||||||
|
scores.saveHighScoresToFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Game state persistence
|
||||||
|
public void saveGameState() {
|
||||||
|
try (ObjectOutputStream oos = new ObjectOutputStream(
|
||||||
|
new FileOutputStream("gamestate.dat"))) {
|
||||||
|
oos.writeObject(this);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HitoriGameMain loadGameState() {
|
||||||
|
try (ObjectInputStream ois = new ObjectInputStream(
|
||||||
|
new FileInputStream("gamestate.dat"))) {
|
||||||
|
return (HitoriGameMain) ois.readObject();
|
||||||
|
} catch (IOException | ClassNotFoundException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void reset() {
|
||||||
|
super.reset();
|
||||||
|
resetTimer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,98 @@
|
||||||
|
package domain;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class HitoriGameMoves extends GameBase {
|
||||||
|
private List<GameState> history;
|
||||||
|
private int historyPointer;
|
||||||
|
|
||||||
|
private static class GameState implements Serializable {
|
||||||
|
boolean[][] blackCells;
|
||||||
|
boolean[][] whiteCells;
|
||||||
|
|
||||||
|
GameState(boolean[][] blackCells, boolean[][] whiteCells) {
|
||||||
|
this.blackCells = new boolean[blackCells.length][blackCells[0].length];
|
||||||
|
this.whiteCells = new boolean[whiteCells.length][whiteCells[0].length];
|
||||||
|
for (int i = 0; i < blackCells.length; i++) {
|
||||||
|
this.blackCells[i] = Arrays.copyOf(blackCells[i], blackCells[i].length);
|
||||||
|
this.whiteCells[i] = Arrays.copyOf(whiteCells[i], whiteCells[i].length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public HitoriGameMoves(int[][] initialBoard) {
|
||||||
|
super(initialBoard);
|
||||||
|
this.history = new ArrayList<>();
|
||||||
|
this.historyPointer = -1;
|
||||||
|
saveState();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void markCellAsBlack(int row, int col) {
|
||||||
|
if (!isValidBlackMark(row, col)) {
|
||||||
|
mistakeCount++;
|
||||||
|
}
|
||||||
|
blackCells[row][col] = true;
|
||||||
|
whiteCells[row][col] = false;
|
||||||
|
saveState();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void markCellAsWhite(int row, int col) {
|
||||||
|
whiteCells[row][col] = true;
|
||||||
|
blackCells[row][col] = false;
|
||||||
|
saveState();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean isValidBlackMark(int row, int col) {
|
||||||
|
if (row > 0 && blackCells[row-1][col] ||
|
||||||
|
row < board.length-1 && blackCells[row+1][col] ||
|
||||||
|
col > 0 && blackCells[row][col-1] ||
|
||||||
|
col < board[0].length-1 && blackCells[row][col+1]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void saveState() {
|
||||||
|
while (history.size() > historyPointer + 1) {
|
||||||
|
history.remove(history.size() - 1);
|
||||||
|
}
|
||||||
|
history.add(new GameState(blackCells, whiteCells));
|
||||||
|
historyPointer++;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean undo() {
|
||||||
|
if (historyPointer > 0) {
|
||||||
|
historyPointer--;
|
||||||
|
GameState state = history.get(historyPointer);
|
||||||
|
restoreState(state);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean redo() {
|
||||||
|
if (historyPointer < history.size() - 1) {
|
||||||
|
historyPointer++;
|
||||||
|
GameState state = history.get(historyPointer);
|
||||||
|
restoreState(state);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void restoreState(GameState state) {
|
||||||
|
for (int i = 0; i < board.length; i++) {
|
||||||
|
blackCells[i] = Arrays.copyOf(state.blackCells[i], state.blackCells[i].length);
|
||||||
|
whiteCells[i] = Arrays.copyOf(state.whiteCells[i], state.whiteCells[i].length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void reset() {
|
||||||
|
super.reset();
|
||||||
|
history.clear();
|
||||||
|
historyPointer = -1;
|
||||||
|
saveState();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,82 @@
|
||||||
|
package domain;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class HitoriGameScores implements Serializable {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
private Map<String, List<HighScoreEntry>> highScores;
|
||||||
|
|
||||||
|
private static class HighScoreEntry implements Serializable {
|
||||||
|
String playerName;
|
||||||
|
long time;
|
||||||
|
int mistakes;
|
||||||
|
|
||||||
|
HighScoreEntry(String playerName, long time, int mistakes) {
|
||||||
|
this.playerName = playerName;
|
||||||
|
this.time = time;
|
||||||
|
this.mistakes = mistakes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public HitoriGameScores() {
|
||||||
|
this.highScores = new HashMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addHighScore(String playerName, long timeInSeconds, int mistakes) {
|
||||||
|
highScores.putIfAbsent(playerName, new ArrayList<>());
|
||||||
|
highScores.get(playerName).add(new HighScoreEntry(playerName, timeInSeconds, mistakes));
|
||||||
|
saveHighScoresToFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void deleteHighScores() {
|
||||||
|
highScores.clear();
|
||||||
|
saveHighScoresToFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getHighScoresWithAverage() {
|
||||||
|
List<String> result = new ArrayList<>();
|
||||||
|
List<HighScoreEntry> allEntries = new ArrayList<>();
|
||||||
|
|
||||||
|
for (List<HighScoreEntry> entries : highScores.values()) {
|
||||||
|
allEntries.addAll(entries);
|
||||||
|
}
|
||||||
|
|
||||||
|
allEntries.sort((a, b) -> Long.compare(a.time, b.time));
|
||||||
|
|
||||||
|
double avgTime = allEntries.stream()
|
||||||
|
.mapToLong(e -> e.time)
|
||||||
|
.average()
|
||||||
|
.orElse(0);
|
||||||
|
|
||||||
|
for (int i = 0; i < Math.min(10, allEntries.size()); i++) {
|
||||||
|
HighScoreEntry entry = allEntries.get(i);
|
||||||
|
result.add(String.format("%s - Time: %ds - Mistakes: %d",
|
||||||
|
entry.playerName, entry.time, entry.mistakes));
|
||||||
|
}
|
||||||
|
|
||||||
|
result.add(String.format("Average Time: %.1fs", avgTime));
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void saveHighScoresToFile() {
|
||||||
|
try (ObjectOutputStream oos = new ObjectOutputStream(
|
||||||
|
new FileOutputStream("highscores.dat"))) {
|
||||||
|
oos.writeObject(highScores);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public void loadHighScoresFromFile() {
|
||||||
|
try (ObjectInputStream ois = new ObjectInputStream(
|
||||||
|
new FileInputStream("highscores.dat"))) {
|
||||||
|
highScores = (Map<String, List<HighScoreEntry>>) ois.readObject();
|
||||||
|
} catch (IOException | ClassNotFoundException e) {
|
||||||
|
highScores = new HashMap<>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,56 @@
|
||||||
|
package domain;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
public class HitoriGameTimer implements Serializable {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
private transient long startTime;
|
||||||
|
private long elapsedTime;
|
||||||
|
private boolean isPaused;
|
||||||
|
|
||||||
|
public HitoriGameTimer() {
|
||||||
|
this.startTime = 0;
|
||||||
|
this.elapsedTime = 0;
|
||||||
|
this.isPaused = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void startTimer() {
|
||||||
|
if (isPaused || startTime == 0) {
|
||||||
|
startTime = System.currentTimeMillis();
|
||||||
|
isPaused = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void pauseTimer() {
|
||||||
|
if (!isPaused && startTime > 0) {
|
||||||
|
elapsedTime += System.currentTimeMillis() - startTime;
|
||||||
|
startTime = 0;
|
||||||
|
isPaused = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stopTimer() {
|
||||||
|
if (!isPaused && startTime > 0) {
|
||||||
|
elapsedTime += System.currentTimeMillis() - startTime;
|
||||||
|
startTime = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void resetTimer() {
|
||||||
|
startTime = 0;
|
||||||
|
elapsedTime = 0;
|
||||||
|
isPaused = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getElapsedTimeInSeconds() {
|
||||||
|
if (isPaused || startTime == 0) {
|
||||||
|
return elapsedTime / 1000;
|
||||||
|
}
|
||||||
|
return (elapsedTime + System.currentTimeMillis() - startTime) / 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isPaused() {
|
||||||
|
return isPaused;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
5,8,2,6,3,7,7,5,1,8
|
||||||
|
8,4,2,2,1,9,9,3,7,5
|
||||||
|
3,2,7,8,2,5,5,4,3,10
|
||||||
|
10,2,3,1,7,8,6,9,9,9
|
||||||
|
3,3,3,7,6,2,4,10,4,1
|
||||||
|
4,5,9,10,6,10,1,7,8,8
|
||||||
|
2,7,5,9,1,10,3,1,3,6
|
||||||
|
9,5,4,3,8,10,2,9,10,4
|
||||||
|
9,6,10,8,5,3,10,2,5,8
|
||||||
|
9,10,2,2,4,7,9,8,5,7
|
||||||
|
|
||||||
|
// Lösung (schwarze Felder)
|
||||||
|
1,1
|
||||||
|
1,3
|
||||||
|
1,6
|
||||||
|
1,10
|
||||||
|
2,4
|
||||||
|
2,7
|
||||||
|
3,2
|
||||||
|
3,6
|
||||||
|
3,9
|
||||||
|
4,8
|
||||||
|
4,10
|
||||||
|
5,1
|
||||||
|
5,3
|
||||||
|
5,5
|
||||||
|
5,7
|
||||||
|
6,2
|
||||||
|
6,6
|
||||||
|
6,10
|
||||||
|
7,5
|
||||||
|
7,9
|
||||||
|
8,1
|
||||||
|
8,3
|
||||||
|
8,6
|
||||||
|
9,4
|
||||||
|
9,7
|
||||||
|
9,9
|
||||||
|
10,1
|
||||||
|
10,3
|
||||||
|
10,10
|
||||||
|
Can't render this file because it has a wrong number of fields in line 12.
|
|
|
@ -0,0 +1,83 @@
|
||||||
|
7,1,2,9,12,15,8,11,11,9,11,14,13,6,3
|
||||||
|
2,3,8,1,2,11,10,9,5,8,14,3,12,13,15
|
||||||
|
4,14,13,9,4,15,9,10,12,6,5,3,11,5,12
|
||||||
|
15,9,5,6,10,15,1,15,8,3,5,4,6,2,8
|
||||||
|
5,11,7,9,15,1,4,3,8,1,9,2,10,13,2
|
||||||
|
15,15,10,3,1,14,8,12,11,1,9,8,2,7,2
|
||||||
|
10,7,7,12,9,3,15,2,5,2,10,5,1,7,4
|
||||||
|
3,8,9,14,1,6,12,4,15,2,13,11,5,10,11
|
||||||
|
8,6,7,15,11,4,5,11,2,10,3,13,8,12,9
|
||||||
|
2,2,3,3,4,13,5,6,5,11,5,15,8,9,12
|
||||||
|
2,15,15,11,13,7,6,5,3,13,8,10,5,1,11
|
||||||
|
12,5,11,13,13,2,2,8,8,4,10,9,3,2,5
|
||||||
|
1,13,8,2,1,7,11,4,9,15,4,12,9,3,10
|
||||||
|
13,10,12,5,15,3,2,7,13,14,12,12,9,11,6
|
||||||
|
7,12,4,8,14,10,13,13,7,4,2,6,15,15,11
|
||||||
|
|
||||||
|
//Lösung
|
||||||
|
1,4
|
||||||
|
1,6
|
||||||
|
1,8
|
||||||
|
1,11
|
||||||
|
2,1
|
||||||
|
2,3
|
||||||
|
2,9
|
||||||
|
2,12
|
||||||
|
2,14
|
||||||
|
3,5
|
||||||
|
3,7
|
||||||
|
3,11
|
||||||
|
3,15
|
||||||
|
4,1
|
||||||
|
4,3
|
||||||
|
4,6
|
||||||
|
4,9
|
||||||
|
4,13
|
||||||
|
5,4
|
||||||
|
5,10
|
||||||
|
5,15
|
||||||
|
6,2
|
||||||
|
6,5
|
||||||
|
6,7
|
||||||
|
6,9
|
||||||
|
6,11
|
||||||
|
6,13
|
||||||
|
7,1
|
||||||
|
7,3
|
||||||
|
7,6
|
||||||
|
7,8
|
||||||
|
7,12
|
||||||
|
7,14
|
||||||
|
8,5
|
||||||
|
8,9
|
||||||
|
8,15
|
||||||
|
9,3
|
||||||
|
9,8
|
||||||
|
9,13
|
||||||
|
10,1
|
||||||
|
10,4
|
||||||
|
10,7
|
||||||
|
10,9
|
||||||
|
10,11
|
||||||
|
11,3
|
||||||
|
11,10
|
||||||
|
11,13
|
||||||
|
11,15
|
||||||
|
12,2
|
||||||
|
12,5
|
||||||
|
12,7
|
||||||
|
12,9
|
||||||
|
12,11
|
||||||
|
12,14
|
||||||
|
13,1
|
||||||
|
13,6
|
||||||
|
13,8
|
||||||
|
13,13
|
||||||
|
14,3
|
||||||
|
14,5
|
||||||
|
14,9
|
||||||
|
14,12
|
||||||
|
15,1
|
||||||
|
15,7
|
||||||
|
15,10
|
||||||
|
15,14
|
||||||
|
Can't render this file because it has a wrong number of fields in line 17.
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
3,3,1,4
|
||||||
|
4,3,2,2
|
||||||
|
1,3,4,2
|
||||||
|
3,4,3,2
|
||||||
|
|
||||||
|
//Lösung (schwarze Felder)
|
||||||
|
1,2
|
||||||
|
2,4
|
||||||
|
3,2
|
||||||
|
4,1
|
||||||
|
4,4
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
3,4,5,5,2
|
||||||
|
3,2,3,5,4
|
||||||
|
2,1,4,5,5
|
||||||
|
2,3,1,4,1
|
||||||
|
2,5,2,3,2
|
||||||
|
|
||||||
|
//Lösung (schwarze Felder)
|
||||||
|
1,1
|
||||||
|
1,4
|
||||||
|
2,3
|
||||||
|
3,1
|
||||||
|
3,4
|
||||||
|
4,3
|
||||||
|
5,1
|
||||||
|
5,5
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
2,7,2,1,5,8,3,5
|
||||||
|
6,6,1,6,2,4,4,7
|
||||||
|
7,5,8,2,6,6,6,1
|
||||||
|
3,6,8,8,4,2,1,8
|
||||||
|
6,4,7,7,8,2,6,3
|
||||||
|
1,6,4,5,1,3,5,8
|
||||||
|
8,1,3,3,6,4,2,6
|
||||||
|
5,3,6,4,3,4,8,2
|
||||||
|
|
||||||
|
// Lösung (schwarze Felder)
|
||||||
|
1,1
|
||||||
|
1,8
|
||||||
|
2,2
|
||||||
|
2,4
|
||||||
|
2,6
|
||||||
|
3,5
|
||||||
|
3,7
|
||||||
|
4,3
|
||||||
|
4,8
|
||||||
|
5,1
|
||||||
|
5,4
|
||||||
|
5,6
|
||||||
|
6,2
|
||||||
|
6,5
|
||||||
|
6,7
|
||||||
|
7,4
|
||||||
|
7,8
|
||||||
|
8,2
|
||||||
|
8,6
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
4,4,3,5,6,5,7,7
|
||||||
|
8,5,7,6,8,4,7,1
|
||||||
|
7,2,1,2,4,6,2,3
|
||||||
|
8,6,5,2,7,7,3,6
|
||||||
|
3,1,2,7,3,8,6,4
|
||||||
|
1,2,4,1,5,7,3,2
|
||||||
|
5,8,2,4,3,4,1,5
|
||||||
|
2,4,5,1,8,3,8,1
|
||||||
|
|
||||||
|
//Lösung (schwarze Zahlen)
|
||||||
|
1,2
|
||||||
|
1,4
|
||||||
|
1,8
|
||||||
|
2,5
|
||||||
|
2,7
|
||||||
|
3,2
|
||||||
|
3,4
|
||||||
|
4,1
|
||||||
|
4,6
|
||||||
|
4,8
|
||||||
|
5,3
|
||||||
|
5,5
|
||||||
|
6,2
|
||||||
|
6,4
|
||||||
|
6,7
|
||||||
|
7,1
|
||||||
|
7,6
|
||||||
|
8,3
|
||||||
|
8,5
|
||||||
|
8,8
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
Manifest-Version: 1.0
|
||||||
|
Main-Class: de.hs_mannheim.informatik.backend.HitoriGameGUI
|
||||||
|
|
||||||
Loading…
Reference in New Issue