Compare commits

...

22 Commits

Author SHA1 Message Date
Justin 8447ce5fe3 Fully implemented creativeMode 2025-06-24 01:47:00 +02:00
Justin 6d3154d0e3 Reworked PgnController and PgnGui 2025-06-24 01:01:26 +02:00
Justin 5770d13cdc Merge remote-tracking branch 'origin/Main' into JUnit-Tests 2025-06-24 00:51:33 +02:00
Justin ae07b4d719 Added undoMove feature and fixed replay issue 2025-06-24 00:50:32 +02:00
Justin aaa4317c9c Added resign and draw feature 2025-06-23 23:44:15 +02:00
valen 3aa8897ff1 Neue Tests hinzugefügt, ControlleTest entfernt(kein mustHave), weil nach
Änderungen ungültig,
2025-06-23 23:25:53 +02:00
Justin 3c3dd5e8ab Added a ComponentListener to the centerPanel in GameGui 2025-06-23 23:15:50 +02:00
Justin 35b7d9aa9a Changed frame size for all Gui and reworked chessPanel in GameGui 2025-06-23 23:11:23 +02:00
Justin 66a8c1a51d New buttons to resign and draw in GameGui 2025-06-23 22:46:15 +02:00
Justin 24374030be Merge branch 'Main' into Openings 2025-06-23 22:00:47 +02:00
Justin b56813d6dc Imported package GameEndCallback 2025-06-23 21:48:37 +02:00
Justin c864f88e1c Updated JUnit branch 2025-06-23 21:47:20 +02:00
Justin a669a4b2ff Reworked and fixed issues with savePgn feature 2025-06-23 21:20:30 +02:00
valen d16aa13804 Openings werden erkannt und im Logger ausgegeben 2025-06-23 21:02:29 +02:00
valen ea2c0066fd Die Klasse wurde beim letzten "Commi and Push" nicht mit genommen 2025-06-23 13:16:52 +02:00
valen ffbdb8b6e0 Aktuelles Spiel kann als pgn an gewünschten Speicherort, mit gewünschten
Namen gespeichert werden.
Header bis auf Datum ist immer Gleich
2025-06-23 13:16:13 +02:00
Justin d23f7097f7 Merge branch 'Main' into JUnit-Tests 2025-06-22 15:26:18 +02:00
valen 69c4e44671 pom.xml neue Änderung 2025-06-22 15:22:29 +02:00
valen 7ebfecc6c4 ModelTests wurden hinzugefügt 2025-06-22 15:19:08 +02:00
valen 993fa89371 pom.xml Anderung 2025-06-22 15:17:50 +02:00
valen 9e095418a2 Tests fast vollständig 2025-06-22 15:07:06 +02:00
valen 4c58eebc65 JUnit-Test-Klasse angelegt 2025-06-21 14:11:10 +02:00
15 changed files with 4410 additions and 169 deletions

File diff suppressed because it is too large Load Diff

View File

@ -33,13 +33,20 @@
<artifactId>chesslib</artifactId> <artifactId>chesslib</artifactId>
<version>1.3.4</version> <version>1.3.4</version>
</dependency> </dependency>
<!-- JUnit 3 (wie im Template, ggf. auf JUnit 4/5 upgraden für moderne Projekte) -->
<dependency> <dependency>
<groupId>junit</groupId> <groupId>org.junit.jupiter</groupId>
<artifactId>junit</artifactId> <artifactId>junit-jupiter</artifactId>
<version>3.8.1</version> <version>5.10.2</version>
<scope>test</scope>
</dependency>
<!-- Mockito damit man Controller und Gui besser testen kann-->
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>5.11.0</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
</dependencies> </dependencies>
<build> <build>

View File

@ -8,6 +8,8 @@ import java.util.List;
import javax.swing.BorderFactory; import javax.swing.BorderFactory;
import com.github.bhlangonijr.chesslib.game.Game;
import de.hs_mannheim.informatik.chess.model.ChessEngine; import de.hs_mannheim.informatik.chess.model.ChessEngine;
import de.hs_mannheim.informatik.chess.model.MoveDTO; import de.hs_mannheim.informatik.chess.model.MoveDTO;
import de.hs_mannheim.informatik.chess.model.PieceDTO; import de.hs_mannheim.informatik.chess.model.PieceDTO;
@ -82,6 +84,25 @@ public class GameController {
updateGuiBoard(); updateGuiBoard();
}); });
gui.getBtnSave().addActionListener(e -> {
System.out.println("Save-Button wurde geklickt!");
Game currentGame = engine.getCurrentGame();
javax.swing.JFileChooser fileChooser = new javax.swing.JFileChooser();
fileChooser.setDialogTitle("PGN speichern unter...");
int userSelection = fileChooser.showSaveDialog(null);
if (userSelection == javax.swing.JFileChooser.APPROVE_OPTION) {
java.io.File fileToSave = fileChooser.getSelectedFile();
try {
engine.saveAsPgn(currentGame, fileToSave.getParent(), fileToSave.getName());
gui.displayMessage("PGN gespeichert: " + fileToSave.getAbsolutePath());
} catch (Exception ex) {
gui.displayMessage("Fehler beim Speichern: " + ex.getMessage());
}
}
});
gui.getFlipBoardButton().addActionListener(e -> { gui.getFlipBoardButton().addActionListener(e -> {
//ALLE Highlights und Borders zurücksetzen //ALLE Highlights und Borders zurücksetzen
@ -102,13 +123,88 @@ public class GameController {
updateGuiBoard(); 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) { private void handleClick(int guiRow, int guiCol) {
if (gameOver) return; 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 modelRow = flipRow(guiRow);
int modelCol = flipCol(guiCol); int modelCol = flipCol(guiCol);
@ -205,6 +301,7 @@ public class GameController {
public void updateGuiBoard() { public void updateGuiBoard() {
BoardDTO board = engine.getBoardAsDTO(); BoardDTO board = engine.getBoardAsDTO();
gui.updateBoard(board); gui.updateBoard(board);
gui.setOpeningLabel(engine.getOpeningName());
} }
private void switchTimers() { private void switchTimers() {

View File

@ -47,6 +47,24 @@ public class MainController {
CreativeGui creativegui = new CreativeGui(); CreativeGui creativegui = new CreativeGui();
ChessEngine engine = new ChessEngine(); ChessEngine engine = new ChessEngine();
new CreativeController(creativegui, engine); new CreativeController(creativegui, engine);
creativegui.setStartGameCallback(fen -> {
ChessEngine newEngine = new ChessEngine();
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);
});
} }
private void startLoadGameMode() { private void startLoadGameMode() {

View File

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

View File

@ -14,24 +14,30 @@ import java.util.logging.SimpleFormatter;
import com.github.bhlangonijr.chesslib.Board; import com.github.bhlangonijr.chesslib.Board;
import com.github.bhlangonijr.chesslib.Piece; import com.github.bhlangonijr.chesslib.Piece;
import com.github.bhlangonijr.chesslib.Square; import com.github.bhlangonijr.chesslib.Square;
import com.github.bhlangonijr.chesslib.game.Game;
import com.github.bhlangonijr.chesslib.move.Move; import com.github.bhlangonijr.chesslib.move.Move;
import com.github.bhlangonijr.chesslib.pgn.PgnHolder; 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 { public class ChessEngine {
private Board board; private Board board;
private List<Move> moves = new ArrayList<>(); 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 static final Logger logger = Logger.getLogger(ChessEngine.class.getName());
private int currentMoveIndex = 0; private int currentMoveIndex = 0;
private Timer whiteTimer; private Timer whiteTimer;
private Timer blackTimer; private Timer blackTimer;
private Opening detectedOpening = null;
public ChessEngine() { public ChessEngine() {
logging(); logging();
board = new Board(); board = new Board();
} }
public boolean move(MoveDTO move) { public boolean move(MoveDTO move) {
String from = "" + (char)('A' + move.getFromCol()) + (8 - move.getFromRow()); String from = "" + (char)('A' + move.getFromCol()) + (8 - move.getFromRow());
String to = "" + (char)('A' + move.getToCol()) + (8 - move.getToRow()); String to = "" + (char)('A' + move.getToCol()) + (8 - move.getToRow());
@ -39,7 +45,7 @@ public class ChessEngine {
if (board.legalMoves().contains(libMove)) { if (board.legalMoves().contains(libMove)) {
board.doMove(libMove); board.doMove(libMove);
//Replay? Dann abschneiden // Replay? Dann abschneiden
if (currentMoveIndex < moves.size()) { if (currentMoveIndex < moves.size()) {
logger.info("Replay-Modus: Züge nach " + currentMoveIndex + " werden entfernt."); logger.info("Replay-Modus: Züge nach " + currentMoveIndex + " werden entfernt.");
moves = new ArrayList<>(moves.subList(0, currentMoveIndex)); moves = new ArrayList<>(moves.subList(0, currentMoveIndex));
@ -47,12 +53,37 @@ public class ChessEngine {
moves.add(libMove); moves.add(libMove);
currentMoveIndex++; currentMoveIndex++;
logger.info("Zug erfolgreich durchgeführt: " + libMove); 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; return true;
} }
logger.warning("Ungültiger Zug: " + libMove); logger.warning("Ungültiger Zug: " + libMove);
return false; 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) { public List<MoveDTO> getLegalDestinations(String from) {
logger.info("Hole legale Züge von: " + from); logger.info("Hole legale Züge von: " + from);
List<MoveDTO> destinations = new ArrayList<>(); List<MoveDTO> destinations = new ArrayList<>();
@ -158,15 +189,17 @@ public class ChessEngine {
} }
public void setPositionToMoveIndex(int idx) { public void setPositionToMoveIndex(int idx) {
// Neues Board erzeugen
logger.info("Setze Board auf Zug-Index: " + idx); logger.info("Setze Board auf Zug-Index: " + idx);
board = new Board(); board = new Board();
board.loadFromFen(initialFen); // Statt new Board() -> initialFen!
for (int i = 0; i < idx; i++) { for (int i = 0; i < idx; i++) {
board.doMove(moves.get(i)); board.doMove(moves.get(i));
} }
currentMoveIndex = idx; currentMoveIndex = idx;
}
String playedMovesUci = movesToUciString(moves.subList(0, idx));
detectedOpening = Opening.detect(playedMovesUci);
}
public int getCurrentMoveIndex() { public int getCurrentMoveIndex() {
logger.info("Hole aktuellen Zug-Index: " + currentMoveIndex); logger.info("Hole aktuellen Zug-Index: " + currentMoveIndex);
return currentMoveIndex; return currentMoveIndex;
@ -187,6 +220,7 @@ public class ChessEngine {
public void setPositionFromFEN(String fen) { public void setPositionFromFEN(String fen) {
board.loadFromFen(fen); board.loadFromFen(fen);
initialFen = fen;
} }
@ -249,14 +283,17 @@ public class ChessEngine {
} }
public void saveAsPgn(Game game, String path, String dateiname) { public void saveAsPgn(Game game, String path, String dateiname) {
String event = game.getRound().getEvent().getName(); // Sicher alle Strings holen (nie null)
String site = game.getRound().getEvent().getSite(); String event = safe(game.getRound().getEvent().getName());
String site = safe(game.getRound().getEvent().getSite());
String round = "" + game.getRound().getNumber(); String round = "" + game.getRound().getNumber();
String date = game.getRound().getEvent().getStartDate(); // Datum für PGN-Format (YYYY.MM.DD)
String wName = game.getWhitePlayer().getName(); String date = safe(game.getRound().getEvent().getStartDate()).replace("-", ".");
String bName = game.getBlackPlayer().getName(); String wName = safe(game.getWhitePlayer().getName());
String result = game.getResult().getDescription(); String bName = safe(game.getBlackPlayer().getName());
String result = safe(game.getResult().getDescription());
// PGN-Header zusammenbauen
StringBuilder header = new StringBuilder(); StringBuilder header = new StringBuilder();
header.append("[Event \"" + event + "\"]\n"); header.append("[Event \"" + event + "\"]\n");
header.append("[Site \"" + site + "\"]\n"); header.append("[Site \"" + site + "\"]\n");
@ -264,23 +301,25 @@ public class ChessEngine {
header.append("[Round \"" + round + "\"]\n"); header.append("[Round \"" + round + "\"]\n");
header.append("[White \"" + wName + "\"]\n"); header.append("[White \"" + wName + "\"]\n");
header.append("[Black \"" + bName + "\"]\n"); header.append("[Black \"" + bName + "\"]\n");
header.append("[Result \"" + result + "\"]\n"); header.append("[Result \"" + result + "\"]\n\n");
header.append("\n");
StringBuilder sb = new StringBuilder(); // Züge als SAN holen
StringBuilder moves = new StringBuilder();
String[] sanArray = game.getHalfMoves().toSanArray(); String[] sanArray = game.getHalfMoves().toSanArray();
for (int i = 0; i < sanArray.length; i++) { for (int i = 0; i < sanArray.length; i++) {
if (i % 2 == 0) { if (i % 2 == 0) {
sb.append((i / 2 + 1)).append(". "); moves.append((i / 2 + 1)).append(". ");
} }
sb.append(sanArray[i]).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!
sb.append(result); // Endergebnis muss auch am Ende stehen! String file = header + moves.toString();
String file = header.toString() + sb.toString();
// Datei schreiben
try { try {
Files.writeString(Path.of(path, dateiname), file, StandardCharsets.UTF_8); Files.writeString(Path.of(path, dateiname), file, StandardCharsets.UTF_8);
} catch (IOException e) { } catch (IOException e) {
@ -288,6 +327,77 @@ public class ChessEngine {
} }
} }
// Hilfsfunktion für Null-Sicherheit
private String safe(String s) {
return s == null ? "?" : s;
}
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
// Runde anlegen
Round round = new Round(event);
round.setNumber(1);
// Spiel initialisieren
Game game = new Game("1", round); // "1" ist die Game-ID
// Spieler setzen (deine MyPlayer-Klasse)
game.setWhitePlayer(new MyPlayer("White"));
game.setBlackPlayer(new MyPlayer("Black"));
// 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);
}
// Züge übernehmen
MoveList moveList = new MoveList();
for (Move move : moves) {
moveList.add(move);
}
game.setHalfMoves(moveList);
// Position auf aktuellen Zug setzen (letzter gespielter Halbzug)
if (currentMoveIndex > 0 && currentMoveIndex <= moveList.size()) {
game.setPosition(currentMoveIndex - 1);
} else {
game.setPosition(moveList.size() - 1);
}
// FEN setzen: JETZT das aktuelle Board-FEN verwenden!
game.setBoard(new Board());
game.getBoard().loadFromFen(board.getFen());
return game;
}
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) { public void loadMoves(List<Move> moveList) {
board = new Board(); // Neues leeres Brett board = new Board(); // Neues leeres Brett
moves.clear(); moves.clear();

View File

@ -0,0 +1,72 @@
package de.hs_mannheim.informatik.chess.model;
import com.github.bhlangonijr.chesslib.game.Player;
import com.github.bhlangonijr.chesslib.game.PlayerType;
public class MyPlayer implements Player {
private String id = "";
private String name;
private int elo = 0;
private PlayerType type = PlayerType.HUMAN;
private String description = "";
private String longDescription = "";
public MyPlayer(String name) {
this.name = name;
}
@Override
public String getId() {
return id;
}
@Override
public void setId(String id) {
this.id = id;
}
@Override
public int getElo() {
return elo;
}
@Override
public void setElo(int elo) {
this.elo = elo;
}
@Override
public String getName() {
return name;
}
@Override
public void setName(String name) {
this.name = name;
}
@Override
public PlayerType getType() {
return type;
}
@Override
public void setType(PlayerType type) {
this.type = type;
}
@Override
public String getDescription() {
return description;
}
@Override
public void setDescription(String description) {
this.description = description;
}
@Override
public String getLongDescription() {
return longDescription;
}
}

View File

@ -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;
}
}

View File

@ -5,6 +5,11 @@ import java.awt.*;
import java.util.HashMap; import java.util.HashMap;
public class CreativeGui { public class CreativeGui {
public interface StartGameCallback {
void onStartGame(String fen);
}
private boolean isFlipped = false; private boolean isFlipped = false;
private JFrame frame; private JFrame frame;
@ -14,6 +19,10 @@ public class CreativeGui {
private JButton updateBtn; private JButton updateBtn;
private JButton flipBoardButton; private JButton flipBoardButton;
private StartGameCallback startGameCallback;
private JButton startGameButton;
public static final HashMap<String, String> UNICODE_MAP = new HashMap<String, String>() {{ public static final HashMap<String, String> UNICODE_MAP = new HashMap<String, String>() {{
put("BLACK_KING", "\u265A"); put("BLACK_QUEEN", "\u265B"); put("BLACK_KING", "\u265A"); put("BLACK_QUEEN", "\u265B");
put("BLACK_ROOK", "\u265C"); put("BLACK_BISHOP", "\u265D"); put("BLACK_ROOK", "\u265C"); put("BLACK_BISHOP", "\u265D");
@ -30,7 +39,8 @@ public class CreativeGui {
public CreativeGui() { public CreativeGui() {
frame = new JFrame("Creative Mode"); frame = new JFrame("Creative Mode");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setSize(1600, 1200); frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
frame.setUndecorated(false);
frame.setLocationRelativeTo(null); frame.setLocationRelativeTo(null);
JPanel mainPanel = new JPanel(new GridBagLayout()); JPanel mainPanel = new JPanel(new GridBagLayout());
@ -40,7 +50,7 @@ public class CreativeGui {
// LINKS: chessPanel (Board+Toolbars) // LINKS: chessPanel (Board+Toolbars)
gbc.gridx = 0; gbc.gridx = 0;
gbc.gridy = 0; gbc.gridy = 0;
gbc.weightx = 0.6; gbc.weightx = 0.7;
gbc.weighty = 1.0; gbc.weighty = 1.0;
gbc.insets = new Insets(5, 5, 5, 0); gbc.insets = new Insets(5, 5, 5, 0);
gbc.fill = GridBagConstraints.BOTH; gbc.fill = GridBagConstraints.BOTH;
@ -49,7 +59,7 @@ public class CreativeGui {
// RECHTS: FEN & Optionen // RECHTS: FEN & Optionen
gbc.gridx = 1; gbc.gridx = 1;
gbc.gridy = 0; gbc.gridy = 0;
gbc.weightx = 0.4; gbc.weightx = 0.3;
gbc.weighty = 1.0; gbc.weighty = 1.0;
gbc.insets = new Insets(5, 0, 5, 5); gbc.insets = new Insets(5, 0, 5, 5);
gbc.fill = GridBagConstraints.BOTH; gbc.fill = GridBagConstraints.BOTH;
@ -71,7 +81,7 @@ public class CreativeGui {
btn.setFocusPainted(false); btn.setFocusPainted(false);
btn.setPreferredSize(new Dimension(70, 70)); btn.setPreferredSize(new Dimension(70, 70));
btn.setBackground(white ? LIGHT : DARK); btn.setBackground(white ? LIGHT : DARK);
btn.setBorder(BorderFactory.createEmptyBorder(20, 0, 20, 0)); btn.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
String key = prefix + type; String key = prefix + type;
btn.addActionListener(e -> selectedPiece = key); btn.addActionListener(e -> selectedPiece = key);
panel.add(btn); panel.add(btn);
@ -104,48 +114,77 @@ public class CreativeGui {
} }
private JPanel chessPanel() { private JPanel chessPanel() {
JPanel chessPanel = new JPanel(new GridBagLayout()); JPanel chessPanel = new JPanel(new BorderLayout());
chessPanel.setBackground(new Color(0x1b263b)); chessPanel.setBackground(new Color(0x1b263b));
GridBagConstraints gbc = new GridBagConstraints();
// Toolbar oben // Board UND Toolbars in EINEM Panel, damit sie linksbündig mit dem Brett starten!
gbc.gridx = 0; JPanel boardAndToolbars = new JPanel(new BorderLayout());
gbc.gridy = 0; boardAndToolbars.setOpaque(false);
gbc.fill = GridBagConstraints.HORIZONTAL;
chessPanel.add(toolbarPanel(false), gbc);
// Board // Toolbar Schwarz (oben)
gbc.gridx = 0; JPanel blackToolbar = toolbarPanel(false);
gbc.gridy = 1; boardAndToolbars.add(blackToolbar, BorderLayout.NORTH);
gbc.fill = GridBagConstraints.BOTH;
chessPanel.add(boardPanel(), gbc);
// Toolbar unten // Board (zentriert im Panel)
gbc.gridx = 0; JPanel board = boardPanel();
gbc.gridy = 2; boardAndToolbars.add(board, BorderLayout.CENTER);
gbc.fill = GridBagConstraints.HORIZONTAL;
chessPanel.add(toolbarPanel(true), gbc);
// Drehknopf // Toolbar Weiß (unten)
flipBoardButton = new JButton("⇵"); JPanel whiteToolbar = toolbarPanel(true);
flipBoardButton.setPreferredSize(new Dimension(70, 70)); boardAndToolbars.add(whiteToolbar, BorderLayout.SOUTH);
flipBoardButton.setFont(new Font("SansSerif", Font.BOLD, 40));
flipBoardButton.setBackground(new Color(0x5500ff));
flipBoardButton.setForeground(Color.WHITE);
flipBoardButton.setFocusPainted(false);
GridBagConstraints btn = new GridBagConstraints(); // Board+Toolbars mittig in einem Panel mit FlowLayout, damit sie zentriert sind
btn.gridx = 0; JPanel centerPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 0, 0));
btn.gridy = 2; centerPanel.setOpaque(false);
btn.weightx = 0.0; centerPanel.add(boardAndToolbars);
btn.weighty = 0.0;
btn.anchor = GridBagConstraints.EAST; blackToolbar.setPreferredSize(new Dimension(0, 70)); // 70 px hoch
btn.insets = new Insets(5, 0, 0, 0); whiteToolbar.setPreferredSize(new Dimension(0, 70));
chessPanel.add(flipBoardButton, btn); // 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);
return chessPanel; 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() { private JPanel fenPanel() {
JPanel panel = new JPanel(); JPanel panel = new JPanel();
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
@ -159,7 +198,20 @@ public class CreativeGui {
updateBtn = new JButton("Update Board"); updateBtn = new JButton("Update Board");
updateBtn.setAlignmentX(Component.CENTER_ALIGNMENT); updateBtn.setAlignmentX(Component.CENTER_ALIGNMENT);
panel.add(updateBtn); 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) {
startGameCallback.onStartGame(getFenText());
}
});
return panel; return panel;
} }
// Für Controller // Für Controller
@ -171,6 +223,12 @@ public class CreativeGui {
public void setSelectedPiece(String piece) { selectedPiece = piece; } public void setSelectedPiece(String piece) { selectedPiece = piece; }
public String getSelectedPiece() { return selectedPiece; } public String getSelectedPiece() { return selectedPiece; }
public JButton getStartGameButton() { return startGameButton; }
public void setStartGameCallback(StartGameCallback callback) {
this.startGameCallback = callback;
}
public boolean isFlipped() { return isFlipped; } public boolean isFlipped() { return isFlipped; }
public void setFlipped(boolean f) { isFlipped = f; } public void setFlipped(boolean f) { isFlipped = f; }
public JButton getFlipBoardButton() { return flipBoardButton; } public JButton getFlipBoardButton() { return flipBoardButton; }

View File

@ -7,9 +7,12 @@ import java.awt.Font;
import java.awt.GridBagConstraints; import java.awt.GridBagConstraints;
import java.awt.GridBagLayout; import java.awt.GridBagLayout;
import java.awt.GridLayout; import java.awt.GridLayout;
import java.awt.FlowLayout;
import java.awt.Insets; import java.awt.Insets;
import java.util.List; import java.util.List;
import javax.swing.Box;
import javax.swing.BoxLayout; import javax.swing.BoxLayout;
import javax.swing.JButton; import javax.swing.JButton;
import javax.swing.JFrame; import javax.swing.JFrame;
@ -27,14 +30,21 @@ public class GameGui {
private JLabel[][] fields = new JLabel[8][8]; private JLabel[][] fields = new JLabel[8][8];
private JButton flipBoardButton; private JButton flipBoardButton;
private boolean isFlipped = false; private boolean isFlipped = false;
JButton btnSave = new JButton("💾");
private JLabel whiteTimerLabel; private JLabel whiteTimerLabel;
private JLabel blackTimerLabel; private JLabel blackTimerLabel;
private JLabel openingLabel;
JButton btnFirst = new JButton("|<"); private JButton btnFirst = new JButton("|<");
JButton btnPrev = new JButton("<"); private JButton btnPrev = new JButton("<");
JButton btnNext = new JButton(">"); private JButton btnNext = new JButton(">");
JButton btnLast = 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 LIGHT = new Color(0xe0e1dd);
Color DARK = new Color(0x778da9); Color DARK = new Color(0x778da9);
@ -50,7 +60,8 @@ public class GameGui {
public JFrame mainFrame() { public JFrame mainFrame() {
JFrame frame = new JFrame(); JFrame frame = new JFrame();
frame.setSize(1600, 1000); frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
frame.setUndecorated(false);
frame.setLocationRelativeTo(null); frame.setLocationRelativeTo(null);
frame.add(mainPanel()); frame.add(mainPanel());
@ -126,19 +137,58 @@ public class GameGui {
return boardPanel; return boardPanel;
} }
public JPanel chessPanel(JPanel panel) { public JPanel chessPanel(JPanel boardPanel) {
JPanel chessPanel = new JPanel(new GridBagLayout()); JPanel chessPanel = new JPanel(new BorderLayout());
GridBagConstraints board = new GridBagConstraints();
chessPanel.setBackground(new Color(0x1b263b)); chessPanel.setBackground(new Color(0x1b263b));
board.gridx = 0;
board.gridy = 0; // --- Eröffnungslabel oben ---
board.weightx = 0.7; openingLabel = new JLabel("Eröffnung: unbekannt", SwingConstants.CENTER);
board.weighty = 1.0; openingLabel.setFont(new Font("SansSerif", Font.BOLD, 24));
board.insets = new Insets(0, 0, 0, 0); openingLabel.setForeground(Color.WHITE);
//oben, links, unten, rechts openingLabel.setOpaque(true);
board.fill = GridBagConstraints.BOTH; openingLabel.setBackground(new Color(0x283655));
chessPanel.add(panel); openingLabel.setPreferredSize(new Dimension(800, 50));
// Button unten rechts 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 = new JButton("⇵");
flipBoardButton.setPreferredSize(new Dimension(70, 70)); flipBoardButton.setPreferredSize(new Dimension(70, 70));
flipBoardButton.setFont(new Font("SansSerif", Font.BOLD, 40)); flipBoardButton.setFont(new Font("SansSerif", Font.BOLD, 40));
@ -146,19 +196,24 @@ public class GameGui {
flipBoardButton.setForeground(Color.WHITE); flipBoardButton.setForeground(Color.WHITE);
flipBoardButton.setFocusPainted(false); flipBoardButton.setFocusPainted(false);
GridBagConstraints btn = new GridBagConstraints(); undoButton = new JButton("↧");
btn.gridx = 0; undoButton.setPreferredSize(new Dimension(70, 70));
btn.gridy = 1; undoButton.setFont(new Font("SansSerif", Font.BOLD, 40));
btn.weightx = 0.0; undoButton.setBackground(new Color(0xffa500)); // Orange
btn.weighty = 0.0; undoButton.setForeground(Color.WHITE);
btn.anchor = GridBagConstraints.SOUTHEAST; undoButton.setFocusPainted(false);
btn.insets = new Insets(10, 0, 0, 0);
chessPanel.add(flipBoardButton, btn); buttonRow.add(undoButton);
buttonRow.add(resignButton);
buttonRow.add(drawButton);
buttonRow.add(flipBoardButton);
chessPanel.add(buttonRow, BorderLayout.SOUTH);
return chessPanel; return chessPanel;
} }
public JPanel statsPanel() { public JPanel statsPanel() {
JPanel statsPanel = new JPanel(new BorderLayout()); JPanel statsPanel = new JPanel(new BorderLayout());
statsPanel.setBackground(new Color(0x0d1b2a)); statsPanel.setBackground(new Color(0x0d1b2a));
@ -177,15 +232,18 @@ public class GameGui {
// Button-Leiste (SÜD) // Button-Leiste (SÜD)
JPanel buttonPanel = new JPanel(); JPanel buttonPanel = new JPanel();
buttonPanel.setBackground(new Color(0x0d1b2a)); buttonPanel.setBackground(new Color(0x0d1b2a));
buttonPanel.setLayout(new GridLayout(1, 4, 10, 0)); buttonPanel.setLayout(new GridLayout(1, 5, 10, 0)); // Jetzt 5 statt 4 Spalten!
btnFirst.setBackground(new Color(0x212529)); btnFirst.setForeground(Color.WHITE); btnFirst.setBackground(new Color(0x212529)); btnFirst.setForeground(Color.WHITE);
btnPrev.setBackground(new Color(0x212529)); btnPrev.setForeground(Color.WHITE); btnPrev.setBackground(new Color(0x212529)); btnPrev.setForeground(Color.WHITE);
btnNext.setBackground(new Color(0x212529)); btnNext.setForeground(Color.WHITE); btnNext.setBackground(new Color(0x212529)); btnNext.setForeground(Color.WHITE);
btnLast.setBackground(new Color(0x212529)); btnLast.setForeground(Color.WHITE); btnLast.setBackground(new Color(0x212529)); btnLast.setForeground(Color.WHITE);
btnSave.setBackground(new Color(0x218838)); btnSave.setForeground(Color.WHITE);
buttonPanel.add(btnFirst); buttonPanel.add(btnFirst);
buttonPanel.add(btnPrev); buttonPanel.add(btnPrev);
buttonPanel.add(btnNext); buttonPanel.add(btnNext);
buttonPanel.add(btnLast); buttonPanel.add(btnLast);
buttonPanel.add(btnSave);
statsPanel.add(buttonPanel, BorderLayout.SOUTH); statsPanel.add(buttonPanel, BorderLayout.SOUTH);
return statsPanel; return statsPanel;
@ -266,6 +324,9 @@ public class GameGui {
public JButton getBtnPrev() { return btnPrev; } public JButton getBtnPrev() { return btnPrev; }
public JButton getBtnNext() { return btnNext; } public JButton getBtnNext() { return btnNext; }
public JButton getBtnLast() { return btnLast; } 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) { public void updateBoard(BoardDTO boardDTO) {
PieceDTO[][] board = boardDTO.getBoard(); PieceDTO[][] board = boardDTO.getBoard();
@ -305,6 +366,13 @@ public class GameGui {
public JLabel getWhiteTimerLabel() { return whiteTimerLabel; } public JLabel getWhiteTimerLabel() { return whiteTimerLabel; }
public JLabel getBlackTimerLabel() { return blackTimerLabel; } 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) { public void displayMessage(String msg) {
JOptionPane.showMessageDialog(null, msg); JOptionPane.showMessageDialog(null, msg);

View File

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

View File

@ -3,6 +3,7 @@ package de.hs_mannheim.informatik.chess.view;
import java.awt.BorderLayout; import java.awt.BorderLayout;
import java.awt.Color; import java.awt.Color;
import java.awt.Dimension; import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font; import java.awt.Font;
import java.awt.GridBagConstraints; import java.awt.GridBagConstraints;
import java.awt.GridBagLayout; import java.awt.GridBagLayout;
@ -10,6 +11,7 @@ import java.awt.GridLayout;
import java.awt.Insets; import java.awt.Insets;
import java.util.List; import java.util.List;
import javax.swing.Box;
import javax.swing.BoxLayout; import javax.swing.BoxLayout;
import javax.swing.JButton; import javax.swing.JButton;
import javax.swing.JFrame; import javax.swing.JFrame;
@ -33,6 +35,8 @@ public class PgnGui {
JButton btnNext = new JButton(">"); JButton btnNext = new JButton(">");
JButton btnLast = new JButton(">|"); JButton btnLast = new JButton(">|");
private JLabel openingLabel;
Color LIGHT = new Color(0xe0e1dd); Color LIGHT = new Color(0xe0e1dd);
Color DARK = new Color(0x778da9); Color DARK = new Color(0x778da9);
@ -47,7 +51,8 @@ public class PgnGui {
public JFrame mainFrame() { public JFrame mainFrame() {
JFrame frame = new JFrame(); JFrame frame = new JFrame();
frame.setSize(1600, 1000); frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
frame.setUndecorated(false);
frame.setLocationRelativeTo(null); frame.setLocationRelativeTo(null);
frame.add(mainPanel()); frame.add(mainPanel());
@ -123,19 +128,45 @@ public class PgnGui {
return boardPanel; return boardPanel;
} }
public JPanel chessPanel(JPanel panel) { public JPanel chessPanel(JPanel boardPanel) {
JPanel chessPanel = new JPanel(new GridBagLayout()); JPanel chessPanel = new JPanel(new BorderLayout());
GridBagConstraints board = new GridBagConstraints();
chessPanel.setBackground(new Color(0x1b263b)); chessPanel.setBackground(new Color(0x1b263b));
board.gridx = 0;
board.gridy = 0; // --- Eröffnungslabel oben ---
board.weightx = 0.7; openingLabel = new JLabel("Eröffnung: unbekannt", SwingConstants.CENTER);
board.weighty = 1.0; openingLabel.setFont(new Font("SansSerif", Font.BOLD, 24));
board.insets = new Insets(0, 0, 0, 0); openingLabel.setForeground(Color.WHITE);
//oben, links, unten, rechts openingLabel.setOpaque(true);
board.fill = GridBagConstraints.BOTH; openingLabel.setBackground(new Color(0x283655));
chessPanel.add(panel); openingLabel.setPreferredSize(new Dimension(800, 50));
// Button unten rechts 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));
flipBoardButton = new JButton("⇵"); flipBoardButton = new JButton("⇵");
flipBoardButton.setPreferredSize(new Dimension(70, 70)); flipBoardButton.setPreferredSize(new Dimension(70, 70));
flipBoardButton.setFont(new Font("SansSerif", Font.BOLD, 40)); flipBoardButton.setFont(new Font("SansSerif", Font.BOLD, 40));
@ -143,15 +174,9 @@ public class PgnGui {
flipBoardButton.setForeground(Color.WHITE); flipBoardButton.setForeground(Color.WHITE);
flipBoardButton.setFocusPainted(false); flipBoardButton.setFocusPainted(false);
GridBagConstraints btn = new GridBagConstraints(); buttonRow.add(flipBoardButton);
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);
chessPanel.add(flipBoardButton, btn); chessPanel.add(buttonRow, BorderLayout.SOUTH);
return chessPanel; return chessPanel;
} }
@ -239,6 +264,11 @@ public class PgnGui {
this.isFlipped = flipped; this.isFlipped = flipped;
} }
public void setOpeningLabel(String text) {
openingLabel.setText("Eröffnung: " + text);
}
public JButton getBtnFirst() { return btnFirst; } public JButton getBtnFirst() { return btnFirst; }
public JButton getBtnPrev() { return btnPrev; } public JButton getBtnPrev() { return btnPrev; }
public JButton getBtnNext() { return btnNext; } public JButton getBtnNext() { return btnNext; }

View File

@ -1,36 +0,0 @@
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

@ -0,0 +1,222 @@
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());
}
}

View File

@ -0,0 +1,102 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>de.hs-mannheim.informatik.schach</groupId>
<artifactId>schach</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>schach</name>
<description>A simple schach.</description>
<url>http://www.example.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
</properties>
<repositories>
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
</repositories>
<dependencies>
<!-- Schachlib (bhlangonijr) -->
<dependency>
<groupId>com.github.bhlangonijr</groupId>
<artifactId>chesslib</artifactId>
<version>1.3.4</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.10.2</version>
<scope>test</scope>
</dependency>
<!-- Mockito damit man Controller und Gui besser testen kann-->
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>5.11.0</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<pluginManagement>
<plugins>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.4.0</version>
</plugin>
<plugin>
<artifactId>maven-site-plugin</artifactId>
<version>3.12.1</version>
</plugin>
<plugin>
<artifactId>maven-project-info-reports-plugin</artifactId>
<version>3.6.1</version>
</plugin>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.3.1</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.13.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.3.0</version>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>3.4.2</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>3.1.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>3.1.2</version>
</plugin>
</plugins>
</pluginManagement>
</build>
<reporting>
<plugins>
<plugin>
<artifactId>maven-project-info-reports-plugin</artifactId>
</plugin>
</plugins>
</reporting>
</project>