Compare commits

..

4 Commits

Author SHA1 Message Date
thomasmuller 72fd28335f Merge branch 'Quellen' of
https://gitty.informatik.hs-mannheim.de/3021788/PR2_Schach_Teamprojekt.git
into Quellen
2025-06-24 10:49:32 +02:00
Justin Muravjev c981efc0a0 Quellen Justin Muravjev 2025-06-24 10:45:22 +02:00
thomasmuller b5682dc4c8 Quelle erstellt 2025-06-24 10:24:47 +02:00
valen c8dfcab90e LibaryZusammenfassung und Quellen. Mit ChatGPTlinks und Githublink 2025-06-23 21:30:58 +02:00
18 changed files with 498 additions and 1508 deletions

View File

@ -1,8 +1,5 @@
Quellen
Thomas Müller | 3021788
Timer https://chatgpt.com/c/6857ff1e-7ff4-8006-aba3-60d3a2dd59b4
Valentin Weller | 3019075
Junit: https://chatgpt.com/share/6859a713-4b98-8012-8cb2-a9f3c7fb37c8
@ -12,6 +9,11 @@ PGNs: https://chatgpt.com/share/6859a8f1-d3c4-8012-98f4-6ae4b057be73
Eröffnungserkennung: https://github.com/hell-sh/CompactChessOpenings/blob/master/src/sh/hell/compactchess/game/Opening.java
<<<<<<< HEAD
Thomas Müller | 3021788
Timer https://chatgpt.com/c/6857ff1e-7ff4-8006-aba3-60d3a2dd59b4
=======
Quellen
Justin Muravjev 3014931
@ -19,3 +21,4 @@ Justin Muravjev 3014931
ChatGPT:
https://chatgpt.com/share/685a60b4-dad0-8012-86a8-ca9a7e6eb76b
>>>>>>> branch 'Quellen' of https://gitty.informatik.hs-mannheim.de/3021788/PR2_Schach_Teamprojekt.git

View File

@ -10,12 +10,13 @@
<version>0.0.1-SNAPSHOT</version>
<name>schach</name>
<description>A simple schach project</description>
<description>A simple schach.</description>
<url>http://www.example.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.release>17</maven.compiler.release>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
</properties>
<repositories>
@ -26,31 +27,22 @@
</repositories>
<dependencies>
<!-- Schachlib -->
<!-- Schachlib (bhlangonijr) -->
<dependency>
<groupId>com.github.bhlangonijr</groupId>
<artifactId>chesslib</artifactId>
<version>1.3.4</version>
</dependency>
<!-- JUnit 3 (wie im Template, ggf. auf JUnit 4/5 upgraden für moderne Projekte) -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.10.2</version>
<scope>test</scope>
</dependency>
<!-- Mockito -->
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>5.11.0</version>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
</dependencies>
<build>
<pluginManagement>
<plugins>
<plugin>
@ -91,59 +83,13 @@
</plugin>
</plugins>
</pluginManagement>
<plugins>
<!-- Java Compiler Plugin -->
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.13.0</version>
<configuration>
<release>17</release>
</configuration>
</plugin>
<!-- PMD Plugin -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-pmd-plugin</artifactId>
<version>3.21.0</version>
<configuration>
<!-- Set to 17 until PMD supports 21 -->
<targetJdk>17</targetJdk>
<failOnViolation>false</failOnViolation>
<printFailingErrors>true</printFailingErrors>
<linkXRef>false</linkXRef>
<rulesets>
<ruleset>rulesets/java/quickstart.xml</ruleset>
<ruleset>rulesets/java/basic.xml</ruleset>
<ruleset>rulesets/java/braces.xml</ruleset>
<ruleset>rulesets/java/unusedcode.xml</ruleset>
<ruleset>rulesets/java/imports.xml</ruleset>
</rulesets>
</configuration>
<executions>
<execution>
<phase>verify</phase>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- Surefire Plugin for tests -->
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.3.0</version>
</plugin>
</plugins>
</build>
<reporting>
<plugins>
<plugin>
<artifactId>maven-project-info-reports-plugin</artifactId>
<version>3.6.1</version>
</plugin>
</plugins>
</reporting>
</project>
</project>

View File

@ -29,7 +29,7 @@ public class CreativeController {
map.put("WHITE_ROOK", 'R');
map.put("WHITE_BISHOP", 'B');
map.put("WHITE_KNIGHT", 'N');
map.put("WHITE_PAWN", 'P');
map.put("WHITE_PAWN", 'P');
return map;
}

View File

@ -7,76 +7,28 @@ import java.util.ArrayList;
import java.util.List;
import javax.swing.BorderFactory;
import javax.swing.JOptionPane;
import com.github.bhlangonijr.chesslib.game.Game;
import de.hs_mannheim.informatik.chess.model.ChessEngine;
import de.hs_mannheim.informatik.chess.model.GameMode;
import de.hs_mannheim.informatik.chess.model.MoveDTO;
import de.hs_mannheim.informatik.chess.model.PieceDTO;
import de.hs_mannheim.informatik.chess.model.Timer;
import de.hs_mannheim.informatik.chess.model.BoardDTO;
import de.hs_mannheim.informatik.chess.view.GameGui;
public class GameController {
GameGui gui;
ChessEngine engine;
GameEndCallback callback;
private boolean gameOver = false;
private int selectedRow = -1;
private int selectedCol = -1;
private int selectedRow = -1, selectedCol = -1;
private List<int[]> highlightedFields = new ArrayList<>();
private boolean gameWasResignedOrDrawn = false;
private GameMode gameMode;
public GameController(GameGui gui, ChessEngine engine, GameEndCallback callback, GameMode gameMode) {
this(gui, engine, callback); // ruft anderen Konstruktor auf
this.gameMode = gameMode;
if (gameMode != null) {
engine.initTimers(gameMode.minutes, gameMode.incrementSeconds);
setupAndStartTimers();
}
addWindowCloseListener();
}
// Für Creative/PGN-Mode (ohne Zeit)
public GameController(GameGui gui, ChessEngine engine, GameEndCallback callback) {
public GameController(GameGui gui, ChessEngine engine) {
this.gui = gui;
this.engine = engine;
this.callback = callback;
this.gameMode = null;
addWindowCloseListener();
// KEINE Timer initialisieren
initListeners();
updateGuiBoard();
}
private void setupAndStartTimers() {
if (engine.getWhiteTimer() != null) {
engine.getWhiteTimer().setOnTick(secs -> gui.updateWhiteTimerLabel(secs));
engine.getWhiteTimer().setOnTimeout(() -> onTimeout("WHITE"));
engine.getWhiteTimer().stop(); // <-- WICHTIG!
}
if (engine.getBlackTimer() != null) {
engine.getBlackTimer().setOnTick(secs -> gui.updateBlackTimerLabel(secs));
engine.getBlackTimer().setOnTimeout(() -> onTimeout("BLACK"));
engine.getBlackTimer().stop(); // <-- WICHTIG!
}
// Timer-Labels initial setzen
if (engine.getWhiteTimer() != null) gui.updateWhiteTimerLabel(engine.getWhiteTimer().getSecondsLeft());
if (engine.getBlackTimer() != null) gui.updateBlackTimerLabel(engine.getBlackTimer().getSecondsLeft());
// Aktuellen Spieler-Timer starten:
if (engine.getCurrentPlayer().equals("WHITE")) {
engine.getWhiteTimer().start();
} else {
engine.getBlackTimer().start();
}
}
private int flipRow(int row) {
return gui.isFlipped() ? 7 - row : row;
}
@ -84,20 +36,6 @@ public class GameController {
return gui.isFlipped() ? 7 - col : col;
}
private void addWindowCloseListener() {
if (gui.getFrame() != null) {
gui.getFrame().addWindowListener(new java.awt.event.WindowAdapter() {
@Override
public void windowClosing(java.awt.event.WindowEvent e) {
if (!gameOver) {
engine.quicksave();
MainController.engineRAM = engine;
}
new MainController();
}
});
}
}
private void initListeners() {
for (int row = 0; row < 8; row++) {
for (int col = 0; col < 8; col++) {
@ -171,89 +109,11 @@ public class GameController {
// 3. Board neu zeichnen
updateGuiBoard();
});
// --- AUFGEBEN-BUTTON ---
gui.getResignButton().addActionListener(e -> {
if (gameOver) return;
int answer = JOptionPane.showConfirmDialog(
null,
"Willst du wirklich aufgeben?",
"Aufgeben",
JOptionPane.YES_NO_OPTION
);
if (answer == JOptionPane.YES_OPTION) {
gameOver = true;
gameWasResignedOrDrawn = true; // <<<<<<
String winner = engine.getCurrentPlayer().equals("WHITE") ? "SCHWARZ" : "WEIß";
gui.displayMessage(winner + " gewinnt durch Aufgabe!");
if (engine.getWhiteTimer() != null) engine.getWhiteTimer().stop();
if (engine.getBlackTimer() != null) engine.getBlackTimer().stop();
askForRestart();
}
});
gui.getDrawButton().addActionListener(e -> {
if (gameOver) return;
int answer = JOptionPane.showConfirmDialog(
null,
"Remis anbieten? (Das Spiel endet sofort unentschieden)",
"Remis",
JOptionPane.YES_NO_OPTION
);
if (answer == JOptionPane.YES_OPTION) {
gameOver = true;
gameWasResignedOrDrawn = true; // <<<<<<
gui.displayMessage("Remis! (durch Einigung)");
if (engine.getWhiteTimer() != null) engine.getWhiteTimer().stop();
if (engine.getBlackTimer() != null) 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);
@ -299,9 +159,6 @@ public class GameController {
}
private void handleMove(MoveDTO move) {
if (gameOver) return;
BoardDTO boardDTO = engine.getBoardAsDTO();
PieceDTO piece = boardDTO.getBoard()[move.getFromRow()][move.getFromCol()];
boolean isPawn = piece != null && piece.getType().equals("PAWN");
@ -328,23 +185,13 @@ public class GameController {
updateGuiBoard();
gui.updateMoveList(engine.getMoveListStringsGrouped());
// ---- HIER ist die Matt/Patt/Remis-Prüfung ----
if (engine.isMated()) {
String winner = engine.getCurrentPlayer().equals("WHITE") ? "SCHWARZ" : "WEIß";
gui.displayMessage(winner + " hat gewonnen (Schachmatt)!");
gameOver = true;
askForRestart();
} else if (engine.isStalemate() || engine.isDraw()) {
gui.displayMessage("Remis! (Stalemate oder andere Regel)");
gameOver = true;
askForRestart();
}
if (!engine.isMated() && !engine.isStalemate() && !engine.isDraw()) {
switchTimers();
}
}
@ -352,79 +199,16 @@ public class GameController {
public void updateGuiBoard() {
BoardDTO board = engine.getBoardAsDTO();
gui.updateBoard(board);
gui.setOpeningLabel(engine.getOpeningName());
}
private void switchTimers() {
GameMode mode = engine.getGameMode();
Timer whiteTimer = engine.getWhiteTimer();
Timer blackTimer = engine.getBlackTimer();
// Wenn KEIN Modus (also kein Timer): NICHTS machen!
if (mode == null || whiteTimer == null || blackTimer == null) return;
if (engine.getCurrentPlayer().equals("WHITE")) {
if (mode.incrementSeconds > 0) {
blackTimer.addSeconds(mode.incrementSeconds);
}
blackTimer.stop();
whiteTimer.start();
} else {
if (mode.incrementSeconds > 0) {
whiteTimer.addSeconds(mode.incrementSeconds);
}
whiteTimer.stop();
blackTimer.start();
}
}
// Hilfsmethode, um von Koordinaten (row/col) auf z.B. "E2" zu kommen
private String coordToChessNotation(int modelRow, int modelCol) {
char file = (char)('A' + modelCol);
int rank = 8 - modelRow;
return "" + file + rank;
}
// Timeout-Methode
private void onTimeout(String color) {
if (gameOver) return; // Doppelt hält besser
gameOver = true;
String winner = color.equals("WHITE") ? "SCHWARZ" : "WEIß";
gui.displayMessage(winner + " hat durch Zeit gewonnen!");
engine.getWhiteTimer().stop();
engine.getBlackTimer().stop();
askForRestart();
}
private void askForRestart() {
int answer = JOptionPane.showConfirmDialog(
null,
"Neue Partie starten?",
"Spiel beendet",
JOptionPane.YES_NO_OPTION
);
javax.swing.SwingUtilities.getWindowAncestor(gui.getField(0, 0)).dispose();
if (answer == JOptionPane.YES_OPTION) {
engine.clearQuicksave();
MainController.engineRAM = null;
callback.onNewGameRequested();
} else {
// HIER: QuickSave **NUR** falls das Spiel NICHT durch Aufgabe/Remis/Patt beendet wurde!
if (!gameWasResignedOrDrawn) {
engine.quicksave();
MainController.engineRAM = engine;
} else {
engine.clearQuicksave();
MainController.engineRAM = null;
}
callback.onReturnToMenu();
}
gameWasResignedOrDrawn = false; // Reset für nächstes Spiel
}
private void resetFieldBackground(int row, int col) {
Color LIGHT = new Color(0xe0e1dd);
Color DARK = new Color(0x778da9);

View File

@ -1,6 +0,0 @@
package de.hs_mannheim.informatik.chess.controller;
public interface GameEndCallback {
void onNewGameRequested();
void onReturnToMenu();
}

View File

@ -5,7 +5,6 @@ import de.hs_mannheim.informatik.chess.view.PgnGui;
import de.hs_mannheim.informatik.chess.view.PgnSelectionGui;
import de.hs_mannheim.informatik.chess.view.CreativeGui;
import de.hs_mannheim.informatik.chess.view.GameGui;
import de.hs_mannheim.informatik.chess.view.GameModeSelector;
import java.io.IOException;
import java.util.List;
@ -16,11 +15,9 @@ import javax.swing.JOptionPane;
import com.github.bhlangonijr.chesslib.game.Game;
import de.hs_mannheim.informatik.chess.model.ChessEngine;
import de.hs_mannheim.informatik.chess.model.GameMode;
public class MainController {
private MainGui mainGui;
static ChessEngine engineRAM = null;
public MainController() {
mainGui = new MainGui();
@ -31,54 +28,10 @@ public class MainController {
}
private void startNormalMode() {
// Prüfe, ob es im RAM ein Quicksave gibt:
if (engineRAM != null && engineRAM.quickload()) {
int choice = JOptionPane.showConfirmDialog(
null,
"Letzte Partie fortsetzen?",
"Quicksave gefunden",
JOptionPane.YES_NO_OPTION
);
if (choice == JOptionPane.YES_OPTION) {
GameGui gameGui = new GameGui();
GameEndCallback callback = new GameEndCallback() {
public void onNewGameRequested() { startNormalMode(); }
public void onReturnToMenu() { new MainController(); }
};
new GameController(gameGui, engineRAM, callback); // KEIN initTimers, KEIN neuer Engine!
// --- Timerlabels aktualisieren
gameGui.updateWhiteTimerLabel(engineRAM.getWhiteTimer().getSecondsLeft());
gameGui.updateBlackTimerLabel(engineRAM.getBlackTimer().getSecondsLeft());
// --- Timer des aktuellen Spielers starten
if (engineRAM.getCurrentPlayer().equals("WHITE")) {
engineRAM.getWhiteTimer().start();
} else {
engineRAM.getBlackTimer().start();
}
mainGui.close();
return; // Fertig!
} else {
engineRAM.clearQuicksave();
engineRAM = null;
}
}
// Neues Spiel normal starten:
GameMode mode = GameModeSelector.selectGameMode();
if (mode == null) return;
mainGui.close();
ChessEngine engine = new ChessEngine(mode);
engineRAM = engine; // Für spätere Quicksaves merken!
GameGui gameGui = new GameGui();
GameEndCallback callback = new GameEndCallback() {
public void onNewGameRequested() {
startNormalMode();
}
public void onReturnToMenu() {
new MainController();
}
};
new GameController(gameGui, engine, callback, mode);
ChessEngine engine = new ChessEngine();
new GameController(gameGui, engine);
}
private void startCreativeMode() {
@ -86,27 +39,8 @@ public class MainController {
CreativeGui creativegui = new CreativeGui();
ChessEngine engine = new ChessEngine();
new CreativeController(creativegui, engine);
creativegui.setStartGameCallback(fen -> {
// 1. Modus-Auswahl-Dialog zeigen!
GameMode mode = GameModeSelector.selectGameMode(); // (Dialog, wie beim Normal Mode)
if (mode == null) return; // User hat abgebrochen → nichts machen
ChessEngine newEngine = new ChessEngine(mode); // Engine mit Modus (Timer)
newEngine.setPositionFromFEN(fen);
GameGui gameGui = new GameGui();
GameEndCallback callback = new GameEndCallback() {
public void onNewGameRequested() { startCreativeMode(); }
public void onReturnToMenu() { new MainController(); }
};
new GameController(gameGui, newEngine, callback, mode); // mit Timer/ohne je nach Modus
creativegui.close();
});
}
private void startLoadGameMode() {
JFileChooser chooser = new JFileChooser();
int result = chooser.showOpenDialog(null);
@ -126,6 +60,5 @@ public class MainController {
JOptionPane.showMessageDialog(null, "Fehler beim Laden der PGN-Datei:\n" + ex.getMessage());
}
}
mainGui.close();
}
}

View File

@ -65,8 +65,7 @@ public class PgnController {
public void updateGuiBoard() {
BoardDTO board = engine.getBoardAsDTO();
gui.updateBoard(board);
gui.updateMoveList(engine.getMoveListStringsGrouped());
gui.setOpeningLabel(engine.getOpeningName());
gui.updateMoveList(engine.getMoveListStringsGrouped());
}
private void resetFieldBackground(int row, int col) {

View File

@ -1,10 +1,8 @@
package de.hs_mannheim.informatik.chess.model;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.ConsoleHandler;
@ -20,505 +18,365 @@ import com.github.bhlangonijr.chesslib.move.Move;
import com.github.bhlangonijr.chesslib.pgn.PgnHolder;
import com.github.bhlangonijr.chesslib.game.*;
import com.github.bhlangonijr.chesslib.move.MoveList;
import java.time.LocalDate;
import com.github.bhlangonijr.chesslib.Side;
public class ChessEngine {
private Board board;
private List<Move> moves = new ArrayList<>();
private String initialFen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
private static final Logger logger = Logger.getLogger(ChessEngine.class.getName());
private int quicksaveWhiteTimeLeft = -1;
private int quicksaveBlackTimeLeft = -1;
private int currentMoveIndex = 0;
private Timer whiteTimer;
private Timer blackTimer;
private final GameMode mode;
private String quicksaveFen = null;
private List<Move> quicksaveMoves = null;
private int quicksaveMoveIndex = 0;
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());
Move libMove = new Move(Square.valueOf(from), Square.valueOf(to));
if (board.legalMoves().contains(libMove)) {
board.doMove(libMove);
public ChessEngine() {
this.mode = null;
logging();
board = new Board();
}
// Replay? Dann abschneiden
if (currentMoveIndex < moves.size()) {
logger.info("Replay-Modus: Züge nach " + currentMoveIndex + " werden entfernt.");
moves = new ArrayList<>(moves.subList(0, currentMoveIndex));
}
moves.add(libMove);
currentMoveIndex++;
logger.info("Zug erfolgreich durchgeführt: " + libMove);
public ChessEngine(GameMode mode) {
this.mode = mode;
whiteTimer = new Timer(mode.minutes, mode.seconds);
blackTimer = new Timer(mode.minutes, mode.seconds);
logging();
board = new Board();
}
// Opening-Erkennung nach jedem erfolgreichen Zug
String playedMovesUci = movesToUciString(moves);
Opening detectedOpening = Opening.detect(playedMovesUci);
public boolean move(MoveDTO move) {
String from = "" + (char) ('A' + move.getFromCol()) + (8 - move.getFromRow());
String to = "" + (char) ('A' + move.getToCol()) + (8 - move.getToRow());
Move libMove = new Move(Square.valueOf(from), Square.valueOf(to));
if (board.legalMoves().contains(libMove)) {
board.doMove(libMove);
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;
}
if (currentMoveIndex < moves.size()) {
if (logger.isLoggable(Level.INFO)) {
logger.info("Replay-Modus: Züge nach " + currentMoveIndex + " werden entfernt.");
}
moves = new ArrayList<>(moves.subList(0, currentMoveIndex));
}
moves.add(libMove);
currentMoveIndex++;
if (logger.isLoggable(Level.INFO)) {
logger.info("Zug erfolgreich durchgeführt: " + libMove);
}
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<>();
try {
Square fromSq = Square.valueOf(from.toUpperCase());
for (Move move : board.legalMoves()) {
if (move.getFrom().equals(fromSq)) {
int fromRow = 8 - fromSq.getRank().ordinal() - 1;
int fromCol = fromSq.getFile().ordinal();
int toRow = 8 - move.getTo().getRank().ordinal() - 1;
int toCol = move.getTo().getFile().ordinal();
destinations.add(new MoveDTO(fromRow, fromCol, toRow, toCol));
}
}
logger.info("Es wurden " + destinations.size() + " Ziele gefunden.");
} catch (Exception e) {
logger.severe("Fehler beim Holen der legalen Ziele: " + e.getMessage());
}
return destinations;
}
public List<String> getMoveListStringsGrouped() {
logger.info("Gruppiere Züge für Anzeige.");
List<String> result = new ArrayList<>();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < moves.size(); i++) {
if (i % 2 == 0) sb.append((i/2 + 1) + ". ");
sb.append(moves.get(i).toString()).append(" ");
if (i % 2 == 1 || i == moves.size() - 1) {
result.add(sb.toString().trim());
sb = new StringBuilder();
}
}
return result;
}
public PieceDTO getPieceAt(String square) {
logger.info("Hole Figur an Feld: " + square);
Piece piece = board.getPiece(Square.valueOf(square.toUpperCase()));
return convertPieceToDTO(piece);
}
public boolean moveWithPromotion(MoveDTO move, String promotionPiece) {
String from = "" + (char)('A' + move.getFromCol()) + (8 - move.getFromRow());
String to = "" + (char)('A' + move.getToCol()) + (8 - move.getToRow());
String playedMovesUci = movesToUciString(moves);
detectedOpening = Opening.detect(playedMovesUci);
// Die Farbe bestimmen!
boolean isWhite = (8 - move.getFromRow()) < (8 - move.getToRow());
Piece promotion;
switch (promotionPiece) {
case "ROOK": promotion = isWhite ? Piece.WHITE_ROOK : Piece.BLACK_ROOK; break;
case "KNIGHT": promotion = isWhite ? Piece.WHITE_KNIGHT : Piece.BLACK_KNIGHT; break;
case "BISHOP": promotion = isWhite ? Piece.WHITE_BISHOP : Piece.BLACK_BISHOP; break;
default: promotion = isWhite ? Piece.WHITE_QUEEN : Piece.BLACK_QUEEN;
}
if (detectedOpening != null && logger.isLoggable(Level.INFO)) {
logger.info("Aktuelles Opening erkannt: " + detectedOpening.getEco() + " - " + detectedOpening.getName());
}
return true;
}
if (logger.isLoggable(Level.WARNING)) {
logger.warning("Ungültiger Zug: " + libMove);
}
return false;
}
Move libMove = new Move(Square.valueOf(from), Square.valueOf(to), promotion);
public String getOpeningName() {
if (detectedOpening != null) {
return detectedOpening.getEco() + " - " + detectedOpening.getName();
} else {
return "unbekannt";
}
}
if (board.legalMoves().contains(libMove)) {
board.doMove(libMove);
private String movesToUciString(List<Move> moves) {
StringBuilder sb = new StringBuilder();
for (Move m : moves) {
sb.append(m.toString()).append(" ");
}
return sb.toString().trim();
}
if (currentMoveIndex < moves.size()) {
moves = new ArrayList<>(moves.subList(0, currentMoveIndex));
}
moves.add(libMove);
currentMoveIndex++;
logger.info("Promotionszug durchgeführt: " + libMove);
return true;
}
logger.warning("Ungültiger Promotionszug: " + libMove);
return false;
}
public BoardDTO getBoardAsDTO() {
logger.info("Erstelle DTO-Abbild des Boards");
PieceDTO[][] dtoBoard = new PieceDTO[8][8];
for (int rank = 8; rank >= 1; rank--) {
for (int file = 0; file < 8; file++) {
Square square = Square.valueOf("" + (char)('A' + file) + rank);
Piece piece = board.getPiece(square);
dtoBoard[8-rank][file] = convertPieceToDTO(piece);
}
}
return new BoardDTO(dtoBoard);
}
private String pieceToUnicode(Piece piece) {
switch (piece) {
case WHITE_KING: return "♔";
case WHITE_QUEEN: return "♕";
case WHITE_ROOK: return "♖";
case WHITE_BISHOP: return "♗";
case WHITE_KNIGHT: return "♘";
case WHITE_PAWN: return "♙";
case BLACK_KING: return "♚";
case BLACK_QUEEN: return "♛";
case BLACK_ROOK: return "♜";
case BLACK_BISHOP: return "♝";
case BLACK_KNIGHT: return "♞";
case BLACK_PAWN: return "♟";
default: return " ";
}
}
public void setPositionToMoveIndex(int idx) {
// Neues Board erzeugen
logger.info("Setze Board auf Zug-Index: " + idx);
board = new Board();
for (int i = 0; i < idx; i++) {
board.doMove(moves.get(i));
}
currentMoveIndex = idx;
}
public int getCurrentMoveIndex() {
logger.info("Hole aktuellen Zug-Index: " + currentMoveIndex);
return currentMoveIndex;
}
public int getMoveListSize() {
logger.info("Hole Anzahl gespielter Züge: " + moves.size());
return moves.size();
}
private PieceDTO convertPieceToDTO(Piece piece) {
if (piece == null || piece.equals(Piece.NONE)) return null;
String color = piece.name().startsWith("WHITE") ? "WHITE" : "BLACK";
String type = piece.name().substring(piece.name().indexOf('_') + 1); // "PAWN", "KING"...
String symbol = pieceToUnicode(piece);
return new PieceDTO(type, color, symbol);
}
public void setPositionFromFEN(String fen) {
board.loadFromFen(fen);
}
public List<MoveDTO> getLegalDestinations(String from) {
if (logger.isLoggable(Level.INFO)) {
logger.info("Hole legale Züge von: " + from);
}
List<MoveDTO> destinations = new ArrayList<>();
try {
Square fromSq = Square.valueOf(from.toUpperCase(java.util.Locale.ROOT));
for (Move move : board.legalMoves()) {
if (move.getFrom().equals(fromSq)) {
int fromRow = 8 - fromSq.getRank().ordinal() - 1;
int fromCol = fromSq.getFile().ordinal();
int toRow = 8 - move.getTo().getRank().ordinal() - 1;
int toCol = move.getTo().getFile().ordinal();
destinations.add(new MoveDTO(fromRow, fromCol, toRow, toCol));
}
}
if (logger.isLoggable(Level.INFO)) {
logger.info("Es wurden " + destinations.size() + " Ziele gefunden.");
}
} catch (Exception e) {
if (logger.isLoggable(Level.SEVERE)) {
logger.severe("Fehler beim Holen der legalen Ziele: " + e.getMessage());
}
}
return destinations;
}
public boolean isMated() {
boolean mated = board.isMated();
logger.info("isMated() = " + mated);
return mated;
}
public boolean isStalemate() {
boolean stale = board.isStaleMate();
logger.info("isStalemate() = " + stale);
return stale;
}
public boolean isDraw() {
boolean draw = board.isDraw();
logger.info("isDraw() = " + draw);
return draw;
}
public String getCurrentPlayer() {
String player = board.getSideToMove().toString();
logger.info("Am Zug: " + player);
return player;
}
public void logging() {
// Eigener Handler nur für diese Klasse
ConsoleHandler handler = new ConsoleHandler();
handler.setLevel(Level.ALL);
handler.setFormatter(new SimpleFormatter() {
@Override
public synchronized String format(LogRecord lr) {
return String.format("[%s] %s%n%n", lr.getLevel().getLocalizedName(), lr.getMessage());
}
});
logger.setUseParentHandlers(false);
logger.addHandler(handler);
logger.info("ChessEngine wurde initialisiert.");
}
public List<Game> loadGamesFromPgn(String path) throws IOException {
public List<String> getMoveListStringsGrouped() {
if (logger.isLoggable(Level.INFO)) {
logger.info("Gruppiere Züge für Anzeige.");
}
List<String> result = new ArrayList<>();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < moves.size(); i++) {
if (i % 2 == 0) {
sb.append((i / 2 + 1)).append(". ");
}
sb.append(moves.get(i).toString()).append(" ");
if (i % 2 == 1 || i == moves.size() - 1) {
result.add(sb.toString().trim());
sb = new StringBuilder();
}
}
return result;
}
public void quicksave() {
this.quicksaveFen = board.getFen();
this.quicksaveMoves = new ArrayList<>(moves);
this.quicksaveMoveIndex = currentMoveIndex;
if (whiteTimer != null) {
quicksaveWhiteTimeLeft = whiteTimer.getSecondsLeft();
}
if (blackTimer != null) {
quicksaveBlackTimeLeft = blackTimer.getSecondsLeft();
}
}
public boolean quickload() {
if (quicksaveFen == null) {
return false;
}
board = new Board();
board.loadFromFen(quicksaveFen);
moves = new ArrayList<>(quicksaveMoves);
currentMoveIndex = quicksaveMoveIndex;
if (whiteTimer != null && quicksaveWhiteTimeLeft != -1) {
whiteTimer.setSecondsLeft(quicksaveWhiteTimeLeft);
}
if (blackTimer != null && quicksaveBlackTimeLeft != -1) {
blackTimer.setSecondsLeft(quicksaveBlackTimeLeft);
}
return true;
}
public void clearQuicksave() {
quicksaveFen = null;
quicksaveMoves = null;
quicksaveMoveIndex = 0;
}
public PieceDTO getPieceAt(String square) {
if (logger.isLoggable(Level.INFO)) {
logger.info("Hole Figur an Feld: " + square);
}
Piece piece = board.getPiece(Square.valueOf(square.toUpperCase(java.util.Locale.ROOT)));
return convertPieceToDTO(piece);
}
public boolean moveWithPromotion(MoveDTO move, String promotionPiece) {
String from = "" + (char) ('A' + move.getFromCol()) + (8 - move.getFromRow());
String to = "" + (char) ('A' + move.getToCol()) + (8 - move.getToRow());
boolean isWhite = (8 - move.getFromRow()) < (8 - move.getToRow());
Piece promotion;
switch (promotionPiece) {
case "ROOK":
promotion = isWhite ? Piece.WHITE_ROOK : Piece.BLACK_ROOK;
break;
case "KNIGHT":
promotion = isWhite ? Piece.WHITE_KNIGHT : Piece.BLACK_KNIGHT;
break;
case "BISHOP":
promotion = isWhite ? Piece.WHITE_BISHOP : Piece.BLACK_BISHOP;
break;
default:
promotion = isWhite ? Piece.WHITE_QUEEN : Piece.BLACK_QUEEN;
break;
}
Move libMove = new Move(Square.valueOf(from), Square.valueOf(to), promotion);
if (board.legalMoves().contains(libMove)) {
board.doMove(libMove);
if (currentMoveIndex < moves.size()) {
moves = new ArrayList<>(moves.subList(0, currentMoveIndex));
}
moves.add(libMove);
currentMoveIndex++;
if (logger.isLoggable(Level.INFO)) {
logger.info("Promotionszug durchgeführt: " + libMove);
}
return true;
}
if (logger.isLoggable(Level.WARNING)) {
logger.warning("Ungültiger Promotionszug: " + libMove);
}
return false;
}
public BoardDTO getBoardAsDTO() {
if (logger.isLoggable(Level.INFO)) {
logger.info("Erstelle DTO-Abbild des Boards");
}
PieceDTO[][] dtoBoard = new PieceDTO[8][8];
for (int rank = 8; rank >= 1; rank--) {
for (int file = 0; file < 8; file++) {
Square square = Square.valueOf("" + (char) ('A' + file) + rank);
Piece piece = board.getPiece(square);
dtoBoard[8 - rank][file] = convertPieceToDTO(piece);
}
}
return new BoardDTO(dtoBoard);
}
private String pieceToUnicode(Piece piece) {
switch (piece) {
case WHITE_KING:
return "♔";
case WHITE_QUEEN:
return "♕";
case WHITE_ROOK:
return "♖";
case WHITE_BISHOP:
return "♗";
case WHITE_KNIGHT:
return "♘";
case WHITE_PAWN:
return "♙";
case BLACK_KING:
return "♚";
case BLACK_QUEEN:
return "♛";
case BLACK_ROOK:
return "♜";
case BLACK_BISHOP:
return "♝";
case BLACK_KNIGHT:
return "♞";
case BLACK_PAWN:
return "♟";
default:
return " ";
}
}
public void setPositionToMoveIndex(int idx) {
if (logger.isLoggable(Level.INFO)) {
logger.info("Setze Board auf Zug-Index: " + idx);
}
board = new Board();
board.loadFromFen(initialFen);
for (int i = 0; i < idx; i++) {
board.doMove(moves.get(i));
}
currentMoveIndex = idx;
String playedMovesUci = movesToUciString(moves.subList(0, idx));
detectedOpening = Opening.detect(playedMovesUci);
}
public int getCurrentMoveIndex() {
if (logger.isLoggable(Level.INFO)) {
logger.info("Hole aktuellen Zug-Index: " + currentMoveIndex);
}
return currentMoveIndex;
}
public int getMoveListSize() {
if (logger.isLoggable(Level.INFO)) {
logger.info("Hole Anzahl gespielter Züge: " + moves.size());
}
return moves.size();
}
private PieceDTO convertPieceToDTO(Piece piece) {
if (piece == null || piece.equals(Piece.NONE)) {
return null;
}
String color = piece.name().startsWith("WHITE") ? "WHITE" : "BLACK";
String type = piece.name().substring(piece.name().indexOf('_') + 1);
String symbol = pieceToUnicode(piece);
return new PieceDTO(type, color, symbol);
}
public void setPositionFromFEN(String fen) {
board.loadFromFen(fen);
initialFen = fen;
}
public boolean isMated() {
boolean mated = board.isMated();
if (logger.isLoggable(Level.INFO)) {
logger.info("isMated() = " + mated);
}
return mated;
}
public boolean isStalemate() {
boolean stale = board.isStaleMate();
if (logger.isLoggable(Level.INFO)) {
logger.info("isStalemate() = " + stale);
}
return stale;
}
public boolean isDraw() {
boolean draw = board.isDraw();
if (logger.isLoggable(Level.INFO)) {
logger.info("isDraw() = " + draw);
}
return draw;
}
public String getCurrentPlayer() {
String player = board.getSideToMove().toString();
if (logger.isLoggable(Level.INFO)) {
logger.info("Am Zug: " + player);
}
return player;
}
public void logging() {
ConsoleHandler handler = new ConsoleHandler();
handler.setLevel(Level.ALL);
handler.setFormatter(new SimpleFormatter() {
@Override
public synchronized String format(LogRecord lr) {
return String.format("[%s] %s%n%n", lr.getLevel().getLocalizedName(), lr.getMessage());
}
});
logger.setUseParentHandlers(false);
logger.addHandler(handler);
if (logger.isLoggable(Level.INFO)) {
logger.info("ChessEngine wurde initialisiert.");
}
}
public List<Game> loadGamesFromPgn(String path) throws IOException {
PgnHolder pgnHolder = new PgnHolder(path);
try {
PgnHolder pgnHolder = new PgnHolder(path);
try {
pgnHolder.loadPgn();
} catch (Exception e) {
e.printStackTrace();
}
return pgnHolder.getGames();
}
}
List<Game> games = pgnHolder.getGames();
return games;
}
public void saveAsPgn(Game game, String path, String dateiname) {
// Sicher alle Strings holen (nie null)
String event = safe(game.getRound().getEvent().getName());
String site = safe(game.getRound().getEvent().getSite());
String round = "" + game.getRound().getNumber();
// Datum für PGN-Format (YYYY.MM.DD)
String date = safe(game.getRound().getEvent().getStartDate()).replace("-", ".");
String wName = safe(game.getWhitePlayer().getName());
String bName = safe(game.getBlackPlayer().getName());
String result = safe(game.getResult().getDescription());
public void initTimers(int min, int sec) {
if (whiteTimer == null) {
whiteTimer = new Timer(min, sec);
} else if (quicksaveWhiteTimeLeft != -1) {
whiteTimer = new Timer(min, sec);
whiteTimer.setSecondsLeft(quicksaveWhiteTimeLeft);
} else {
whiteTimer = new Timer(min, sec);
}
// PGN-Header zusammenbauen
StringBuilder header = new StringBuilder();
header.append("[Event \"" + event + "\"]\n");
header.append("[Site \"" + site + "\"]\n");
header.append("[Date \"" + date + "\"]\n");
header.append("[Round \"" + round + "\"]\n");
header.append("[White \"" + wName + "\"]\n");
header.append("[Black \"" + bName + "\"]\n");
header.append("[Result \"" + result + "\"]\n\n");
if (blackTimer == null) {
blackTimer = new Timer(min, sec);
} else if (quicksaveBlackTimeLeft != -1) {
blackTimer = new Timer(min, sec);
blackTimer.setSecondsLeft(quicksaveBlackTimeLeft);
} else {
blackTimer = new Timer(min, sec);
}
}
// Züge als SAN holen
StringBuilder moves = new StringBuilder();
String[] sanArray = game.getHalfMoves().toSanArray();
public void saveAsPgn(Game game, String path, String dateiname) {
String event = safe(game.getRound().getEvent().getName());
String site = safe(game.getRound().getEvent().getSite());
String round = "" + game.getRound().getNumber();
String date = safe(game.getRound().getEvent().getStartDate()).replace("-", ".");
String wName = safe(game.getWhitePlayer().getName());
String bName = safe(game.getBlackPlayer().getName());
String result = safe(game.getResult().getDescription());
for (int i = 0; i < sanArray.length; i++) {
if (i % 2 == 0) {
moves.append((i / 2 + 1)).append(". ");
}
moves.append(sanArray[i]).append(" ");
// Optional: Zeilenumbruch für Lesbarkeit
// if (i > 0 && i % 8 == 0) moves.append("\n");
}
moves.append(result); // Ergebnis am Ende!
StringBuilder header = new StringBuilder();
header.append("[Event \"" + event + "\"]\n");
header.append("[Site \"" + site + "\"]\n");
header.append("[Date \"" + date + "\"]\n");
header.append("[Round \"" + round + "\"]\n");
header.append("[White \"" + wName + "\"]\n");
header.append("[Black \"" + bName + "\"]\n");
header.append("[Result \"" + result + "\"]\n\n");
String file = header + moves.toString();
StringBuilder movesSb = new StringBuilder();
String[] sanArray = game.getHalfMoves().toSanArray();
// Datei schreiben
try {
Files.writeString(Path.of(path, dateiname), file, StandardCharsets.UTF_8);
} catch (IOException e) {
e.printStackTrace();
}
}
for (int i = 0; i < sanArray.length; i++) {
if (i % 2 == 0) {
movesSb.append((i / 2 + 1)).append(". ");
}
movesSb.append(sanArray[i]).append(" ");
}
movesSb.append(result);
// Hilfsfunktion für Null-Sicherheit
private String safe(String s) {
return s == null ? "?" : s;
}
String file = header + movesSb.toString();
public Game getCurrentGame() {
return getCurrentGame(this.board, this.moves, this.currentMoveIndex);
}
public Game getCurrentGame(Board board, java.util.List<Move> moves, int currentMoveIndex) {
// Event und Turnierdaten setzen
Event event = new Event();
event.setName("Generated Game");
event.setSite("Local");
event.setStartDate(LocalDate.now().toString()); // Format: yyyy-MM-dd
try {
Files.writeString(Path.of(path, dateiname), file, StandardCharsets.UTF_8);
} catch (IOException e) {
e.printStackTrace();
}
}
// Runde anlegen
Round round = new Round(event);
round.setNumber(1);
private String safe(String s) {
return s == null ? "?" : s;
}
// Spiel initialisieren
Game game = new Game("1", round); // "1" ist die Game-ID
public Game getCurrentGame() {
return getCurrentGame(this.board, this.moves, this.currentMoveIndex);
}
// Spieler setzen (deine MyPlayer-Klasse)
game.setWhitePlayer(new MyPlayer("White"));
game.setBlackPlayer(new MyPlayer("Black"));
public Game getCurrentGame(Board board, List<Move> moves, int currentMoveIndex) {
Event event = new Event();
event.setName("Generated Game");
event.setSite("Local");
event.setStartDate(LocalDate.now().toString());
// Ergebnis setzen
if (board.isMated()) {
game.setResult(board.getSideToMove() == Side.WHITE ? GameResult.BLACK_WON : GameResult.WHITE_WON);
} else if (board.isStaleMate() || board.isDraw()) {
game.setResult(GameResult.DRAW);
} else {
game.setResult(GameResult.ONGOING);
}
Round round = new Round(event);
round.setNumber(1);
// Züge übernehmen
MoveList moveList = new MoveList();
for (Move move : moves) {
moveList.add(move);
}
game.setHalfMoves(moveList);
Game game = new Game("1", round);
// Position auf aktuellen Zug setzen (letzter gespielter Halbzug)
if (currentMoveIndex > 0 && currentMoveIndex <= moveList.size()) {
game.setPosition(currentMoveIndex - 1);
} else {
game.setPosition(moveList.size() - 1);
}
game.setWhitePlayer(new MyPlayer("White"));
game.setBlackPlayer(new MyPlayer("Black"));
// FEN setzen: JETZT das aktuelle Board-FEN verwenden!
game.setBoard(new Board());
game.getBoard().loadFromFen(board.getFen());
if (board.isMated()) {
game.setResult(board.getSideToMove() == Side.WHITE ? GameResult.BLACK_WON : GameResult.WHITE_WON);
} else if (board.isStaleMate() || board.isDraw()) {
game.setResult(GameResult.DRAW);
} else {
game.setResult(GameResult.ONGOING);
}
return game;
}
MoveList moveList = new MoveList();
for (Move move : moves) {
moveList.add(move);
}
game.setHalfMoves(moveList);
if (currentMoveIndex > 0 && currentMoveIndex <= moveList.size()) {
game.setPosition(currentMoveIndex - 1);
} else {
game.setPosition(moveList.size() - 1);
}
public void loadMoves(List<Move> moveList) {
board = new Board(); // Neues leeres Brett
moves.clear();
currentMoveIndex = 0;
game.setBoard(new Board());
game.getBoard().loadFromFen(board.getFen());
for (Move move : moveList) {
board.doMove(move);
moves.add(move);
currentMoveIndex++;
}
return game;
}
public void undoLastMove() {
if (currentMoveIndex > 0 && !moves.isEmpty()) {
board.undoMove();
moves.remove(currentMoveIndex - 1);
currentMoveIndex--;
String playedMovesUci = movesToUciString(moves.subList(0, currentMoveIndex));
detectedOpening = Opening.detect(playedMovesUci);
}
}
public void loadMoves(List<Move> moveList) {
board = new Board();
moves.clear();
currentMoveIndex = 0;
for (Move move : moveList) {
board.doMove(move);
moves.add(move);
currentMoveIndex++;
}
}
public Timer getWhiteTimer() {
return whiteTimer;
}
public Timer getBlackTimer() {
return blackTimer;
}
public GameMode getGameMode() {
return mode;
}
}
}

View File

@ -1,26 +0,0 @@
package de.hs_mannheim.informatik.chess.model;
public enum GameMode {
CLASSIC(3, 0, 0),
RAPID(5, 0, 0),
BULLET(1, 0, 10); // 1 Minute + 10 Sek Inkrement
public final int minutes;
public final int seconds;
public final int incrementSeconds;
GameMode(int minutes, int seconds, int incrementSeconds) {
this.minutes = minutes;
this.seconds = seconds;
this.incrementSeconds = incrementSeconds;
}
@Override
public String toString() {
return switch (this) {
case CLASSIC -> "3 Minuten (klassisch)";
case RAPID -> "5 Minuten (rapid)";
case BULLET -> "1 Minute + 10 Sek Inkrement";
};
}
}

View File

@ -1,68 +0,0 @@
package de.hs_mannheim.informatik.chess.model;
import java.util.function.Consumer;
public class Timer {
private int secondsLeft;
private javax.swing.Timer swingTimer;
private Runnable onTimeout;
private Consumer<Integer> onTick;
public Timer(int minutes, int seconds) {
this.secondsLeft = minutes * 60 + seconds;
}
public void setOnTimeout(Runnable onTimeout) {
this.onTimeout = onTimeout;
}
public void setOnTick(Consumer<Integer> onTick) {
this.onTick = onTick;
}
public void start() {
if (swingTimer != null && swingTimer.isRunning()) {
swingTimer.stop();
}
swingTimer = new javax.swing.Timer(1000, e -> {
secondsLeft--;
if (onTick != null) {
onTick.accept(secondsLeft);
}
if (secondsLeft <= 0) {
stop();
if (onTimeout != null) {
onTimeout.run();
}
}
});
swingTimer.start();
}
public void stop() {
if (swingTimer != null) {
swingTimer.stop();
}
}
public void reset(int minutes, int seconds) {
stop();
this.secondsLeft = minutes * 60 + seconds;
if (onTick != null) {
onTick.accept(secondsLeft);
}
}
public int getSecondsLeft() {
return secondsLeft;
}
public void setSecondsLeft(int secondsLeft) {
this.secondsLeft = secondsLeft;
}
public void addSeconds(int seconds) {
this.secondsLeft += seconds;
}
}

View File

@ -5,11 +5,6 @@ import java.awt.*;
import java.util.HashMap;
public class CreativeGui {
public interface StartGameCallback {
void onStartGame(String fen);
}
private boolean isFlipped = false;
private JFrame frame;
@ -18,12 +13,6 @@ public class CreativeGui {
private JTextField fenField;
private JButton updateBtn;
private JButton flipBoardButton;
private boolean closedByUser = true;
private StartGameCallback startGameCallback;
private JButton startGameButton;
public static final HashMap<String, String> UNICODE_MAP = new HashMap<String, String>() {{
put("BLACK_KING", "\u265A"); put("BLACK_QUEEN", "\u265B");
@ -41,8 +30,7 @@ public class CreativeGui {
public CreativeGui() {
frame = new JFrame("Creative Mode");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
frame.setUndecorated(false);
frame.setSize(1600, 1200);
frame.setLocationRelativeTo(null);
JPanel mainPanel = new JPanel(new GridBagLayout());
@ -52,7 +40,7 @@ public class CreativeGui {
// LINKS: chessPanel (Board+Toolbars)
gbc.gridx = 0;
gbc.gridy = 0;
gbc.weightx = 0.7;
gbc.weightx = 0.6;
gbc.weighty = 1.0;
gbc.insets = new Insets(5, 5, 5, 0);
gbc.fill = GridBagConstraints.BOTH;
@ -61,21 +49,12 @@ public class CreativeGui {
// RECHTS: FEN & Optionen
gbc.gridx = 1;
gbc.gridy = 0;
gbc.weightx = 0.3;
gbc.weightx = 0.4;
gbc.weighty = 1.0;
gbc.insets = new Insets(5, 0, 5, 5);
gbc.fill = GridBagConstraints.BOTH;
mainPanel.add(fenPanel(), gbc);
frame.addWindowListener(new java.awt.event.WindowAdapter() {
@Override
public void windowClosed(java.awt.event.WindowEvent e) {
if (closedByUser) {
new de.hs_mannheim.informatik.chess.controller.MainController();
}
}
});
frame.setContentPane(mainPanel);
frame.setVisible(true);
}
@ -92,7 +71,7 @@ public class CreativeGui {
btn.setFocusPainted(false);
btn.setPreferredSize(new Dimension(70, 70));
btn.setBackground(white ? LIGHT : DARK);
btn.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
btn.setBorder(BorderFactory.createEmptyBorder(20, 0, 20, 0));
String key = prefix + type;
btn.addActionListener(e -> selectedPiece = key);
panel.add(btn);
@ -125,76 +104,47 @@ public class CreativeGui {
}
private JPanel chessPanel() {
JPanel chessPanel = new JPanel(new BorderLayout());
JPanel chessPanel = new JPanel(new GridBagLayout());
chessPanel.setBackground(new Color(0x1b263b));
GridBagConstraints gbc = new GridBagConstraints();
// Board UND Toolbars in EINEM Panel, damit sie linksbündig mit dem Brett starten!
JPanel boardAndToolbars = new JPanel(new BorderLayout());
boardAndToolbars.setOpaque(false);
// Toolbar oben
gbc.gridx = 0;
gbc.gridy = 0;
gbc.fill = GridBagConstraints.HORIZONTAL;
chessPanel.add(toolbarPanel(false), gbc);
// Toolbar Schwarz (oben)
JPanel blackToolbar = toolbarPanel(false);
boardAndToolbars.add(blackToolbar, BorderLayout.NORTH);
// Board
gbc.gridx = 0;
gbc.gridy = 1;
gbc.fill = GridBagConstraints.BOTH;
chessPanel.add(boardPanel(), gbc);
// Board (zentriert im Panel)
JPanel board = boardPanel();
boardAndToolbars.add(board, BorderLayout.CENTER);
// Toolbar unten
gbc.gridx = 0;
gbc.gridy = 2;
gbc.fill = GridBagConstraints.HORIZONTAL;
chessPanel.add(toolbarPanel(true), gbc);
// Toolbar Weiß (unten)
JPanel whiteToolbar = toolbarPanel(true);
boardAndToolbars.add(whiteToolbar, BorderLayout.SOUTH);
// Board+Toolbars mittig in einem Panel mit FlowLayout, damit sie zentriert sind
JPanel centerPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 0, 0));
centerPanel.setOpaque(false);
centerPanel.add(boardAndToolbars);
// Drehknopf
flipBoardButton = new JButton("⇵");
flipBoardButton.setPreferredSize(new Dimension(70, 70));
flipBoardButton.setFont(new Font("SansSerif", Font.BOLD, 40));
flipBoardButton.setBackground(new Color(0x5500ff));
flipBoardButton.setForeground(Color.WHITE);
flipBoardButton.setFocusPainted(false);
blackToolbar.setPreferredSize(new Dimension(0, 70)); // 70 px hoch
whiteToolbar.setPreferredSize(new Dimension(0, 70));
// Dynamisch skalieren wie gehabt
centerPanel.addComponentListener(new java.awt.event.ComponentAdapter() {
public void componentResized(java.awt.event.ComponentEvent evt) {
int totalHeight = centerPanel.getHeight();
int totalWidth = centerPanel.getWidth();
int toolbarHeight = blackToolbar.getPreferredSize().height + whiteToolbar.getPreferredSize().height;
// Falls Toolbars keine PrefSize haben, nimm getHeight()
if (toolbarHeight == 0) toolbarHeight = blackToolbar.getHeight() + whiteToolbar.getHeight();
int boardMaxHeight = totalHeight - toolbarHeight;
int size = Math.min(totalWidth, boardMaxHeight);
board.setPreferredSize(new Dimension(size, size));
board.revalidate();
}
});
chessPanel.add(centerPanel, BorderLayout.CENTER);
// Drehknopf rechts, schön mittig
JPanel eastPanel = new JPanel();
eastPanel.setOpaque(false);
eastPanel.setLayout(new BoxLayout(eastPanel, BoxLayout.Y_AXIS));
eastPanel.add(Box.createVerticalGlue());
eastPanel.add(flipBoardButton = createFlipButton());
eastPanel.add(Box.createVerticalGlue());
chessPanel.add(eastPanel, BorderLayout.EAST);
// Buffer links, wenn du willst
chessPanel.add(Box.createRigidArea(new Dimension(40, 0)), BorderLayout.WEST);
GridBagConstraints btn = new GridBagConstraints();
btn.gridx = 0;
btn.gridy = 2;
btn.weightx = 0.0;
btn.weighty = 0.0;
btn.anchor = GridBagConstraints.EAST;
btn.insets = new Insets(5, 0, 0, 0);
chessPanel.add(flipBoardButton, btn);
return chessPanel;
}
// Flip-Knopf Builder, damit dus an mehreren Stellen nutzen kannst:
private JButton createFlipButton() {
JButton btn = new JButton("⇵");
btn.setPreferredSize(new Dimension(70, 70));
btn.setFont(new Font("SansSerif", Font.BOLD, 40));
btn.setBackground(new Color(0x5500ff));
btn.setForeground(Color.WHITE);
btn.setFocusPainted(false);
return btn;
}
private JPanel fenPanel() {
JPanel panel = new JPanel();
@ -209,21 +159,7 @@ public class CreativeGui {
updateBtn = new JButton("Update Board");
updateBtn.setAlignmentX(Component.CENTER_ALIGNMENT);
panel.add(updateBtn);
startGameButton = new JButton("🟢 Partie starten");
startGameButton.setAlignmentX(Component.CENTER_ALIGNMENT);
startGameButton.setBackground(new Color(0x218838));
startGameButton.setForeground(Color.WHITE);
panel.add(startGameButton);
startGameButton.addActionListener(e -> {
if (startGameCallback != null) {
setClosedByUser(false);
startGameCallback.onStartGame(getFenText());
}
});
return panel;
}
// Für Controller
@ -234,21 +170,8 @@ public class CreativeGui {
public JButton getUpdateButton() { return updateBtn; }
public void setSelectedPiece(String piece) { selectedPiece = piece; }
public String getSelectedPiece() { return selectedPiece; }
public void setClosedByUser(boolean b) {
this.closedByUser = b;
}
public JButton getStartGameButton() { return startGameButton; }
public void setStartGameCallback(StartGameCallback callback) {
this.startGameCallback = callback;
}
public boolean isFlipped() { return isFlipped; }
public void setFlipped(boolean f) { isFlipped = f; }
public JButton getFlipBoardButton() { return flipBoardButton; }
public void close() {
frame.dispose();
}
}

View File

@ -7,12 +7,9 @@ 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;
@ -26,25 +23,16 @@ import de.hs_mannheim.informatik.chess.model.BoardDTO;
import de.hs_mannheim.informatik.chess.model.PieceDTO;
public class GameGui {
JFrame frame;
private JLabel[][] fields = new JLabel[8][8];
private JButton flipBoardButton;
private boolean isFlipped = false;
JButton btnSave = new JButton("💾");
private JLabel whiteTimerLabel;
private JLabel blackTimerLabel;
private JLabel openingLabel;
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 undoButton;
JButton btnFirst = new JButton("|<");
JButton btnPrev = new JButton("<");
JButton btnNext = new JButton(">");
JButton btnLast = new JButton(">|");
JButton btnSave = new JButton("SavePgn");
Color LIGHT = new Color(0xe0e1dd);
Color DARK = new Color(0x778da9);
@ -59,14 +47,12 @@ public class GameGui {
public JFrame mainFrame() {
frame = new JFrame();
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
frame.setUndecorated(false);
JFrame frame = new JFrame();
frame.setSize(1600, 1000);
frame.setLocationRelativeTo(null);
frame.add(mainPanel());
frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
frame.setDefaultCloseOperation(2);
frame.setVisible(true);
return frame;
}
@ -138,90 +124,43 @@ public class GameGui {
return boardPanel;
}
public JPanel chessPanel(JPanel boardPanel) {
JPanel chessPanel = new JPanel(new BorderLayout());
chessPanel.setBackground(new Color(0x1b263b));
public JPanel chessPanel(JPanel panel) {
JPanel chessPanel = new JPanel(new GridBagLayout());
GridBagConstraints board = new GridBagConstraints();
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
flipBoardButton = new JButton("⇵");
flipBoardButton.setPreferredSize(new Dimension(70, 70));
flipBoardButton.setFont(new Font("SansSerif", Font.BOLD, 40));
flipBoardButton.setBackground(new Color(0x5500ff));
flipBoardButton.setForeground(Color.WHITE);
flipBoardButton.setFocusPainted(false);
// --- 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);
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);
// --- 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));
flipBoardButton.setBackground(new Color(0x5500ff));
flipBoardButton.setForeground(Color.WHITE);
flipBoardButton.setFocusPainted(false);
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);
buttonRow.add(undoButton);
buttonRow.add(resignButton);
buttonRow.add(drawButton);
buttonRow.add(flipBoardButton);
chessPanel.add(buttonRow, BorderLayout.SOUTH);
return chessPanel;
chessPanel.add(flipBoardButton, btn);
return chessPanel;
}
public JPanel statsPanel() {
JPanel statsPanel = new JPanel(new BorderLayout());
statsPanel.setBackground(new Color(0x0d1b2a));
// Panel für die Timer (NORD)
statsPanel.add(timerPanel(), BorderLayout.NORTH);
// Move-Liste
moveListPanel = new JPanel();
moveListPanel.setLayout(new BoxLayout(moveListPanel, BoxLayout.Y_AXIS));
@ -230,49 +169,31 @@ public class GameGui {
moveListScroll.setPreferredSize(new Dimension(250, 800));
statsPanel.add(moveListScroll, BorderLayout.CENTER);
// Button-Leiste (SÜD)
// Button-Leiste
JPanel buttonPanel = new JPanel();
buttonPanel.setBackground(new Color(0x0d1b2a));
buttonPanel.setLayout(new GridLayout(1, 5, 10, 0)); // Jetzt 5 statt 4 Spalten!
// Grid oder Flow
buttonPanel.setLayout(new GridLayout(1, 4, 10, 0));
// Style (optional)
btnFirst.setBackground(new Color(0x212529)); btnFirst.setForeground(Color.WHITE);
btnPrev.setBackground(new Color(0x212529)); btnPrev.setForeground(Color.WHITE);
btnNext.setBackground(new Color(0x212529)); btnNext.setForeground(Color.WHITE);
btnLast.setBackground(new Color(0x212529)); btnLast.setForeground(Color.WHITE);
btnSave.setBackground(new Color(0x218838)); btnSave.setForeground(Color.WHITE);
btnLast.setBackground(new Color(0x212529)); btnSave.setForeground(Color.WHITE);
// Hinzufügen
buttonPanel.add(btnFirst);
buttonPanel.add(btnPrev);
buttonPanel.add(btnNext);
buttonPanel.add(btnLast);
buttonPanel.add(btnSave);
// Unten ins BorderLayout
statsPanel.add(buttonPanel, BorderLayout.SOUTH);
return statsPanel;
}
private JPanel timerPanel() {
JPanel panel = new JPanel(new GridLayout(2, 1));
panel.setBackground(new Color(0x0d1b2a));
whiteTimerLabel = new JLabel("Weiß: --:--", SwingConstants.CENTER);
blackTimerLabel = new JLabel("Schwarz: --:--", SwingConstants.CENTER);
whiteTimerLabel.setFont(new Font("SansSerif", Font.BOLD, 24));
whiteTimerLabel.setForeground(Color.WHITE);
whiteTimerLabel.setBackground(new Color(0x1b263b));
whiteTimerLabel.setOpaque(true);
blackTimerLabel.setFont(new Font("SansSerif", Font.BOLD, 24));
blackTimerLabel.setForeground(Color.WHITE);
blackTimerLabel.setBackground(new Color(0x1b263b));
blackTimerLabel.setOpaque(true);
panel.add(whiteTimerLabel);
panel.add(blackTimerLabel);
return panel;
}
public String showPromotionDialog(String color) {
String[] choices = {"Dame", "Turm", "Springer", "Läufer"};
@ -325,9 +246,7 @@ public class GameGui {
public JButton getBtnPrev() { return btnPrev; }
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 JButton getBtnSave() { return btnSave; }
public void updateBoard(BoardDTO boardDTO) {
PieceDTO[][] board = boardDTO.getBoard();
@ -349,38 +268,9 @@ public class GameGui {
}
}
public void updateWhiteTimerLabel(int secondsLeft) {
whiteTimerLabel.setText("Weiß: " + formatTime(secondsLeft));
}
public void updateBlackTimerLabel(int secondsLeft) {
blackTimerLabel.setText("Schwarz: " + formatTime(secondsLeft));
}
private String formatTime(int seconds) {
int min = seconds / 60;
int sec = seconds % 60;
return String.format("%02d:%02d", min, sec);
}
// Optional: Getter, falls du direkt ran willst (braucht man aber fast nie)
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);
}
public JFrame getFrame() {
return frame;
}
}

View File

@ -1,23 +0,0 @@
package de.hs_mannheim.informatik.chess.view;
import javax.swing.*;
import de.hs_mannheim.informatik.chess.model.GameMode;
public class GameModeSelector {
public static GameMode selectGameMode() {
GameMode[] options = GameMode.values();
GameMode selected = (GameMode) JOptionPane.showInputDialog(
null,
"Wähle den Spielmodus:",
"Spielmodus auswählen",
JOptionPane.QUESTION_MESSAGE,
null,
options,
GameMode.CLASSIC
);
return selected != null ? selected : GameMode.CLASSIC;
}
}

View File

@ -17,8 +17,7 @@ public class MainGui {
frame = new JFrame("Chess - Hauptmenü");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
frame.setUndecorated(false);
frame.setSize(1600, 1000);
frame.setLocationRelativeTo(null);
//Haupt-Panel mit GridBagLayout

View File

@ -3,7 +3,6 @@ package de.hs_mannheim.informatik.chess.view;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
@ -11,7 +10,6 @@ import java.awt.GridLayout;
import java.awt.Insets;
import java.util.List;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
@ -35,8 +33,6 @@ public class PgnGui {
JButton btnNext = new JButton(">");
JButton btnLast = new JButton(">|");
private JLabel openingLabel;
Color LIGHT = new Color(0xe0e1dd);
Color DARK = new Color(0x778da9);
@ -51,19 +47,12 @@ public class PgnGui {
public JFrame mainFrame() {
JFrame frame = new JFrame();
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
frame.setUndecorated(false);
frame.setSize(1600, 1000);
frame.setLocationRelativeTo(null);
frame.add(mainPanel());
frame.setDefaultCloseOperation(2);
frame.setVisible(true);
frame.addWindowListener(new java.awt.event.WindowAdapter() {
@Override
public void windowClosed(java.awt.event.WindowEvent e) {
new de.hs_mannheim.informatik.chess.controller.MainController();
}
});
return frame;
}
@ -134,57 +123,37 @@ public class PgnGui {
return boardPanel;
}
public JPanel chessPanel(JPanel boardPanel) {
JPanel chessPanel = new JPanel(new BorderLayout());
chessPanel.setBackground(new Color(0x1b263b));
public JPanel chessPanel(JPanel panel) {
JPanel chessPanel = new JPanel(new GridBagLayout());
GridBagConstraints board = new GridBagConstraints();
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
flipBoardButton = new JButton("⇵");
flipBoardButton.setPreferredSize(new Dimension(70, 70));
flipBoardButton.setFont(new Font("SansSerif", Font.BOLD, 40));
flipBoardButton.setBackground(new Color(0x5500ff));
flipBoardButton.setForeground(Color.WHITE);
flipBoardButton.setFocusPainted(false);
// --- 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);
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);
// --- 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));
flipBoardButton = new JButton("⇵");
flipBoardButton.setPreferredSize(new Dimension(70, 70));
flipBoardButton.setFont(new Font("SansSerif", Font.BOLD, 40));
flipBoardButton.setBackground(new Color(0x5500ff));
flipBoardButton.setForeground(Color.WHITE);
flipBoardButton.setFocusPainted(false);
buttonRow.add(flipBoardButton);
chessPanel.add(buttonRow, BorderLayout.SOUTH);
return chessPanel;
chessPanel.add(flipBoardButton, btn);
return chessPanel;
}
public JPanel statsPanel() {
@ -270,11 +239,6 @@ public class PgnGui {
this.isFlipped = flipped;
}
public void setOpeningLabel(String text) {
openingLabel.setText("Eröffnung: " + text);
}
public JButton getBtnFirst() { return btnFirst; }
public JButton getBtnPrev() { return btnPrev; }
public JButton getBtnNext() { return btnNext; }

View File

@ -0,0 +1,36 @@
package de.hs_mannheim.informatik.chess.test;
import junit.framework.*;
/**
* Unit test for simple App.
*/
public class AppTest
extends TestCase
{
/**
* Create the test case
*
* @param testName name of the test case
*/
public AppTest( String testName )
{
super( testName );
}
/**
* @return the suite of tests being tested
*/
public static TestSuite suite()
{
return new TestSuite( AppTest.class );
}
/**
* Rigourous Test :-)
*/
public void testApp()
{
assertTrue( true );
}
}

View File

@ -1,222 +0,0 @@
package de.hs_mannheim.informatik.chess.test;
import static org.junit.jupiter.api.Assertions.*;
import java.util.ArrayList;
import java.util.List;
import de.hs_mannheim.informatik.chess.model.*;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
class ModelTest {
private ChessEngine engine;
@BeforeEach
public void setUp() {
engine = new ChessEngine(); // Echte Instanz!
}
@Test
public void ErkenntObZugLegalOderIllegal()
{
assertTrue(engine.move(new MoveDTO(6, 4, 4, 4)));
assertFalse(engine.move(new MoveDTO(7, 0, 5, 1)));
}
@Test
public void GibtLegaleMovesAn() {
List<MoveDTO> mvs = new ArrayList<>();
mvs.add(new MoveDTO(6,4,5,4));
mvs.add(new MoveDTO(6,4,4,4));
List<MoveDTO> moves = engine.getLegalDestinations("E2");
assertEquals(2, moves.size());
assertTrue(moves.stream().anyMatch(m -> m.getToRow() == 5 && m.getToCol() == 4));
assertTrue(moves.stream().anyMatch(m -> m.getToRow() == 4 && m.getToCol() == 4));
}
@Test //Stichprobenartige Kontrolle ob richtige Figur an richtiger Stelle
public void BoardWirdRichtigAufgebaut() {
BoardDTO board = engine.getBoardAsDTO();
PieceDTO a1 = board.getBoard()[7][0];
assertEquals("ROOK", a1.getType());
assertEquals("WHITE", a1.getColor());
PieceDTO e1 = board.getBoard()[7][4];
assertEquals("KING", e1.getType());
assertEquals("WHITE", e1.getColor());
PieceDTO a8 = board.getBoard()[0][0];
assertEquals("ROOK", a8.getType());
assertEquals("BLACK", a8.getColor());
PieceDTO e8 = board.getBoard()[0][4];
assertEquals("KING", e8.getType());
assertEquals("BLACK", e8.getColor());
PieceDTO e2 = board.getBoard()[6][4];
assertEquals("PAWN", e2.getType());
assertEquals("WHITE", e2.getColor());
PieceDTO d7 = board.getBoard()[1][3];
assertEquals("PAWN", d7.getType());
assertEquals("BLACK", d7.getColor());
PieceDTO e4 = board.getBoard()[4][4];
assertNull(e4);
PieceDTO d5 = board.getBoard()[3][3];
assertNull(d5);
}
@Test
public void speichertMovesRichtigGruppiert() {
engine.move(new MoveDTO(6, 6, 4, 6));
engine.move(new MoveDTO(1, 4, 3, 4));
engine.move(new MoveDTO(7, 6, 5, 5)); //Züge um das speichern zu testen
engine.move(new MoveDTO(0, 1, 2, 2));
engine.move(new MoveDTO(7, 1, 5, 2));
List<String> gruppiertGespeichert = engine.getMoveListStringsGrouped(); //Moves in Liste gespeichert um zu testen
assertTrue(gruppiertGespeichert.size() >= 3, "Zu wenige gespeicherte Gruppen");
assertTrue(gruppiertGespeichert.get(0).startsWith("1."));
assertTrue(gruppiertGespeichert.get(1).startsWith("2."));
assertTrue(gruppiertGespeichert.get(2).startsWith("3."));
for (int i = 0; i < gruppiertGespeichert.size(); i++) {
String[] parts = gruppiertGespeichert.get(i).split(" ");
if (i == gruppiertGespeichert.size() - 1) {
assertTrue(parts.length == 2 || parts.length == 3);
} else {
assertEquals(3, parts.length);
}
}
}
@Test
public void erkenntMattKorrekt() {
assertFalse(engine.isMated()); //<--Test, dass nicht immer alles einfach Matt ist
engine.setPositionFromFEN("7k/6Q1/5K2/8/8/8/8/8 b - - 0 1"); //<--Matt position vorbereiten
System.out.println("Aktueller Spieler: " + engine.getCurrentPlayer());
System.out.println("isMated(): " + engine.isMated());
assertEquals("BLACK", engine.getCurrentPlayer());
assertTrue(engine.isMated()); //<Test ob nun spieler Matt ist
}
@Test
public void erkenntPattKorrekt() {
assertFalse(engine.isStalemate());
engine.setPositionFromFEN("7k/5Q2/6K1/8/8/8/8/8 b - - 0 1");
System.out.println("Aktueller Spieler: " + engine.getCurrentPlayer());
System.out.println("isStalemate(): " + engine.isStalemate());
assertEquals("BLACK", engine.getCurrentPlayer());
assertTrue(engine.isStalemate());
}
@Test
public void erkenntUnentschieden() {
assertFalse(engine.isDraw());
engine.setPositionFromFEN("8/8/8/8/8/8/8/4K2k w - - 0 1"); // nur zwei Könige
assertTrue(engine.isDraw());
}
@Test
public void MethodeGibtRichtigeFigurZurück() {
String type = "KING";
String color= "WHITE";
PieceDTO test = engine.getPieceAt("E1");
assertEquals(type, test.getType());
assertEquals(color, test.getColor());
}
@Test
public void MethodeGibtRichtigenPlayerZurück() {
assertEquals("WHITE", engine.getCurrentPlayer());
engine.move(new MoveDTO(6, 4, 4, 4));
assertEquals("BLACK", engine.getCurrentPlayer());
}
@Test
public void MethodeSetztBoardRichtigzurück() {
engine.move(new MoveDTO(6,4,4,4)); // e2-e4
engine.move(new MoveDTO(1,4,3,4)); // e7-e5
engine.setPositionToMoveIndex(1);
PieceDTO pawn = engine.getPieceAt("E4");
assertNotNull(pawn);
assertEquals("PAWN", pawn.getType());
assertNull(engine.getPieceAt("E5"));
assertEquals(1, engine.getCurrentMoveIndex());
}
@Test
public void FigurZurQueenBefördernklappt() {
engine.setPositionFromFEN("8/P7/8/8/8/8/8/k6K w - - 0 1"); // Weißer Bauer auf a7, Weiß am Zug
boolean moved = engine.moveWithPromotion(new MoveDTO(1, 0, 0, 0), "QUEEN"); // a7-a8=Dame
assertTrue(moved);
PieceDTO piece = engine.getPieceAt("A8");
assertEquals("QUEEN", piece.getType());
assertEquals("WHITE", piece.getColor());
}
@Test
public void fenAufbauFunktioniert() {
// Beispiel-FEN: Weißer König auf e1, schwarze Dame auf d8, schwarzer Bauer auf a7, Rest leer
String fen = "3q4/p7/8/8/8/8/8/4K3 w - - 0 1";
engine.setPositionFromFEN(fen);
// Kontrolliere schwarze Dame auf d8 (0,3)
PieceDTO d8 = engine.getPieceAt("D8");
assertEquals("QUEEN", d8.getType());
assertEquals("BLACK", d8.getColor());
// Kontrolliere schwarzen Bauern auf a7 (1,0)
PieceDTO a7 = engine.getPieceAt("A7");
assertEquals("PAWN", a7.getType());
assertEquals("BLACK", a7.getColor());
// Kontrolliere weißen König auf e1 (7,4)
PieceDTO e1 = engine.getPieceAt("E1");
assertEquals("KING", e1.getType());
assertEquals("WHITE", e1.getColor());
// Leeres Feld testen: e2 (6,4)
PieceDTO e2 = engine.getPieceAt("E2");
assertNull(e2);
// Leeres Feld testen: h5 (3,7)
PieceDTO h5 = engine.getPieceAt("H5");
assertNull(h5);
}
@Test
public void timerWirdRichtigErstellt() {
engine.initTimers(5, 30);
assertEquals(330, engine.getWhiteTimer().getSecondsLeft());
assertEquals(330, engine.getBlackTimer().getSecondsLeft());
}
}