Merge remote-tracking branch 'origin/Main' into JUnit-Tests
commit
5770d13cdc
File diff suppressed because it is too large
Load Diff
|
@ -123,13 +123,88 @@ public class GameController {
|
|||
updateGuiBoard();
|
||||
});
|
||||
|
||||
// --- AUFGEBEN-BUTTON ---
|
||||
gui.getResignButton().addActionListener(e -> {
|
||||
if (gameOver) return;
|
||||
|
||||
int answer = javax.swing.JOptionPane.showConfirmDialog(
|
||||
null,
|
||||
"Willst du wirklich aufgeben?",
|
||||
"Aufgeben",
|
||||
javax.swing.JOptionPane.YES_NO_OPTION
|
||||
);
|
||||
if (answer == javax.swing.JOptionPane.YES_OPTION) {
|
||||
gameOver = true;
|
||||
String winner = engine.getCurrentPlayer().equals("WHITE") ? "SCHWARZ" : "WEIß";
|
||||
gui.displayMessage(winner + " gewinnt durch Aufgabe!");
|
||||
engine.getWhiteTimer().stop();
|
||||
engine.getBlackTimer().stop();
|
||||
askForRestart();
|
||||
}
|
||||
});
|
||||
|
||||
// --- PATT-/REMIS-BUTTON ---
|
||||
gui.getDrawButton().addActionListener(e -> {
|
||||
if (gameOver) return;
|
||||
|
||||
int answer = javax.swing.JOptionPane.showConfirmDialog(
|
||||
null,
|
||||
"Remis anbieten? (Das Spiel endet sofort unentschieden)",
|
||||
"Remis",
|
||||
javax.swing.JOptionPane.YES_NO_OPTION
|
||||
);
|
||||
if (answer == javax.swing.JOptionPane.YES_OPTION) {
|
||||
gameOver = true;
|
||||
gui.displayMessage("Remis! (durch Einigung)");
|
||||
engine.getWhiteTimer().stop();
|
||||
engine.getBlackTimer().stop();
|
||||
askForRestart();
|
||||
}
|
||||
});
|
||||
|
||||
gui.getUndoButton().addActionListener(e -> {
|
||||
// Wer ist am Zug? (Das ist der, der gefragt wird)
|
||||
String currentPlayer = engine.getCurrentPlayer(); // "WHITE" oder "BLACK"
|
||||
// Wer möchte zurücknehmen? (Das ist der, der NICHT am Zug ist)
|
||||
String currentName = currentPlayer.equals("WHITE") ? "Weiß" : "Schwarz";
|
||||
String previousName = currentPlayer.equals("WHITE") ? "Schwarz" : "Weiß";
|
||||
|
||||
int answer = javax.swing.JOptionPane.showConfirmDialog(
|
||||
null,
|
||||
currentName + " ist am Zug. " +
|
||||
previousName + " möchte seinen letzten Zug zurücknehmen.\n" +
|
||||
currentName + ", erlaubst du das?",
|
||||
"Zug zurücknehmen?",
|
||||
javax.swing.JOptionPane.YES_NO_OPTION
|
||||
);
|
||||
|
||||
if (answer == javax.swing.JOptionPane.YES_OPTION) {
|
||||
engine.undoLastMove();
|
||||
updateGuiBoard();
|
||||
gui.updateMoveList(engine.getMoveListStringsGrouped());
|
||||
gui.setOpeningLabel(engine.getOpeningName());
|
||||
gui.displayMessage("Der letzte Zug wurde zurückgenommen.");
|
||||
} else if (answer == javax.swing.JOptionPane.NO_OPTION) {
|
||||
gui.displayMessage("Das Zurücknehmen wurde abgelehnt.");
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
private boolean isAtLatestMove() {
|
||||
return engine.getCurrentMoveIndex() == engine.getMoveListSize();
|
||||
}
|
||||
|
||||
private void handleClick(int guiRow, int guiCol) {
|
||||
|
||||
if (gameOver) return;
|
||||
|
||||
if (!isAtLatestMove()) {
|
||||
gui.displayMessage("Du bist im Zug-Archiv und kannst keine Figuren bewegen. Klick auf '>|', um zum letzten Zug zu gehen.");
|
||||
return;
|
||||
}
|
||||
|
||||
int modelRow = flipRow(guiRow);
|
||||
int modelCol = flipCol(guiCol);
|
||||
|
||||
|
@ -226,6 +301,7 @@ public class GameController {
|
|||
public void updateGuiBoard() {
|
||||
BoardDTO board = engine.getBoardAsDTO();
|
||||
gui.updateBoard(board);
|
||||
gui.setOpeningLabel(engine.getOpeningName());
|
||||
}
|
||||
|
||||
private void switchTimers() {
|
||||
|
|
|
@ -31,11 +31,12 @@ public class ChessEngine {
|
|||
private Timer whiteTimer;
|
||||
private Timer blackTimer;
|
||||
|
||||
private Opening detectedOpening = null;
|
||||
|
||||
public ChessEngine() {
|
||||
logging();
|
||||
board = new Board();
|
||||
}
|
||||
|
||||
public boolean move(MoveDTO move) {
|
||||
String from = "" + (char)('A' + move.getFromCol()) + (8 - move.getFromRow());
|
||||
String to = "" + (char)('A' + move.getToCol()) + (8 - move.getToRow());
|
||||
|
@ -43,7 +44,7 @@ public class ChessEngine {
|
|||
if (board.legalMoves().contains(libMove)) {
|
||||
board.doMove(libMove);
|
||||
|
||||
//Replay? Dann abschneiden
|
||||
// Replay? Dann abschneiden
|
||||
if (currentMoveIndex < moves.size()) {
|
||||
logger.info("Replay-Modus: Züge nach " + currentMoveIndex + " werden entfernt.");
|
||||
moves = new ArrayList<>(moves.subList(0, currentMoveIndex));
|
||||
|
@ -51,12 +52,37 @@ public class ChessEngine {
|
|||
moves.add(libMove);
|
||||
currentMoveIndex++;
|
||||
logger.info("Zug erfolgreich durchgeführt: " + libMove);
|
||||
|
||||
// Opening-Erkennung nach jedem erfolgreichen Zug
|
||||
String playedMovesUci = movesToUciString(moves);
|
||||
detectedOpening = Opening.detect(playedMovesUci);
|
||||
|
||||
if (detectedOpening != null) {
|
||||
logger.info("Aktuelles Opening erkannt: " + detectedOpening.getEco() + " - " + detectedOpening.getName());
|
||||
// Optional: Speichere das Opening in ein Feld, falls benötigt
|
||||
}
|
||||
return true;
|
||||
}
|
||||
logger.warning("Ungültiger Zug: " + libMove);
|
||||
return false;
|
||||
}
|
||||
|
||||
public String getOpeningName() {
|
||||
if (detectedOpening != null) {
|
||||
return detectedOpening.getEco() + " - " + detectedOpening.getName();
|
||||
} else {
|
||||
return "unbekannt";
|
||||
}
|
||||
}
|
||||
|
||||
private String movesToUciString(List<Move> moves) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (Move m : moves) {
|
||||
sb.append(m.toString()).append(" ");
|
||||
}
|
||||
return sb.toString().trim();
|
||||
}
|
||||
|
||||
public List<MoveDTO> getLegalDestinations(String from) {
|
||||
logger.info("Hole legale Züge von: " + from);
|
||||
List<MoveDTO> destinations = new ArrayList<>();
|
||||
|
@ -169,6 +195,9 @@ public class ChessEngine {
|
|||
board.doMove(moves.get(i));
|
||||
}
|
||||
currentMoveIndex = idx;
|
||||
|
||||
String playedMovesUci = movesToUciString(moves.subList(0, idx));
|
||||
detectedOpening = Opening.detect(playedMovesUci);
|
||||
}
|
||||
|
||||
public int getCurrentMoveIndex() {
|
||||
|
@ -355,6 +384,18 @@ public class ChessEngine {
|
|||
}
|
||||
|
||||
|
||||
public void undoLastMove() {
|
||||
if (currentMoveIndex > 0 && moves.size() > 0) {
|
||||
board.undoMove(); // 1. Brett zurücksetzen
|
||||
moves.remove(currentMoveIndex - 1); // 2. Zug aus Move-Liste löschen
|
||||
currentMoveIndex--; // 3. Index anpassen
|
||||
|
||||
// 4. Erkennung Opening neu machen!
|
||||
String playedMovesUci = movesToUciString(moves.subList(0, currentMoveIndex));
|
||||
detectedOpening = Opening.detect(playedMovesUci);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void loadMoves(List<Move> moveList) {
|
||||
board = new Board(); // Neues leeres Brett
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
package de.hs_mannheim.informatik.chess.model;
|
||||
|
||||
import java.util.*;
|
||||
import java.nio.file.*;
|
||||
import java.io.*;
|
||||
|
||||
public class Opening {
|
||||
private final String eco;
|
||||
private final String name;
|
||||
private final String moves;
|
||||
|
||||
public Opening(String eco, String name, String moves) {
|
||||
this.eco = eco;
|
||||
this.name = name;
|
||||
this.moves = moves;
|
||||
}
|
||||
|
||||
public String getEco() { return eco; }
|
||||
public String getName() { return name; }
|
||||
public String getMoves() { return moves; }
|
||||
|
||||
// Öffnet und cached die Liste aus der gewünschten CSV
|
||||
private static List<Opening> cachedOpenings = null;
|
||||
|
||||
public static List<Opening> allOpenings() {
|
||||
if (cachedOpenings == null) {
|
||||
cachedOpenings = new ArrayList<>();
|
||||
// Passe den Pfad für deinen Benutzernamen an!
|
||||
String path = "Ressources/all_openings.csv";
|
||||
|
||||
try (BufferedReader br = Files.newBufferedReader(Paths.get(path))) {
|
||||
String line;
|
||||
while ((line = br.readLine()) != null) {
|
||||
// CSV-Format: ECO,"Name","Moves"
|
||||
String[] parts = line.split(",(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)", -1);
|
||||
if (parts.length == 3) {
|
||||
String eco = parts[0];
|
||||
String name = parts[1].replaceAll("^\"|\"$", "");
|
||||
String moves = parts[2].replaceAll("^\"|\"$", "");
|
||||
cachedOpenings.add(new Opening(eco, name, moves));
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return cachedOpenings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sucht das längste passende Opening für eine gegebene Zugfolge (UCI).
|
||||
* @param playedMovesUci UCI-Züge als String, z.B. "e2e4 e7e5 g1f3"
|
||||
* @return bestes Opening oder null
|
||||
*/
|
||||
public static Opening detect(String playedMovesUci) {
|
||||
Opening bestMatch = null;
|
||||
int bestLength = 0;
|
||||
for (Opening opening : allOpenings()) {
|
||||
if (playedMovesUci.startsWith(opening.getMoves())) {
|
||||
if (opening.getMoves().length() > bestLength) {
|
||||
bestMatch = opening;
|
||||
bestLength = opening.getMoves().length();
|
||||
}
|
||||
}
|
||||
}
|
||||
return bestMatch;
|
||||
}
|
||||
}
|
|
@ -30,7 +30,8 @@ public class CreativeGui {
|
|||
public CreativeGui() {
|
||||
frame = new JFrame("Creative Mode");
|
||||
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
|
||||
frame.setSize(1600, 1200);
|
||||
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
|
||||
frame.setUndecorated(false);
|
||||
frame.setLocationRelativeTo(null);
|
||||
|
||||
JPanel mainPanel = new JPanel(new GridBagLayout());
|
||||
|
|
|
@ -7,9 +7,12 @@ import java.awt.Font;
|
|||
import java.awt.GridBagConstraints;
|
||||
import java.awt.GridBagLayout;
|
||||
import java.awt.GridLayout;
|
||||
import java.awt.FlowLayout;
|
||||
|
||||
import java.awt.Insets;
|
||||
import java.util.List;
|
||||
|
||||
import javax.swing.Box;
|
||||
import javax.swing.BoxLayout;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JFrame;
|
||||
|
@ -31,11 +34,17 @@ public class GameGui {
|
|||
|
||||
private JLabel whiteTimerLabel;
|
||||
private JLabel blackTimerLabel;
|
||||
private JLabel openingLabel;
|
||||
|
||||
JButton btnFirst = new JButton("|<");
|
||||
JButton btnPrev = new JButton("<");
|
||||
JButton btnNext = new JButton(">");
|
||||
JButton btnLast = new JButton(">|");
|
||||
private JButton btnFirst = new JButton("|<");
|
||||
private JButton btnPrev = new JButton("<");
|
||||
private JButton btnNext = new JButton(">");
|
||||
private JButton btnLast = new JButton(">|");
|
||||
|
||||
private JButton resignButton;
|
||||
private JButton drawButton;
|
||||
private JButton quickSaveButton;
|
||||
private JButton undoButton;
|
||||
|
||||
Color LIGHT = new Color(0xe0e1dd);
|
||||
Color DARK = new Color(0x778da9);
|
||||
|
@ -51,7 +60,8 @@ public class GameGui {
|
|||
|
||||
public JFrame mainFrame() {
|
||||
JFrame frame = new JFrame();
|
||||
frame.setSize(1600, 1000);
|
||||
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
|
||||
frame.setUndecorated(false);
|
||||
frame.setLocationRelativeTo(null);
|
||||
frame.add(mainPanel());
|
||||
|
||||
|
@ -127,19 +137,58 @@ public class GameGui {
|
|||
return boardPanel;
|
||||
}
|
||||
|
||||
public JPanel chessPanel(JPanel panel) {
|
||||
JPanel chessPanel = new JPanel(new GridBagLayout());
|
||||
GridBagConstraints board = new GridBagConstraints();
|
||||
public JPanel chessPanel(JPanel boardPanel) {
|
||||
JPanel chessPanel = new JPanel(new BorderLayout());
|
||||
chessPanel.setBackground(new Color(0x1b263b));
|
||||
board.gridx = 0;
|
||||
board.gridy = 0;
|
||||
board.weightx = 0.7;
|
||||
board.weighty = 1.0;
|
||||
board.insets = new Insets(0, 0, 0, 0);
|
||||
//oben, links, unten, rechts
|
||||
board.fill = GridBagConstraints.BOTH;
|
||||
chessPanel.add(panel);
|
||||
// Button unten rechts
|
||||
|
||||
// --- Eröffnungslabel oben ---
|
||||
openingLabel = new JLabel("Eröffnung: unbekannt", SwingConstants.CENTER);
|
||||
openingLabel.setFont(new Font("SansSerif", Font.BOLD, 24));
|
||||
openingLabel.setForeground(Color.WHITE);
|
||||
openingLabel.setOpaque(true);
|
||||
openingLabel.setBackground(new Color(0x283655));
|
||||
openingLabel.setPreferredSize(new Dimension(800, 50));
|
||||
chessPanel.add(openingLabel, BorderLayout.NORTH);
|
||||
|
||||
// --- Board in ein zentriertes Panel mit fixer Größe ---
|
||||
JPanel centerPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 0, 0));
|
||||
centerPanel.setOpaque(false);
|
||||
centerPanel.add(boardPanel);
|
||||
|
||||
centerPanel.addComponentListener(new java.awt.event.ComponentAdapter() {
|
||||
public void componentResized(java.awt.event.ComponentEvent evt) {
|
||||
int size = Math.min(centerPanel.getWidth(), centerPanel.getHeight());
|
||||
boardPanel.setPreferredSize(new Dimension(size, size));
|
||||
boardPanel.revalidate();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
chessPanel.add(centerPanel, BorderLayout.CENTER);
|
||||
|
||||
// --- Dummy-Buffer für WEST und EAST ---
|
||||
chessPanel.add(Box.createRigidArea(new Dimension(40, 0)), BorderLayout.WEST);
|
||||
chessPanel.add(Box.createRigidArea(new Dimension(40, 0)), BorderLayout.EAST);
|
||||
|
||||
// --- Buttonleiste unten bauen ---
|
||||
JPanel buttonRow = new JPanel();
|
||||
buttonRow.setOpaque(false);
|
||||
buttonRow.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.RIGHT, 10, 0));
|
||||
|
||||
resignButton = new JButton("🏳");
|
||||
resignButton.setPreferredSize(new Dimension(70, 70));
|
||||
resignButton.setFont(new Font("SansSerif", Font.BOLD, 35));
|
||||
resignButton.setBackground(new Color(0xff0044));
|
||||
resignButton.setForeground(Color.WHITE);
|
||||
resignButton.setFocusPainted(false);
|
||||
|
||||
drawButton = new JButton("½");
|
||||
drawButton.setPreferredSize(new Dimension(70, 70));
|
||||
drawButton.setFont(new Font("SansSerif", Font.BOLD, 35));
|
||||
drawButton.setBackground(new Color(0x0080ff));
|
||||
drawButton.setForeground(Color.WHITE);
|
||||
drawButton.setFocusPainted(false);
|
||||
|
||||
flipBoardButton = new JButton("⇵");
|
||||
flipBoardButton.setPreferredSize(new Dimension(70, 70));
|
||||
flipBoardButton.setFont(new Font("SansSerif", Font.BOLD, 40));
|
||||
|
@ -147,19 +196,24 @@ public class GameGui {
|
|||
flipBoardButton.setForeground(Color.WHITE);
|
||||
flipBoardButton.setFocusPainted(false);
|
||||
|
||||
GridBagConstraints btn = new GridBagConstraints();
|
||||
btn.gridx = 0;
|
||||
btn.gridy = 1;
|
||||
btn.weightx = 0.0;
|
||||
btn.weighty = 0.0;
|
||||
btn.anchor = GridBagConstraints.SOUTHEAST;
|
||||
btn.insets = new Insets(10, 0, 0, 0);
|
||||
undoButton = new JButton("↧");
|
||||
undoButton.setPreferredSize(new Dimension(70, 70));
|
||||
undoButton.setFont(new Font("SansSerif", Font.BOLD, 40));
|
||||
undoButton.setBackground(new Color(0xffa500)); // Orange
|
||||
undoButton.setForeground(Color.WHITE);
|
||||
undoButton.setFocusPainted(false);
|
||||
|
||||
chessPanel.add(flipBoardButton, btn);
|
||||
buttonRow.add(undoButton);
|
||||
buttonRow.add(resignButton);
|
||||
buttonRow.add(drawButton);
|
||||
buttonRow.add(flipBoardButton);
|
||||
|
||||
chessPanel.add(buttonRow, BorderLayout.SOUTH);
|
||||
|
||||
return chessPanel;
|
||||
}
|
||||
|
||||
|
||||
public JPanel statsPanel() {
|
||||
JPanel statsPanel = new JPanel(new BorderLayout());
|
||||
statsPanel.setBackground(new Color(0x0d1b2a));
|
||||
|
@ -270,6 +324,8 @@ public class GameGui {
|
|||
public JButton getBtnNext() { return btnNext; }
|
||||
public JButton getBtnLast() { return btnLast; }
|
||||
public JButton getBtnSave() { return btnSave; }
|
||||
public JButton getResignButton() { return resignButton; }
|
||||
public JButton getDrawButton() { return drawButton; }
|
||||
|
||||
public void updateBoard(BoardDTO boardDTO) {
|
||||
PieceDTO[][] board = boardDTO.getBoard();
|
||||
|
@ -309,6 +365,13 @@ public class GameGui {
|
|||
public JLabel getWhiteTimerLabel() { return whiteTimerLabel; }
|
||||
public JLabel getBlackTimerLabel() { return blackTimerLabel; }
|
||||
|
||||
public void setOpeningLabel(String text) {
|
||||
openingLabel.setText("Eröffnung: " + text);
|
||||
}
|
||||
|
||||
public JButton getUndoButton() {
|
||||
return undoButton;
|
||||
}
|
||||
|
||||
public void displayMessage(String msg) {
|
||||
JOptionPane.showMessageDialog(null, msg);
|
||||
|
|
|
@ -17,7 +17,8 @@ public class MainGui {
|
|||
|
||||
frame = new JFrame("Chess - Hauptmenü");
|
||||
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||
frame.setSize(1600, 1000);
|
||||
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
|
||||
frame.setUndecorated(false);
|
||||
frame.setLocationRelativeTo(null);
|
||||
|
||||
//Haupt-Panel mit GridBagLayout
|
||||
|
|
|
@ -47,7 +47,8 @@ public class PgnGui {
|
|||
|
||||
public JFrame mainFrame() {
|
||||
JFrame frame = new JFrame();
|
||||
frame.setSize(1600, 1000);
|
||||
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
|
||||
frame.setUndecorated(false);
|
||||
frame.setLocationRelativeTo(null);
|
||||
frame.add(mainPanel());
|
||||
|
||||
|
|
Loading…
Reference in New Issue