Merge branch 'main' into Löhle
# Conflicts: # src/main/java/de/deversmann/gui/GameView.java # src/main/java/de/deversmann/gui/HitoriApp.javapull/2/head
commit
da6ffa8379
|
@ -0,0 +1,39 @@
|
|||
package de.deversmann.domain;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
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<>();
|
||||
|
||||
try (BufferedReader br = new BufferedReader(new FileReader(csvFile))) {
|
||||
String line;
|
||||
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());
|
||||
}
|
||||
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);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
|
@ -1,235 +1,4 @@
|
|||
package de.deversmann.gui;
|
||||
|
||||
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_2_0 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_2_0(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");
|
||||
}
|
||||
}
|
||||
}
|
||||
public class GameView {
|
||||
}
|
||||
|
|
|
@ -1,17 +1,4 @@
|
|||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue