package de.deversmann.gui; 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; SpielfeldGUI spielfeldGUI; JComboBox cbSpielfelder; JButton btnLoad; JButton btnRandom; JButton btnCheckSolution; JButton btnShowSolution; JButton btnReset; JLabel timeLabel; 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(); } 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 ); } } 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 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); } boolean containsCell(List 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; } 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(); } void resetField() { var feld = facade.getAktuellesPuzzle(); if (feld != null) { spielfeldGUI.updateGrid(feld); timeLabel.setText("Time: 0s"); } } }