Musste neuen Commit machen, nachdem Datenstand nicht den gleichen Stand hatte wie main um einen Pull request in main zu gestatten

pull/2/head
Leon Maximilian Löhle 2025-01-06 19:42:02 +01:00
parent da6ffa8379
commit ae5fb68bd4
5 changed files with 252 additions and 57 deletions

View File

@ -1,6 +1,5 @@
package de.deversmann.domain;
public class Zeiterfassung {
private long startTime;

View File

@ -1,54 +1,4 @@
package de.deversmann.facade;
import java.io.IOException;
import java.util.List;
public class Facade {
private final CSVReader csvReader;
private final HighscoreManager_2_0 highscoreManager;
private final Zeiterfassung_2_0 zeiterfassung;
// Hier speichern wir das aktuell geladene Puzzle (mit Lösung)
private PuzzleData currentPuzzleData;
public Facade() {
this.csvReader = new CSVReader();
this.highscoreManager = new HighscoreManager_2_0();
this.zeiterfassung = new Zeiterfassung_2_0();
}
public void ladeSpielfeld(String csvPfad) throws IOException {
// Liest Puzzle + Lösung aus der CSV
this.currentPuzzleData = csvReader.readPuzzleWithSolution(csvPfad);
}
public int[][] getAktuellesPuzzle() {
return (currentPuzzleData != null)
? currentPuzzleData.getPuzzle()
: null;
}
public List<int[]> getLoesungsKoordinaten() {
return (currentPuzzleData != null)
? currentPuzzleData.getSolutionCoordinates()
: null;
}
public void startZeiterfassung() {
zeiterfassung.start();
}
public long stopZeiterfassung() {
zeiterfassung.stop();
return zeiterfassung.getElapsedTimeInSeconds();
}
public void addHighscore(int score) {
highscoreManager.addHighscore(score);
}
public List<Integer> getAllHighscores() {
return highscoreManager.getHighscores();
}
}
}

View File

@ -1,4 +1,235 @@
package de.deversmann.gui;
public class GameView {
}
import de.deversmann.facade.Facade;
import javax.swing.*;
import java.awt.*;
import java.io.IOException;
import java.util.List;
import java.util.Random;
public class GameView extends JFrame {
private final Facade facade;
private 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;
private final String[] spielfelder = {
"4x4.csv",
"5x5.csv",
"8x8_leicht.csv",
"8x8_medium.csv",
"10x10.csv",
"15x15.csv"
};
public GameView(Facade facade) {
this.facade = facade;
setTitle("Hitori App");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(800, 700);
initComponents();
startTimer();
setVisible(true);
}
private void initComponents() {
JPanel controlPanel = new JPanel();
cbSpielfelder = new JComboBox<>(spielfelder);
btnLoad = new JButton("Spielfeld laden");
btnRandom = new JButton("Zufällig");
btnCheckSolution = new JButton("Lösung prüfen");
btnShowSolution = new JButton("Lösung anzeigen");
btnReset = new JButton("Reset");
timeLabel = new JLabel("Time: 0s");
btnLoad.addActionListener(e -> {
String selectedFile = (String) cbSpielfelder.getSelectedItem();
if (selectedFile != null) {
ladeSpielfeld("src/Spielfelder/" + selectedFile);
}
});
btnRandom.addActionListener(e -> {
Random rand = new Random();
int idx = rand.nextInt(spielfelder.length);
String randomField = spielfelder[idx];
cbSpielfelder.setSelectedItem(randomField);
ladeSpielfeld("src/Spielfelder/" + randomField);
});
btnCheckSolution.addActionListener(e -> checkSolution());
btnShowSolution.addActionListener(e -> showSolution());
btnReset.addActionListener(e -> resetField());
controlPanel.add(new JLabel("Wähle ein Spielfeld:"));
controlPanel.add(cbSpielfelder);
controlPanel.add(btnLoad);
controlPanel.add(btnRandom);
controlPanel.add(btnCheckSolution);
controlPanel.add(btnShowSolution);
controlPanel.add(btnReset);
controlPanel.add(timeLabel);
getContentPane().setLayout(new BorderLayout());
getContentPane().add(controlPanel, BorderLayout.NORTH);
spielfeldGUI = new SpielfeldGUI(1, 1);
getContentPane().add(spielfeldGUI, BorderLayout.CENTER);
}
private void startTimer() {
timer = new Timer(1000, e -> {
long seconds = facade.getElapsedTimeSoFar();
timeLabel.setText("Time: " + seconds + "s");
});
timer.start();
}
private void ladeSpielfeld(String pfad) {
try {
facade.ladeSpielfeld(pfad);
facade.loadCurrentPuzzleHighscoreFromFile();
int[][] feld = facade.getAktuellesPuzzle();
if (feld != null) {
spielfeldGUI.updateGrid(feld);
timeLabel.setText("Time: 0s");
}
} catch (IOException ex) {
JOptionPane.showMessageDialog(this,
"Fehler beim Laden: " + ex.getMessage(),
"Fehler",
JOptionPane.ERROR_MESSAGE
);
}
}
private void checkSolution() {
var blackCells = spielfeldGUI.getBlackCells();
var solutionCoordinates = facade.getLoesungsKoordinaten();
if (solutionCoordinates == null) {
JOptionPane.showMessageDialog(this, "Kein Puzzle geladen!", "Fehler", JOptionPane.ERROR_MESSAGE);
return;
}
Set<String> solutionSet = new HashSet<>();
for (int[] sol : solutionCoordinates) {
solutionSet.add((sol[0] - 1) + "," + (sol[1] - 1));
}
int errorsThisCheck = 0;
for (int[] bc : blackCells) {
String bcStr = bc[0] + "," + bc[1];
if (!solutionSet.contains(bcStr)) {
spielfeldGUI.markCellAsError(bc[0], bc[1]);
facade.incrementErrorCount();
errorsThisCheck++;
}
}
if (errorsThisCheck > 0) {
JOptionPane.showMessageDialog(this,
"Noch nicht korrekt! " + errorsThisCheck + " falsche Felder markiert.",
"Ergebnis",
JOptionPane.WARNING_MESSAGE
);
return;
}
boolean allSet = true;
for (String sol : solutionSet) {
if (!containsCell(blackCells, sol)) {
allSet = false;
break;
}
}
if (!allSet) {
JOptionPane.showMessageDialog(this,
"Nicht alle richtigen Felder sind schwarz!",
"Ergebnis",
JOptionPane.WARNING_MESSAGE
);
return;
}
long finalTime = facade.stopZeiterfassung();
timeLabel.setText("Time: " + finalTime + "s");
String playerName = JOptionPane.showInputDialog(
this,
"Gratulation, richtig gelöst!\nBitte Namen eingeben:",
"Name eingeben",
JOptionPane.QUESTION_MESSAGE
);
if (playerName == null || playerName.isBlank()) {
playerName = "Unbekannt";
}
int totalErrors = facade.getCurrentErrorCount();
facade.addHighscoreForCurrentPuzzle(playerName, finalTime, totalErrors);
try {
facade.saveCurrentPuzzleHighscoreToFile();
} catch (IOException e) {
System.out.println("Konnte Puzzle-spezifischen Highscore nicht speichern: " + e.getMessage());
}
double avgTime = facade.getAverageTimeForCurrentPuzzle();
StringBuilder sb = new StringBuilder();
sb.append("Spiel gelöst!\n");
sb.append("Deine Zeit: ").append(finalTime).append("s\n");
sb.append("Fehler: ").append(totalErrors).append("\n");
if (avgTime < 0) {
sb.append("Durchschnittszeit: Keine Einträge\n");
} else {
sb.append(String.format("Durchschnittszeit: %.2f s\n", avgTime));
}
JOptionPane.showMessageDialog(this, sb.toString(), "Ergebnis", JOptionPane.INFORMATION_MESSAGE);
}
private boolean containsCell(List<int[]> blackCells, String sol) {
String[] parts = sol.split(",");
int rr = Integer.parseInt(parts[0]);
int cc = Integer.parseInt(parts[1]);
for (int[] bc : blackCells) {
if (bc[0] == rr && bc[1] == cc) {
return true;
}
}
return false;
}
private void showSolution() {
var feld = facade.getAktuellesPuzzle();
if (feld == null) return;
spielfeldGUI.updateGrid(feld);
var solution = facade.getLoesungsKoordinaten();
if (solution != null) {
for (int[] coord : solution) {
spielfeldGUI.setCellBlack(coord[0] - 1, coord[1] - 1);
}
}
spielfeldGUI.setAllNonBlackToWhite();
}
private void resetField() {
var feld = facade.getAktuellesPuzzle();
if (feld != null) {
spielfeldGUI.updateGrid(feld);
timeLabel.setText("Time: 0s");
}
}
}

View File

@ -1,4 +1,18 @@
package de.deversmann.gui;
import de.deversmann.facade.Facade;
public class HitoriApp {
private Facade facade;
public HitoriApp() {
facade = new Facade();
}
public void start() {
GameView view = new GameView(facade);
view.setVisible(true);
}
}

View File

@ -5,13 +5,14 @@ import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.*;
import java.util.List;
public class SpielfeldGUI_2_0 extends JPanel {
public class SpielfeldGUI extends JPanel {
private JLabel[][] grid;
private Set<String> errorCells = new HashSet<>();
public SpielfeldGUI_2_0(int rows, int cols) {
public SpielfeldGUI(int rows, int cols) {
setLayout(new GridLayout(rows, cols));
grid = new JLabel[rows][cols];
@ -132,4 +133,4 @@ public class SpielfeldGUI_2_0 extends JPanel {
if (grid == null) return false;
return (r >= 0 && r < grid.length && c >= 0 && c < grid[r].length);
}
}
}