Compare commits
13 Commits
ae5fb68bd4
...
88d67200c8
Author | SHA1 | Date |
---|---|---|
|
88d67200c8 | |
|
34240b22dc | |
|
07e6cf3600 | |
|
ee20cea0eb | |
|
d67e9495ce | |
|
77a4247677 | |
|
71124dab2a | |
|
cabd4db873 | |
|
92bc8247e4 | |
|
1a32962ba8 | |
|
57147ae818 | |
|
981547383f | |
|
e21e289f36 |
33
pom.xml
33
pom.xml
|
@ -21,6 +21,31 @@
|
|||
<version>5.8.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter</artifactId>
|
||||
<version>5.9.3</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.powermock</groupId>
|
||||
<artifactId>powermock-module-junit4</artifactId>
|
||||
<version>2.0.9</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.powermock</groupId>
|
||||
<artifactId>powermock-api-mockito2</artifactId>
|
||||
<version>2.0.9</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.powermock</groupId>
|
||||
<artifactId>powermock-module-junit4-rule</artifactId>
|
||||
<version>2.0.9</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<!-- https://mvnrepository.com/artifact/org.apache.maven.plugins/maven-checkstyle-plugin -->
|
||||
<dependency>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
|
@ -28,6 +53,14 @@
|
|||
<version>3.6.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<version>5.15.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
|
||||
<!-- https://mvnrepository.com/artifact/org.apache.maven.plugins/maven-javadoc-plugin -->
|
||||
<dependency>
|
||||
|
|
|
@ -4,36 +4,54 @@ import java.io.BufferedReader;
|
|||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class CSVReader {
|
||||
|
||||
/**
|
||||
* Liest die CSV-Datei ein und gibt die enthaltenen Werte als zweidimensionales int-Array zurück.
|
||||
*
|
||||
* @param csvFile Pfad zur CSV-Datei
|
||||
* @return zweidimensionales Array, das die Zahlen aus der CSV enthält
|
||||
* @throws IOException wenn ein Fehler beim Lesen auftritt
|
||||
*/
|
||||
public int[][] readCsvToIntArray(String csvFile) throws IOException {
|
||||
ArrayList<int[]> rows = new ArrayList<>();
|
||||
public PuzzleData readPuzzleWithSolution(String csvFile) throws IOException {
|
||||
List<int[]> puzzleRows = new ArrayList<>();
|
||||
List<int[]> solutionCoordinates = new ArrayList<>();
|
||||
|
||||
try (BufferedReader br = new BufferedReader(new FileReader(csvFile))) {
|
||||
String line;
|
||||
boolean inSolutionPart = false;
|
||||
|
||||
while ((line = br.readLine()) != null) {
|
||||
String[] tokens = line.split(",");
|
||||
int[] row = new int[tokens.length];
|
||||
for (int i = 0; i < tokens.length; i++) {
|
||||
row[i] = Integer.parseInt(tokens[i].trim());
|
||||
line = line.trim();
|
||||
if (line.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
if (line.startsWith("//Lösung") || line.startsWith("//")) {
|
||||
inSolutionPart = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!inSolutionPart) {
|
||||
// Puzzle-Teil
|
||||
String[] tokens = line.split(",");
|
||||
int[] rowValues = new int[tokens.length];
|
||||
for (int i = 0; i < tokens.length; i++) {
|
||||
rowValues[i] = Integer.parseInt(tokens[i].trim());
|
||||
}
|
||||
puzzleRows.add(rowValues);
|
||||
} else {
|
||||
// Lösungsteil
|
||||
String[] coords = line.split(",");
|
||||
if (coords.length == 2) {
|
||||
int row = Integer.parseInt(coords[0].trim());
|
||||
int col = Integer.parseInt(coords[1].trim());
|
||||
solutionCoordinates.add(new int[]{row, col});
|
||||
}
|
||||
}
|
||||
rows.add(row);
|
||||
}
|
||||
}
|
||||
|
||||
// ArrayList in 2D-Array umwandeln
|
||||
int[][] result = new int[rows.size()][];
|
||||
for (int i = 0; i < rows.size(); i++) {
|
||||
result[i] = rows.get(i);
|
||||
// puzzleRows -> 2D-Array
|
||||
int[][] puzzleArray = new int[puzzleRows.size()][];
|
||||
for (int i = 0; i < puzzleRows.size(); i++) {
|
||||
puzzleArray[i] = puzzleRows.get(i);
|
||||
}
|
||||
return result;
|
||||
|
||||
return new PuzzleData(puzzleArray, solutionCoordinates);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
package de.deversmann.domain;
|
||||
|
||||
public class HighscoreEntry {
|
||||
|
||||
private final String playerName;
|
||||
private final long timeSeconds;
|
||||
private final int errorCount;
|
||||
|
||||
public HighscoreEntry(String playerName, long timeSeconds, int errorCount) {
|
||||
this.playerName = playerName;
|
||||
this.timeSeconds = timeSeconds;
|
||||
this.errorCount = errorCount;
|
||||
}
|
||||
|
||||
public String getPlayerName() {
|
||||
return playerName;
|
||||
}
|
||||
|
||||
public long getTimeSeconds() {
|
||||
return timeSeconds;
|
||||
}
|
||||
|
||||
public int getErrorCount() {
|
||||
return errorCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return playerName + " - " + timeSeconds + "s (Fehler: " + errorCount + ")";
|
||||
}
|
||||
}
|
|
@ -4,17 +4,99 @@ import java.io.*;
|
|||
import java.util.*;
|
||||
|
||||
public class HighscoreManager {
|
||||
private List<Integer> highscores
|
||||
|
||||
private Map<String, List<HighscoreEntry>> highscoreMap;
|
||||
|
||||
public HighscoreManager() {
|
||||
this.highscores = new ArrayList<>();
|
||||
this.highscoreMap = new HashMap<>();
|
||||
}
|
||||
|
||||
public void addHighscore(int score) {
|
||||
highscores.add(score);
|
||||
public void addHighscore(String puzzleName, String playerName, long timeSeconds, int errorCount) {
|
||||
highscoreMap.putIfAbsent(puzzleName, new ArrayList<>());
|
||||
highscoreMap.get(puzzleName).add(new HighscoreEntry(playerName, timeSeconds, errorCount));
|
||||
}
|
||||
|
||||
public List<Integer> getHighscores() {
|
||||
return new ArrayList<>(highscores);
|
||||
public List<HighscoreEntry> getHighscores(String puzzleName) {
|
||||
return highscoreMap.getOrDefault(puzzleName, Collections.emptyList());
|
||||
}
|
||||
|
||||
public double getAverageTime(String puzzleName) {
|
||||
List<HighscoreEntry> entries = highscoreMap.get(puzzleName);
|
||||
if (entries == null || entries.isEmpty()) {
|
||||
return -1;
|
||||
}
|
||||
long sum = 0;
|
||||
for (HighscoreEntry e : entries) {
|
||||
sum += e.getTimeSeconds();
|
||||
}
|
||||
return (double) sum / entries.size();
|
||||
}
|
||||
|
||||
public void saveSinglePuzzle(String puzzleName, String filename) throws IOException {
|
||||
List<HighscoreEntry> entries = getHighscores(puzzleName);
|
||||
|
||||
entries.sort(Comparator
|
||||
.comparingInt(HighscoreEntry::getErrorCount)
|
||||
.thenComparingLong(HighscoreEntry::getTimeSeconds));
|
||||
|
||||
double avgTime = getAverageTime(puzzleName);
|
||||
|
||||
try (BufferedWriter writer = new BufferedWriter(new FileWriter(filename))) {
|
||||
if (avgTime < 0) {
|
||||
writer.write("Durchschnittszeit: Keine Einträge");
|
||||
} else {
|
||||
writer.write(String.format("Durchschnittszeit: %.2f s", avgTime));
|
||||
}
|
||||
writer.newLine();
|
||||
writer.newLine();
|
||||
|
||||
writer.write(String.format("%-6s | %-5s | %-6s | %-15s",
|
||||
"Platz", "Zeit", "Fehler", "Name"));
|
||||
writer.newLine();
|
||||
writer.write("------------------------------------------------------------");
|
||||
writer.newLine();
|
||||
|
||||
int place = 1;
|
||||
for (HighscoreEntry e : entries) {
|
||||
writer.write(String.format("%-6s | %-5d | %-6d | %-15s",
|
||||
place + ".",
|
||||
e.getTimeSeconds(),
|
||||
e.getErrorCount(),
|
||||
e.getPlayerName()));
|
||||
writer.newLine();
|
||||
place++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void loadSinglePuzzle(String puzzleName, String filename) throws IOException {
|
||||
File file = new File(filename);
|
||||
if (!file.exists()) {
|
||||
System.out.println("Highscore-Datei " + filename + " existiert nicht; wird neu erstellt.");
|
||||
return;
|
||||
}
|
||||
|
||||
try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
|
||||
// Durchschnittszeit und Header überspringen
|
||||
reader.readLine();
|
||||
reader.readLine();
|
||||
reader.readLine();
|
||||
reader.readLine();
|
||||
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
String[] parts = line.split("\\|");
|
||||
if (parts.length < 4) continue;
|
||||
|
||||
String timeStr = parts[1].trim();
|
||||
String errorStr = parts[2].trim();
|
||||
String nameStr = parts[3].trim();
|
||||
|
||||
long timeSeconds = Long.parseLong(timeStr);
|
||||
int errorCount = Integer.parseInt(errorStr);
|
||||
|
||||
addHighscore(puzzleName, nameStr, timeSeconds, errorCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package de.deversmann.domain;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class PuzzleData {
|
||||
|
||||
private final int[][] puzzle;
|
||||
private final List<int[]> solutionCoordinates;
|
||||
|
||||
public PuzzleData(int[][] puzzle, List<int[]> solutionCoordinates) {
|
||||
this.puzzle = puzzle;
|
||||
this.solutionCoordinates = solutionCoordinates;
|
||||
}
|
||||
|
||||
public int[][] getPuzzle() {
|
||||
return puzzle;
|
||||
}
|
||||
|
||||
public List<int[]> getSolutionCoordinates() {
|
||||
return solutionCoordinates;
|
||||
}
|
||||
}
|
|
@ -1,4 +1,97 @@
|
|||
package de.deversmann.facade;
|
||||
|
||||
import de.deversmann.domain.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
public class Facade {
|
||||
|
||||
private final CSVReader csvReader;
|
||||
private final HighscoreManager highscoreManager;
|
||||
private final Zeiterfassung zeiterfassung;
|
||||
|
||||
private PuzzleData currentPuzzleData;
|
||||
private String currentPuzzleName;
|
||||
private int currentErrorCount = 0;
|
||||
|
||||
public Facade() {
|
||||
this.csvReader = new CSVReader();
|
||||
this.highscoreManager = new HighscoreManager();
|
||||
this.zeiterfassung = new Zeiterfassung();
|
||||
}
|
||||
|
||||
public void ladeSpielfeld(String csvPfad) throws IOException {
|
||||
this.currentPuzzleData = csvReader.readPuzzleWithSolution(csvPfad);
|
||||
this.currentPuzzleName = csvPfad;
|
||||
this.currentErrorCount = 0;
|
||||
|
||||
zeiterfassung.stop();
|
||||
zeiterfassung.start();
|
||||
System.out.println("Neues Spielfeld geladen, Timer + Fehler=0");
|
||||
}
|
||||
|
||||
public long stopZeiterfassung() {
|
||||
zeiterfassung.stop();
|
||||
return zeiterfassung.getElapsedTimeInSeconds();
|
||||
}
|
||||
|
||||
public long getElapsedTimeSoFar() {
|
||||
return zeiterfassung.getElapsedTimeInSeconds();
|
||||
}
|
||||
|
||||
public int[][] getAktuellesPuzzle() {
|
||||
return (currentPuzzleData != null) ? currentPuzzleData.getPuzzle() : null;
|
||||
}
|
||||
|
||||
public List<int[]> getLoesungsKoordinaten() {
|
||||
return (currentPuzzleData != null) ? currentPuzzleData.getSolutionCoordinates() : null;
|
||||
}
|
||||
|
||||
// Fehler-Tracking
|
||||
public void incrementErrorCount() {
|
||||
currentErrorCount++;
|
||||
}
|
||||
|
||||
public int getCurrentErrorCount() {
|
||||
return currentErrorCount;
|
||||
}
|
||||
|
||||
// Highscore
|
||||
public void addHighscoreForCurrentPuzzle(String playerName, long timeSeconds, int errorCount) {
|
||||
if (currentPuzzleName != null && !currentPuzzleName.isEmpty()) {
|
||||
highscoreManager.addHighscore(currentPuzzleName, playerName, timeSeconds, errorCount);
|
||||
}
|
||||
}
|
||||
|
||||
public List<HighscoreEntry> getHighscoresForCurrentPuzzle() {
|
||||
if (currentPuzzleName == null) {
|
||||
return List.of();
|
||||
}
|
||||
return highscoreManager.getHighscores(currentPuzzleName);
|
||||
}
|
||||
|
||||
public double getAverageTimeForCurrentPuzzle() {
|
||||
if (currentPuzzleName == null) {
|
||||
return -1;
|
||||
}
|
||||
return highscoreManager.getAverageTime(currentPuzzleName);
|
||||
}
|
||||
|
||||
public void saveCurrentPuzzleHighscoreToFile() throws IOException {
|
||||
if (currentPuzzleName == null) return;
|
||||
String base = currentPuzzleName.replaceAll(".*/", "");
|
||||
String shortName = base.replace(".csv", "") + "_highscore.txt";
|
||||
highscoreManager.saveSinglePuzzle(currentPuzzleName, shortName);
|
||||
System.out.println("Highscore zu " + base + " in " + shortName + " gespeichert.");
|
||||
}
|
||||
|
||||
|
||||
public void loadCurrentPuzzleHighscoreFromFile() throws IOException {
|
||||
if (currentPuzzleName == null) return;
|
||||
String base = currentPuzzleName.replaceAll(".*/", "");
|
||||
String shortName = base.replace(".csv", "") + "_highscore.txt";
|
||||
highscoreManager.loadSinglePuzzle(currentPuzzleName, shortName);
|
||||
System.out.println("Highscore zu " + base + " aus " + shortName + " geladen (falls existiert).");
|
||||
}
|
||||
}
|
|
@ -5,22 +5,24 @@ import de.deversmann.facade.Facade;
|
|||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.io.IOException;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
|
||||
public class GameView extends JFrame {
|
||||
|
||||
private final Facade facade;
|
||||
private SpielfeldGUI spielfeldGUI;
|
||||
SpielfeldGUI spielfeldGUI;
|
||||
|
||||
private JComboBox<String> cbSpielfelder;
|
||||
private JButton btnLoad;
|
||||
private JButton btnRandom;
|
||||
private JButton btnCheckSolution;
|
||||
private JButton btnShowSolution;
|
||||
private JButton btnReset;
|
||||
private JLabel timeLabel;
|
||||
private Timer timer;
|
||||
JComboBox<String> cbSpielfelder;
|
||||
JButton btnLoad;
|
||||
JButton btnRandom;
|
||||
JButton btnCheckSolution;
|
||||
JButton btnShowSolution;
|
||||
JButton btnReset;
|
||||
JLabel timeLabel;
|
||||
Timer timer;
|
||||
|
||||
private final String[] spielfelder = {
|
||||
"4x4.csv",
|
||||
|
@ -96,7 +98,7 @@ public class GameView extends JFrame {
|
|||
timer.start();
|
||||
}
|
||||
|
||||
private void ladeSpielfeld(String pfad) {
|
||||
void ladeSpielfeld(String pfad) {
|
||||
try {
|
||||
facade.ladeSpielfeld(pfad);
|
||||
facade.loadCurrentPuzzleHighscoreFromFile();
|
||||
|
@ -115,7 +117,7 @@ public class GameView extends JFrame {
|
|||
}
|
||||
}
|
||||
|
||||
private void checkSolution() {
|
||||
void checkSolution() {
|
||||
var blackCells = spielfeldGUI.getBlackCells();
|
||||
var solutionCoordinates = facade.getLoesungsKoordinaten();
|
||||
if (solutionCoordinates == null) {
|
||||
|
@ -199,7 +201,7 @@ public class GameView extends JFrame {
|
|||
JOptionPane.showMessageDialog(this, sb.toString(), "Ergebnis", JOptionPane.INFORMATION_MESSAGE);
|
||||
}
|
||||
|
||||
private boolean containsCell(List<int[]> blackCells, String sol) {
|
||||
boolean containsCell(List<int[]> blackCells, String sol) {
|
||||
String[] parts = sol.split(",");
|
||||
int rr = Integer.parseInt(parts[0]);
|
||||
int cc = Integer.parseInt(parts[1]);
|
||||
|
@ -211,7 +213,7 @@ public class GameView extends JFrame {
|
|||
return false;
|
||||
}
|
||||
|
||||
private void showSolution() {
|
||||
void showSolution() {
|
||||
var feld = facade.getAktuellesPuzzle();
|
||||
if (feld == null) return;
|
||||
spielfeldGUI.updateGrid(feld);
|
||||
|
@ -225,7 +227,7 @@ public class GameView extends JFrame {
|
|||
spielfeldGUI.setAllNonBlackToWhite();
|
||||
}
|
||||
|
||||
private void resetField() {
|
||||
void resetField() {
|
||||
var feld = facade.getAktuellesPuzzle();
|
||||
if (feld != null) {
|
||||
spielfeldGUI.updateGrid(feld);
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
package de.deversmann.domain;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class CSVReaderTest {
|
||||
|
||||
@Test
|
||||
void testReadPuzzleWithSolutionRealData() throws IOException {
|
||||
String csvContent = """
|
||||
4,5,6,7
|
||||
8,9,10,11
|
||||
12,13,14,15
|
||||
16,17,18,19
|
||||
//Lösung
|
||||
2,2
|
||||
3,3
|
||||
""";
|
||||
Path tempFile = Files.createTempFile("realPuzzle", ".csv");
|
||||
Files.writeString(tempFile, csvContent);
|
||||
|
||||
CSVReader reader = new CSVReader();
|
||||
PuzzleData data = reader.readPuzzleWithSolution(tempFile.toString());
|
||||
|
||||
int[][] expectedPuzzle = {
|
||||
{4, 5, 6, 7},
|
||||
{8, 9, 10, 11},
|
||||
{12, 13, 14, 15},
|
||||
{16, 17, 18, 19}
|
||||
};
|
||||
assertArrayEquals(expectedPuzzle, data.getPuzzle());
|
||||
assertEquals(2, data.getSolutionCoordinates().size());
|
||||
assertArrayEquals(new int[]{2, 2}, data.getSolutionCoordinates().get(0));
|
||||
assertArrayEquals(new int[]{3, 3}, data.getSolutionCoordinates().get(1));
|
||||
|
||||
Files.delete(tempFile);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testReadPuzzleWithInvalidData() throws IOException {
|
||||
String csvContent = """
|
||||
1,2,3
|
||||
4,5
|
||||
//Lösung
|
||||
a,b
|
||||
""";
|
||||
Path tempFile = Files.createTempFile("invalidPuzzle", ".csv");
|
||||
Files.writeString(tempFile, csvContent);
|
||||
|
||||
CSVReader reader = new CSVReader();
|
||||
|
||||
assertThrows(NumberFormatException.class, () -> reader.readPuzzleWithSolution(tempFile.toString()));
|
||||
|
||||
Files.delete(tempFile);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testReadPuzzleWithoutSolution() throws IOException {
|
||||
String csvContent = """
|
||||
1,2,3
|
||||
4,5,6
|
||||
7,8,9
|
||||
""";
|
||||
Path tempFile = Files.createTempFile("noSolutionPuzzle", ".csv");
|
||||
Files.writeString(tempFile, csvContent);
|
||||
|
||||
CSVReader reader = new CSVReader();
|
||||
PuzzleData data = reader.readPuzzleWithSolution(tempFile.toString());
|
||||
|
||||
assertNotNull(data.getPuzzle());
|
||||
assertTrue(data.getSolutionCoordinates().isEmpty());
|
||||
|
||||
Files.delete(tempFile);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
package de.deversmann.domain;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
class HighscoreEntryTest {
|
||||
|
||||
@Test
|
||||
void testHighscoreEntryProperties() {
|
||||
HighscoreEntry entry = new HighscoreEntry("Alice", 120, 3);
|
||||
|
||||
assertEquals("Alice", entry.getPlayerName());
|
||||
assertEquals(120, entry.getTimeSeconds());
|
||||
assertEquals(3, entry.getErrorCount());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testToString() {
|
||||
HighscoreEntry entry = new HighscoreEntry("Alice", 120, 3);
|
||||
|
||||
assertEquals("Alice - 120s (Fehler: 3)", entry.toString());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
package de.deversmann.domain;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class HighscoreManagerTest {
|
||||
|
||||
@Test
|
||||
void testAddAndRetrieveHighscores() {
|
||||
HighscoreManager manager = new HighscoreManager();
|
||||
manager.addHighscore("Puzzle1", "Alice", 120, 2);
|
||||
|
||||
List<HighscoreEntry> highscores = manager.getHighscores("Puzzle1");
|
||||
|
||||
assertEquals(1, highscores.size());
|
||||
assertEquals("Alice", highscores.get(0).getPlayerName());
|
||||
assertEquals(120, highscores.get(0).getTimeSeconds());
|
||||
assertEquals(2, highscores.get(0).getErrorCount());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSaveAndLoadHighscores() throws IOException {
|
||||
HighscoreManager manager = new HighscoreManager();
|
||||
manager.addHighscore("Puzzle1", "Alice", 120, 2);
|
||||
|
||||
Path tempFile = Files.createTempFile("testHighscores", ".txt");
|
||||
manager.saveSinglePuzzle("Puzzle1", tempFile.toString());
|
||||
|
||||
HighscoreManager newManager = new HighscoreManager();
|
||||
newManager.loadSinglePuzzle("Puzzle1", tempFile.toString());
|
||||
|
||||
List<HighscoreEntry> highscores = newManager.getHighscores("Puzzle1");
|
||||
|
||||
assertEquals(1, highscores.size());
|
||||
assertEquals("Alice", highscores.get(0).getPlayerName());
|
||||
assertEquals(120, highscores.get(0).getTimeSeconds());
|
||||
assertEquals(2, highscores.get(0).getErrorCount());
|
||||
|
||||
Files.delete(tempFile);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetAverageTimeNoEntries() {
|
||||
HighscoreManager manager = new HighscoreManager();
|
||||
double avgTime = manager.getAverageTime("Puzzle1");
|
||||
|
||||
assertEquals(-1, avgTime, "Average time should be -1 for no entries.");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testLoadSinglePuzzleFileNotFound() {
|
||||
HighscoreManager manager = new HighscoreManager();
|
||||
|
||||
assertDoesNotThrow(() -> manager.loadSinglePuzzle("Puzzle1", "nonexistent.txt"));
|
||||
assertTrue(manager.getHighscores("Puzzle1").isEmpty());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
package de.deversmann.domain;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class PuzzleDataTest {
|
||||
|
||||
@Test
|
||||
void testGetPuzzle() {
|
||||
int[][] puzzle = {{1, 2}, {3, 4}};
|
||||
List<int[]> solution = List.of(new int[]{1, 1}, new int[]{2, 2});
|
||||
|
||||
PuzzleData data = new PuzzleData(puzzle, solution);
|
||||
|
||||
assertArrayEquals(puzzle, data.getPuzzle());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetSolutionCoordinates() {
|
||||
int[][] puzzle = {{1, 2}, {3, 4}};
|
||||
List<int[]> solution = List.of(new int[]{1, 1}, new int[]{2, 2});
|
||||
|
||||
PuzzleData data = new PuzzleData(puzzle, solution);
|
||||
|
||||
assertEquals(solution, data.getSolutionCoordinates());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package de.deversmann.domain;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class ZeiterfassungTest {
|
||||
|
||||
@Test
|
||||
void testZeiterfassungStartStop() throws InterruptedException {
|
||||
Zeiterfassung timer = new Zeiterfassung();
|
||||
timer.start();
|
||||
|
||||
Thread.sleep(1000); // 1 Sekunde warten
|
||||
|
||||
timer.stop();
|
||||
long elapsedTime = timer.getElapsedTimeInSeconds();
|
||||
|
||||
assertTrue(elapsedTime >= 1 && elapsedTime < 2, "Elapsed time should be approximately 1 second.");
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,153 @@
|
|||
package de.deversmann.facade;
|
||||
|
||||
import de.deversmann.domain.*;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.Mockito;
|
||||
import org.powermock.api.mockito.PowerMockito;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
class FacadeTest {
|
||||
|
||||
private CSVReader csvReaderMock;
|
||||
private HighscoreManager highscoreManagerMock;
|
||||
private Zeiterfassung zeiterfassungMock;
|
||||
private Facade facade;
|
||||
|
||||
@BeforeEach
|
||||
void setup() throws Exception {
|
||||
facade = new Facade();
|
||||
|
||||
csvReaderMock = mock(CSVReader.class);
|
||||
highscoreManagerMock = mock(HighscoreManager.class);
|
||||
zeiterfassungMock = mock(Zeiterfassung.class);
|
||||
|
||||
PowerMockito.field(Facade.class, "csvReader").set(facade, csvReaderMock);
|
||||
PowerMockito.field(Facade.class, "highscoreManager").set(facade, highscoreManagerMock);
|
||||
PowerMockito.field(Facade.class, "zeiterfassung").set(facade, zeiterfassungMock);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testLadeSpielfeldMitEchtenDaten() throws IOException {
|
||||
PuzzleData puzzleData = new PuzzleData(new int[][]{{1, 2, 3, 4}}, List.of(new int[]{1, 1}));
|
||||
when(csvReaderMock.readPuzzleWithSolution(anyString())).thenReturn(puzzleData);
|
||||
|
||||
facade.ladeSpielfeld("test.csv");
|
||||
|
||||
assertNotNull(facade.getAktuellesPuzzle());
|
||||
assertEquals(1, facade.getLoesungsKoordinaten().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testStopZeiterfassung() {
|
||||
when(zeiterfassungMock.getElapsedTimeInSeconds()).thenReturn(42L);
|
||||
|
||||
long elapsedTime = facade.stopZeiterfassung();
|
||||
|
||||
verify(zeiterfassungMock, times(1)).stop();
|
||||
assertEquals(42L, elapsedTime);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetElapsedTimeSoFar() {
|
||||
when(zeiterfassungMock.getElapsedTimeInSeconds()).thenReturn(15L);
|
||||
|
||||
long elapsedTime = facade.getElapsedTimeSoFar();
|
||||
|
||||
verify(zeiterfassungMock, times(1)).getElapsedTimeInSeconds();
|
||||
assertEquals(15L, elapsedTime);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testIncrementErrorCount() {
|
||||
assertEquals(0, facade.getCurrentErrorCount());
|
||||
|
||||
facade.incrementErrorCount();
|
||||
|
||||
assertEquals(1, facade.getCurrentErrorCount());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAddHighscoreForCurrentPuzzle() throws IOException {
|
||||
facade.ladeSpielfeld("test.csv");
|
||||
|
||||
facade.addHighscoreForCurrentPuzzle("Player1", 100L, 3);
|
||||
|
||||
verify(highscoreManagerMock, times(1))
|
||||
.addHighscore(eq("test.csv"), eq("Player1"), eq(100L), eq(3));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetHighscoresForCurrentPuzzle() throws IOException {
|
||||
when(highscoreManagerMock.getHighscores("test.csv"))
|
||||
.thenReturn(List.of(new HighscoreEntry("Player1", 100L, 2)));
|
||||
|
||||
facade.ladeSpielfeld("test.csv");
|
||||
List<HighscoreEntry> highscores = facade.getHighscoresForCurrentPuzzle();
|
||||
|
||||
assertEquals(1, highscores.size());
|
||||
assertEquals("Player1", highscores.get(0).getPlayerName());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetAverageTimeForCurrentPuzzle() throws IOException {
|
||||
when(highscoreManagerMock.getAverageTime("test.csv")).thenReturn(75.0);
|
||||
|
||||
facade.ladeSpielfeld("test.csv");
|
||||
double avgTime = facade.getAverageTimeForCurrentPuzzle();
|
||||
|
||||
assertEquals(75.0, avgTime, 0.01);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSaveCurrentPuzzleHighscoreToFile() throws IOException {
|
||||
facade.ladeSpielfeld("test.csv");
|
||||
|
||||
facade.saveCurrentPuzzleHighscoreToFile();
|
||||
|
||||
verify(highscoreManagerMock, times(1))
|
||||
.saveSinglePuzzle(eq("test.csv"), anyString());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testLoadCurrentPuzzleHighscoreFromFile() throws IOException {
|
||||
facade.ladeSpielfeld("test.csv");
|
||||
|
||||
facade.loadCurrentPuzzleHighscoreFromFile();
|
||||
|
||||
verify(highscoreManagerMock, times(1))
|
||||
.loadSinglePuzzle(eq("test.csv"), anyString());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetAktuellesPuzzle() throws IOException {
|
||||
PuzzleData puzzleData = new PuzzleData(new int[][]{{1, 2, 3, 4}}, List.of());
|
||||
when(csvReaderMock.readPuzzleWithSolution(anyString())).thenReturn(puzzleData);
|
||||
|
||||
facade.ladeSpielfeld("test.csv");
|
||||
|
||||
int[][] puzzle = facade.getAktuellesPuzzle();
|
||||
|
||||
assertNotNull(puzzle);
|
||||
assertEquals(4, puzzle[0].length);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetLoesungsKoordinaten() throws IOException {
|
||||
PuzzleData puzzleData = new PuzzleData(new int[][]{{1, 2}}, List.of(new int[]{1, 1}));
|
||||
when(csvReaderMock.readPuzzleWithSolution(anyString())).thenReturn(puzzleData);
|
||||
|
||||
facade.ladeSpielfeld("test.csv");
|
||||
|
||||
List<int[]> solutionCoordinates = facade.getLoesungsKoordinaten();
|
||||
|
||||
assertNotNull(solutionCoordinates);
|
||||
assertEquals(1, solutionCoordinates.size());
|
||||
assertArrayEquals(new int[]{1, 1}, solutionCoordinates.get(0));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,153 @@
|
|||
package de.deversmann.gui;
|
||||
|
||||
import de.deversmann.facade.Facade;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
class GameViewTest {
|
||||
|
||||
private Facade facadeMock;
|
||||
private GameView gameView;
|
||||
|
||||
@BeforeEach
|
||||
void setup() {
|
||||
facadeMock = mock(Facade.class);
|
||||
gameView = new GameView(facadeMock);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testInitComponents() {
|
||||
assertNotNull(gameView.cbSpielfelder);
|
||||
assertNotNull(gameView.btnLoad);
|
||||
assertNotNull(gameView.btnRandom);
|
||||
assertNotNull(gameView.btnCheckSolution);
|
||||
assertNotNull(gameView.btnShowSolution);
|
||||
assertNotNull(gameView.btnReset);
|
||||
assertNotNull(gameView.timeLabel);
|
||||
assertNotNull(gameView.spielfeldGUI);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testLoadPuzzleActionWithRealData() throws Exception {
|
||||
doNothing().when(facadeMock).ladeSpielfeld("4x4.csv");
|
||||
|
||||
gameView.ladeSpielfeld("4x4.csv");
|
||||
|
||||
verify(facadeMock, times(1)).ladeSpielfeld("4x4.csv");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testLoadInvalidPuzzle() throws IOException {
|
||||
doThrow(new IOException("Invalid file")).when(facadeMock).ladeSpielfeld("invalid.csv");
|
||||
|
||||
gameView.ladeSpielfeld("invalid.csv");
|
||||
|
||||
verify(facadeMock, times(1)).ladeSpielfeld("invalid.csv");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCheckSolutionWithCorrectData() {
|
||||
var blackCells = List.of(new int[]{0, 0});
|
||||
var solutionCoordinates = List.of(new int[]{1, 1});
|
||||
|
||||
when(facadeMock.getLoesungsKoordinaten()).thenReturn(solutionCoordinates);
|
||||
when(facadeMock.getAktuellesPuzzle()).thenReturn(new int[][]{{1, 2}});
|
||||
|
||||
SpielfeldGUI spielfeldGUIMock = mock(SpielfeldGUI.class);
|
||||
when(spielfeldGUIMock.getBlackCells()).thenReturn(blackCells);
|
||||
|
||||
gameView.spielfeldGUI = spielfeldGUIMock;
|
||||
gameView.checkSolution();
|
||||
|
||||
verify(spielfeldGUIMock, never()).markCellAsError(anyInt(), anyInt());
|
||||
verify(facadeMock, times(1)).stopZeiterfassung();
|
||||
verify(facadeMock, times(1)).addHighscoreForCurrentPuzzle(anyString(), anyLong(), anyInt());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCheckSolutionWithErrors() {
|
||||
var blackCells = List.of(new int[]{0, 1});
|
||||
var solutionCoordinates = List.of(new int[]{1, 1});
|
||||
|
||||
when(facadeMock.getLoesungsKoordinaten()).thenReturn(solutionCoordinates);
|
||||
when(facadeMock.getAktuellesPuzzle()).thenReturn(new int[][]{{1, 2}});
|
||||
|
||||
SpielfeldGUI spielfeldGUIMock = mock(SpielfeldGUI.class);
|
||||
when(spielfeldGUIMock.getBlackCells()).thenReturn(blackCells);
|
||||
|
||||
gameView.spielfeldGUI = spielfeldGUIMock;
|
||||
gameView.checkSolution();
|
||||
|
||||
verify(spielfeldGUIMock, times(1)).markCellAsError(0, 1);
|
||||
verify(facadeMock, times(1)).incrementErrorCount();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testShowSolution() {
|
||||
int[][] mockGrid = {{1, 2}, {3, 4}};
|
||||
List<int[]> solution = List.of(new int[]{1, 1}, new int[]{2, 2});
|
||||
|
||||
when(facadeMock.getAktuellesPuzzle()).thenReturn(mockGrid);
|
||||
when(facadeMock.getLoesungsKoordinaten()).thenReturn(solution);
|
||||
|
||||
SpielfeldGUI spielfeldGUIMock = mock(SpielfeldGUI.class);
|
||||
gameView.spielfeldGUI = spielfeldGUIMock;
|
||||
|
||||
gameView.showSolution();
|
||||
|
||||
verify(spielfeldGUIMock, times(1)).updateGrid(mockGrid);
|
||||
verify(spielfeldGUIMock, times(1)).setCellBlack(0, 0); // Lösung wird schwarz markiert
|
||||
verify(spielfeldGUIMock, times(1)).setCellBlack(1, 1);
|
||||
verify(spielfeldGUIMock, times(1)).setAllNonBlackToWhite();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testResetField() {
|
||||
int[][] mockGrid = {{1, 2}, {3, 4}};
|
||||
when(facadeMock.getAktuellesPuzzle()).thenReturn(mockGrid);
|
||||
|
||||
SpielfeldGUI spielfeldGUIMock = mock(SpielfeldGUI.class);
|
||||
gameView.spielfeldGUI = spielfeldGUIMock;
|
||||
|
||||
gameView.resetField();
|
||||
|
||||
verify(spielfeldGUIMock, times(1)).updateGrid(mockGrid);
|
||||
assertEquals("Time: 0s", gameView.timeLabel.getText());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testTimerUpdatesTimeLabel() {
|
||||
when(facadeMock.getElapsedTimeSoFar()).thenReturn(42L);
|
||||
|
||||
Timer timer = gameView.timer;
|
||||
assertNotNull(timer);
|
||||
|
||||
timer.getActionListeners()[0].actionPerformed(null);
|
||||
|
||||
JLabel timeLabel = gameView.timeLabel;
|
||||
assertEquals("Time: 42s", timeLabel.getText());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRandomPuzzleLoading() throws Exception {
|
||||
doNothing().when(facadeMock).ladeSpielfeld(anyString());
|
||||
|
||||
gameView.btnRandom.doClick();
|
||||
|
||||
verify(facadeMock, atLeastOnce()).ladeSpielfeld(anyString());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testContainsCell() {
|
||||
List<int[]> blackCells = List.of(new int[]{1, 1}, new int[]{2, 2});
|
||||
assertTrue(gameView.containsCell(blackCells, "1,1"));
|
||||
assertFalse(gameView.containsCell(blackCells, "3,3"));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
package de.deversmann.gui;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class SpielfeldGUITest {
|
||||
|
||||
@Test
|
||||
void testUpdateGrid() {
|
||||
SpielfeldGUI gui = new SpielfeldGUI(2, 2);
|
||||
|
||||
int[][] grid = {
|
||||
{1, 2},
|
||||
{3, 4}
|
||||
};
|
||||
gui.updateGrid(grid);
|
||||
|
||||
assertNotNull(gui.getBlackCells());
|
||||
assertEquals(0, gui.getBlackCells().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSetCellBlack() {
|
||||
SpielfeldGUI gui = new SpielfeldGUI(2, 2);
|
||||
|
||||
gui.setCellBlack(0, 1);
|
||||
assertEquals(1, gui.getBlackCells().size());
|
||||
assertArrayEquals(new int[]{0, 1}, gui.getBlackCells().get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testMarkCellAsError() {
|
||||
SpielfeldGUI gui = new SpielfeldGUI(2, 2);
|
||||
|
||||
gui.markCellAsError(0, 1);
|
||||
|
||||
// Fehlerhafte Zelle wird rot markiert (Border)
|
||||
assertNotNull(gui.getBlackCells());
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue