Updated JUnit branch
commit
c864f88e1c
|
@ -0,0 +1,169 @@
|
||||||
|
package de.hs_mannheim.informatik.chess.controller;
|
||||||
|
|
||||||
|
import de.hs_mannheim.informatik.chess.view.CreativeGui;
|
||||||
|
import de.hs_mannheim.informatik.chess.model.ChessEngine;
|
||||||
|
import de.hs_mannheim.informatik.chess.model.PieceDTO;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
import java.awt.event.MouseListener;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class CreativeController {
|
||||||
|
private CreativeGui gui;
|
||||||
|
private ChessEngine engine;
|
||||||
|
|
||||||
|
// Hilfsmap für Unicode zu Chesslib Piece FEN-Zeichen
|
||||||
|
private static final HashMap<String, Character> PIECE_TO_FEN = createPieceToFenMap();
|
||||||
|
|
||||||
|
private static HashMap<String, Character> createPieceToFenMap() {
|
||||||
|
HashMap<String, Character> map = new HashMap<String, Character>();
|
||||||
|
map.put("BLACK_KING", 'k');
|
||||||
|
map.put("BLACK_QUEEN", 'q');
|
||||||
|
map.put("BLACK_ROOK", 'r');
|
||||||
|
map.put("BLACK_BISHOP", 'b');
|
||||||
|
map.put("BLACK_KNIGHT", 'n');
|
||||||
|
map.put("BLACK_PAWN", 'p');
|
||||||
|
map.put("WHITE_KING", 'K');
|
||||||
|
map.put("WHITE_QUEEN", 'Q');
|
||||||
|
map.put("WHITE_ROOK", 'R');
|
||||||
|
map.put("WHITE_BISHOP", 'B');
|
||||||
|
map.put("WHITE_KNIGHT", 'N');
|
||||||
|
map.put("WHITE_PAWN", 'P');
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CreativeController(CreativeGui gui, ChessEngine engine) {
|
||||||
|
this.gui = gui;
|
||||||
|
this.engine = engine;
|
||||||
|
|
||||||
|
setupFieldListeners();
|
||||||
|
setupFenUpdateListener();
|
||||||
|
gui.setFenText("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1");
|
||||||
|
applyFenToBoard();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupFieldListeners() {
|
||||||
|
JLabel[][] fields = gui.getFields();
|
||||||
|
for (int row = 0; row < 8; row++) {
|
||||||
|
for (int col = 0; col < 8; col++) {
|
||||||
|
final int r = row, c = col;
|
||||||
|
for (MouseListener l : fields[r][c].getMouseListeners()) {
|
||||||
|
fields[r][c].removeMouseListener(l);
|
||||||
|
}
|
||||||
|
fields[r][c].addMouseListener(new java.awt.event.MouseAdapter() {
|
||||||
|
public void mousePressed(java.awt.event.MouseEvent evt) {
|
||||||
|
fieldClicked(r, c);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gui.getFlipBoardButton().addActionListener(e -> {
|
||||||
|
applyFenToBoard();
|
||||||
|
gui.setFlipped(!gui.isFlipped());
|
||||||
|
updateGuiFromEngine(); // Board wird neu angezeigt, ggf. invertiert
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void fieldClicked(int row, int col) {
|
||||||
|
String selectedPiece = gui.getSelectedPiece();
|
||||||
|
if (selectedPiece == null) return;
|
||||||
|
if ("ERASER".equals(selectedPiece)) {
|
||||||
|
gui.getFields()[row][col].setText("");
|
||||||
|
} else {
|
||||||
|
gui.getFields()[row][col].setText(CreativeGui.UNICODE_MAP.get(selectedPiece));
|
||||||
|
}
|
||||||
|
// Jetzt FEN synchronisieren:
|
||||||
|
gui.setFenText(boardToFen());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void setupFenUpdateListener() {
|
||||||
|
//Getter für das Feld in deiner Gui:
|
||||||
|
JTextField fenField = gui.getFenField();
|
||||||
|
if (fenField != null) {
|
||||||
|
fenField.addActionListener(new java.awt.event.ActionListener() {
|
||||||
|
public void actionPerformed(java.awt.event.ActionEvent e) {
|
||||||
|
applyFenToBoard();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
JButton updateBtn = gui.getUpdateButton();
|
||||||
|
if (updateBtn != null) {
|
||||||
|
updateBtn.addActionListener(new java.awt.event.ActionListener() {
|
||||||
|
public void actionPerformed(java.awt.event.ActionEvent e) {
|
||||||
|
applyFenToBoard();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void applyFenToBoard() {
|
||||||
|
String fen = gui.getFenText();
|
||||||
|
try {
|
||||||
|
engine.setPositionFromFEN(fen);
|
||||||
|
updateGuiFromEngine();
|
||||||
|
} catch (Exception ex) {
|
||||||
|
JOptionPane.showMessageDialog(null, "Ungültiges FEN: " + ex.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Board aus der GUI zu FEN String
|
||||||
|
private String boardToFen() {
|
||||||
|
JLabel[][] fields = gui.getFields();
|
||||||
|
StringBuilder fen = new StringBuilder();
|
||||||
|
for (int row = 0; row < 8; row++) {
|
||||||
|
int empty = 0;
|
||||||
|
for (int col = 0; col < 8; col++) {
|
||||||
|
String symbol = fields[row][col].getText();
|
||||||
|
String pieceKey = null;
|
||||||
|
for (Map.Entry<String, String> entry : CreativeGui.UNICODE_MAP.entrySet()) {
|
||||||
|
if (entry.getValue().equals(symbol)) {
|
||||||
|
pieceKey = entry.getKey();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (pieceKey == null || "ERASER".equals(pieceKey) || symbol.trim().isEmpty()) {
|
||||||
|
empty++;
|
||||||
|
} else {
|
||||||
|
if (empty > 0) {
|
||||||
|
fen.append(empty);
|
||||||
|
empty = 0;
|
||||||
|
}
|
||||||
|
Character fenChar = PIECE_TO_FEN.get(pieceKey);
|
||||||
|
if (fenChar != null) fen.append(fenChar);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (empty > 0) fen.append(empty);
|
||||||
|
if (row < 7) fen.append('/');
|
||||||
|
}
|
||||||
|
fen.append(" w - - 0 1");
|
||||||
|
return fen.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateGuiFromEngine() {
|
||||||
|
PieceDTO[][] board = engine.getBoardAsDTO().getBoard();
|
||||||
|
JLabel[][] fields = gui.getFields();
|
||||||
|
|
||||||
|
boolean flipped = gui.isFlipped(); // NEU
|
||||||
|
|
||||||
|
for (int row = 0; row < 8; row++) {
|
||||||
|
for (int col = 0; col < 8; col++) {
|
||||||
|
int displayRow = flipped ? 7 - row : row;
|
||||||
|
int displayCol = flipped ? 7 - col : col;
|
||||||
|
PieceDTO p = board[row][col];
|
||||||
|
if (p == null) {
|
||||||
|
fields[displayRow][displayCol].setText("");
|
||||||
|
} else {
|
||||||
|
for (Map.Entry<String, String> entry : CreativeGui.UNICODE_MAP.entrySet()) {
|
||||||
|
if (entry.getKey().startsWith(p.getColor()) && entry.getKey().endsWith(p.getType())) {
|
||||||
|
fields[displayRow][displayCol].setText(entry.getValue());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -8,25 +8,40 @@ 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;
|
||||||
import de.hs_mannheim.informatik.chess.model.BoardDTO;
|
import de.hs_mannheim.informatik.chess.model.BoardDTO;
|
||||||
import de.hs_mannheim.informatik.chess.view.GameGui;
|
import de.hs_mannheim.informatik.chess.view.GameGui;
|
||||||
|
import de.hs_mannheim.informatik.chess.view.MainGui;
|
||||||
|
|
||||||
public class Controller {
|
public class GameController {
|
||||||
GameGui gui;
|
GameGui gui;
|
||||||
ChessEngine engine;
|
ChessEngine engine;
|
||||||
|
GameEndCallback callback;
|
||||||
|
|
||||||
|
private boolean gameOver = false;
|
||||||
private int selectedRow = -1, selectedCol = -1;
|
private int selectedRow = -1, selectedCol = -1;
|
||||||
private List<int[]> highlightedFields = new ArrayList<>();
|
private List<int[]> highlightedFields = new ArrayList<>();
|
||||||
|
|
||||||
public Controller(GameGui gui, ChessEngine engine) {
|
public GameController(GameGui gui, ChessEngine engine, GameEndCallback callback) {
|
||||||
this.gui = gui;
|
this.gui = gui;
|
||||||
this.engine = engine;
|
this.engine = engine;
|
||||||
|
this.callback = callback;
|
||||||
|
engine.initTimers(3, 0);
|
||||||
|
time();
|
||||||
initListeners();
|
initListeners();
|
||||||
updateGuiBoard();
|
updateGuiBoard();
|
||||||
}
|
}
|
||||||
|
private void time() {
|
||||||
|
engine.getWhiteTimer().setOnTick(secs -> gui.updateWhiteTimerLabel(secs));
|
||||||
|
engine.getBlackTimer().setOnTick(secs -> gui.updateBlackTimerLabel(secs));
|
||||||
|
engine.getWhiteTimer().setOnTimeout(() -> onTimeout("WHITE"));
|
||||||
|
engine.getBlackTimer().setOnTimeout(() -> onTimeout("BLACK"));
|
||||||
|
engine.getWhiteTimer().start();
|
||||||
|
}
|
||||||
private int flipRow(int row) {
|
private int flipRow(int row) {
|
||||||
return gui.isFlipped() ? 7 - row : row;
|
return gui.isFlipped() ? 7 - row : row;
|
||||||
}
|
}
|
||||||
|
@ -68,6 +83,25 @@ public class Controller {
|
||||||
engine.setPositionToMoveIndex(engine.getMoveListSize());
|
engine.setPositionToMoveIndex(engine.getMoveListSize());
|
||||||
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 -> {
|
||||||
|
@ -93,6 +127,9 @@ public class Controller {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleClick(int guiRow, int guiCol) {
|
private void handleClick(int guiRow, int guiCol) {
|
||||||
|
|
||||||
|
if (gameOver) return;
|
||||||
|
|
||||||
int modelRow = flipRow(guiRow);
|
int modelRow = flipRow(guiRow);
|
||||||
int modelCol = flipCol(guiCol);
|
int modelCol = flipCol(guiCol);
|
||||||
|
|
||||||
|
@ -125,7 +162,7 @@ public class Controller {
|
||||||
for (int[] xy : highlightedFields) {
|
for (int[] xy : highlightedFields) {
|
||||||
resetFieldBackground(xy[0], xy[1]);
|
resetFieldBackground(xy[0], xy[1]);
|
||||||
}
|
}
|
||||||
highlightedFields.clear();
|
highlightedFields.clear();
|
||||||
int oldGuiRow = gui.isFlipped() ? 7 - selectedRow : selectedRow;
|
int oldGuiRow = gui.isFlipped() ? 7 - selectedRow : selectedRow;
|
||||||
int oldGuiCol = gui.isFlipped() ? 7 - selectedCol : selectedCol;
|
int oldGuiCol = gui.isFlipped() ? 7 - selectedCol : selectedCol;
|
||||||
gui.getField(oldGuiRow, oldGuiCol).setBorder(null);
|
gui.getField(oldGuiRow, oldGuiCol).setBorder(null);
|
||||||
|
@ -137,43 +174,113 @@ public class Controller {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void handleMove(MoveDTO move) {
|
private void handleMove(MoveDTO move) {
|
||||||
if (engine.move(move)) {
|
|
||||||
updateGuiBoard();
|
if (gameOver) return;
|
||||||
|
|
||||||
//Züge in der MoveList aktualisieren
|
BoardDTO boardDTO = engine.getBoardAsDTO();
|
||||||
gui.updateMoveList(engine.getMoveListStringsGrouped());
|
PieceDTO piece = boardDTO.getBoard()[move.getFromRow()][move.getFromCol()];
|
||||||
|
boolean isPawn = piece != null && piece.getType().equals("PAWN");
|
||||||
//Spielstatus prüfen
|
boolean isWhitePromotion = isPawn && piece.getColor().equals("WHITE") && move.getToRow() == 0;
|
||||||
if (engine.isMated()) {
|
boolean isBlackPromotion = isPawn && piece.getColor().equals("BLACK") && move.getToRow() == 7;
|
||||||
String winner = engine.getCurrentPlayer().equals("WHITE") ? "SCHWARZ" : "WEIß";
|
|
||||||
gui.displayMessage(winner + " hat gewonnen (Schachmatt)!");
|
boolean success = false;
|
||||||
} else if (engine.isStalemate() || engine.isDraw()) {
|
|
||||||
gui.displayMessage("Remis! (Stalemate oder andere Regel)");
|
if (isWhitePromotion || isBlackPromotion) {
|
||||||
|
String color = piece.getColor().equals("WHITE") ? "Weiß" : "Schwarz";
|
||||||
|
String promotion = gui.showPromotionDialog(color);
|
||||||
|
success = engine.moveWithPromotion(move, promotion);
|
||||||
|
if (!success) {
|
||||||
|
gui.displayMessage("Ungültiger Promotionszug!");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
gui.displayMessage("Ungültiger Zug!");
|
success = engine.move(move);
|
||||||
|
if (!success) {
|
||||||
|
gui.displayMessage("Ungültiger Zug!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void updateGuiBoard() {
|
public void updateGuiBoard() {
|
||||||
BoardDTO board = engine.getBoardAsDTO();
|
BoardDTO board = engine.getBoardAsDTO();
|
||||||
gui.updateBoard(board);
|
gui.updateBoard(board);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void switchTimers() {
|
||||||
|
if (engine.getCurrentPlayer().equals("WHITE")) {
|
||||||
|
engine.getBlackTimer().stop();
|
||||||
|
engine.getWhiteTimer().start();
|
||||||
|
} else {
|
||||||
|
engine.getWhiteTimer().stop();
|
||||||
|
engine.getBlackTimer().start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Hilfsmethode, um von Koordinaten (row/col) auf z.B. "E2" zu kommen
|
// Hilfsmethode, um von Koordinaten (row/col) auf z.B. "E2" zu kommen
|
||||||
private String coordToChessNotation(int modelRow, int modelCol) {
|
private String coordToChessNotation(int modelRow, int modelCol) {
|
||||||
char file = (char)('A' + modelCol);
|
char file = (char)('A' + modelCol);
|
||||||
int rank = 8 - modelRow;
|
int rank = 8 - modelRow;
|
||||||
return "" + file + rank;
|
return "" + file + rank;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Timeout-Methode
|
||||||
private void resetFieldBackground(int row, int col) {
|
private void onTimeout(String color) {
|
||||||
if ((row + col) % 2 == 0) {
|
if (gameOver) return; // Doppelt hält besser
|
||||||
gui.getField(row, col).setBackground(new Color(0x778da9));
|
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 = javax.swing.JOptionPane.showConfirmDialog(
|
||||||
|
null,
|
||||||
|
"Neue Partie starten?",
|
||||||
|
"Spiel beendet",
|
||||||
|
javax.swing.JOptionPane.YES_NO_OPTION
|
||||||
|
);
|
||||||
|
javax.swing.SwingUtilities.getWindowAncestor(gui.getField(0, 0)).dispose();
|
||||||
|
if (answer == javax.swing.JOptionPane.YES_OPTION) {
|
||||||
|
callback.onNewGameRequested();
|
||||||
} else {
|
} else {
|
||||||
gui.getField(row, col).setBackground(new Color(0xe0e1dd));
|
callback.onReturnToMenu();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void resetFieldBackground(int row, int col) {
|
||||||
|
Color LIGHT = new Color(0xe0e1dd);
|
||||||
|
Color DARK = new Color(0x778da9);
|
||||||
|
if ((row + col) % 2 == 0) {
|
||||||
|
gui.getField(row, col).setBackground(LIGHT);
|
||||||
|
} else {
|
||||||
|
gui.getField(row, col).setBackground(DARK);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
package de.hs_mannheim.informatik.chess.controller;
|
||||||
|
|
||||||
|
public interface GameEndCallback {
|
||||||
|
void onNewGameRequested();
|
||||||
|
void onReturnToMenu();
|
||||||
|
}
|
|
@ -0,0 +1,72 @@
|
||||||
|
package de.hs_mannheim.informatik.chess.controller;
|
||||||
|
|
||||||
|
import de.hs_mannheim.informatik.chess.view.MainGui;
|
||||||
|
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 java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.swing.JFileChooser;
|
||||||
|
import javax.swing.JOptionPane;
|
||||||
|
|
||||||
|
import com.github.bhlangonijr.chesslib.game.Game;
|
||||||
|
|
||||||
|
import de.hs_mannheim.informatik.chess.model.ChessEngine;
|
||||||
|
|
||||||
|
public class MainController {
|
||||||
|
private MainGui mainGui;
|
||||||
|
|
||||||
|
public MainController() {
|
||||||
|
mainGui = new MainGui();
|
||||||
|
|
||||||
|
mainGui.setNormalModeListener(e -> startNormalMode());
|
||||||
|
mainGui.setCreativeModeListener(e -> startCreativeMode());
|
||||||
|
mainGui.setLoadGameListener(e -> startLoadGameMode());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void startNormalMode() {
|
||||||
|
mainGui.close();
|
||||||
|
GameGui gameGui = new GameGui();
|
||||||
|
ChessEngine engine = new ChessEngine();
|
||||||
|
GameEndCallback callback = new GameEndCallback() {
|
||||||
|
public void onNewGameRequested() {
|
||||||
|
startNormalMode();
|
||||||
|
}
|
||||||
|
public void onReturnToMenu() {
|
||||||
|
new MainController();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
new GameController(gameGui, engine, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void startCreativeMode() {
|
||||||
|
mainGui.close();
|
||||||
|
CreativeGui creativegui = new CreativeGui();
|
||||||
|
ChessEngine engine = new ChessEngine();
|
||||||
|
new CreativeController(creativegui, engine);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void startLoadGameMode() {
|
||||||
|
JFileChooser chooser = new JFileChooser();
|
||||||
|
int result = chooser.showOpenDialog(null);
|
||||||
|
if (result == JFileChooser.APPROVE_OPTION) {
|
||||||
|
String path = chooser.getSelectedFile().getAbsolutePath();
|
||||||
|
ChessEngine engine = new ChessEngine();
|
||||||
|
try {
|
||||||
|
List<Game> games = engine.loadGamesFromPgn(path);
|
||||||
|
// Jetzt Auswahl-GUI öffnen!
|
||||||
|
new PgnSelectionGui(games, selectedGame -> {
|
||||||
|
// Callback wenn User eins ausgewählt hat!
|
||||||
|
PgnGui pgnGui = new PgnGui();
|
||||||
|
engine.loadMoves(selectedGame.getHalfMoves());
|
||||||
|
new PgnController(pgnGui, engine);
|
||||||
|
});
|
||||||
|
} catch (IOException ex) {
|
||||||
|
JOptionPane.showMessageDialog(null, "Fehler beim Laden der PGN-Datei:\n" + ex.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,82 @@
|
||||||
|
package de.hs_mannheim.informatik.chess.controller;
|
||||||
|
|
||||||
|
import java.awt.Color;
|
||||||
|
|
||||||
|
import de.hs_mannheim.informatik.chess.model.ChessEngine;
|
||||||
|
import de.hs_mannheim.informatik.chess.model.BoardDTO;
|
||||||
|
import de.hs_mannheim.informatik.chess.view.PgnGui;
|
||||||
|
|
||||||
|
public class PgnController {
|
||||||
|
PgnGui gui;
|
||||||
|
ChessEngine engine;
|
||||||
|
|
||||||
|
|
||||||
|
public PgnController(PgnGui pgngui, ChessEngine engine) {
|
||||||
|
this.gui = pgngui;
|
||||||
|
this.engine = engine;
|
||||||
|
initListeners();
|
||||||
|
updateGuiBoard();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initListeners() {
|
||||||
|
// Erster Zug
|
||||||
|
gui.getBtnFirst().addActionListener(e -> {
|
||||||
|
engine.setPositionToMoveIndex(0);
|
||||||
|
updateGuiBoard();
|
||||||
|
});
|
||||||
|
// Ein Zug zurück
|
||||||
|
gui.getBtnPrev().addActionListener(e -> {
|
||||||
|
int idx = Math.max(0, engine.getCurrentMoveIndex() - 1);
|
||||||
|
engine.setPositionToMoveIndex(idx);
|
||||||
|
updateGuiBoard();
|
||||||
|
});
|
||||||
|
// Ein Zug vor
|
||||||
|
gui.getBtnNext().addActionListener(e -> {
|
||||||
|
int idx = Math.min(engine.getMoveListSize(), engine.getCurrentMoveIndex() + 1);
|
||||||
|
engine.setPositionToMoveIndex(idx);
|
||||||
|
updateGuiBoard();
|
||||||
|
});
|
||||||
|
// Letzter Zug
|
||||||
|
gui.getBtnLast().addActionListener(e -> {
|
||||||
|
engine.setPositionToMoveIndex(engine.getMoveListSize());
|
||||||
|
updateGuiBoard();
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
gui.getFlipBoardButton().addActionListener(e -> {
|
||||||
|
//ALLE Highlights und Borders zurücksetzen
|
||||||
|
for (int row = 0; row < 8; row++) {
|
||||||
|
for (int col = 0; col < 8; col++) {
|
||||||
|
resetFieldBackground(row, col);
|
||||||
|
gui.getField(row, col).setBorder(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Flip-Zustand ändern
|
||||||
|
gui.setFlipped(!gui.isFlipped());
|
||||||
|
|
||||||
|
// 3. Board neu zeichnen
|
||||||
|
updateGuiBoard();
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateGuiBoard() {
|
||||||
|
BoardDTO board = engine.getBoardAsDTO();
|
||||||
|
gui.updateBoard(board);
|
||||||
|
gui.updateMoveList(engine.getMoveListStringsGrouped());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void resetFieldBackground(int row, int col) {
|
||||||
|
Color LIGHT = new Color(0xe0e1dd);
|
||||||
|
Color DARK = new Color(0x778da9);
|
||||||
|
if ((row + col) % 2 == 0) {
|
||||||
|
gui.getField(row, col).setBackground(LIGHT);
|
||||||
|
} else {
|
||||||
|
gui.getField(row, col).setBackground(DARK);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -1,19 +1,12 @@
|
||||||
package de.hs_mannheim.informatik.chess.main;
|
package de.hs_mannheim.informatik.chess.main;
|
||||||
import de.hs_mannheim.informatik.chess.controller.Controller;
|
import de.hs_mannheim.informatik.chess.controller.MainController;
|
||||||
import de.hs_mannheim.informatik.chess.model.ChessEngine;
|
|
||||||
import de.hs_mannheim.informatik.chess.view.GameGui;
|
|
||||||
import de.hs_mannheim.informatik.chess.view.MainGui;
|
|
||||||
|
|
||||||
|
|
||||||
public class Main{
|
public class Main{
|
||||||
|
|
||||||
public static void main( String[] args ){
|
public static void main( String[] args ){
|
||||||
new MainGui(() -> {
|
new MainController();
|
||||||
//Wenn "Normal Modus" gedrückt wird
|
|
||||||
GameGui gui = new GameGui();
|
|
||||||
ChessEngine engine = new ChessEngine();
|
|
||||||
new Controller(gui, engine);
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,8 @@
|
||||||
package de.hs_mannheim.informatik.chess.model;
|
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.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.logging.ConsoleHandler;
|
import java.util.logging.ConsoleHandler;
|
||||||
|
@ -11,6 +15,12 @@ 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.move.Move;
|
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 {
|
public class ChessEngine {
|
||||||
private Board board;
|
private Board board;
|
||||||
|
@ -18,6 +28,8 @@ public class ChessEngine {
|
||||||
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 blackTimer;
|
||||||
|
|
||||||
public ChessEngine() {
|
public ChessEngine() {
|
||||||
logging();
|
logging();
|
||||||
|
@ -87,6 +99,37 @@ public class ChessEngine {
|
||||||
return convertPieceToDTO(piece);
|
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());
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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++;
|
||||||
|
logger.info("Promotionszug durchgeführt: " + libMove);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
logger.warning("Ungültiger Promotionszug: " + libMove);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public BoardDTO getBoardAsDTO() {
|
public BoardDTO getBoardAsDTO() {
|
||||||
logger.info("Erstelle DTO-Abbild des Boards");
|
logger.info("Erstelle DTO-Abbild des Boards");
|
||||||
PieceDTO[][] dtoBoard = new PieceDTO[8][8];
|
PieceDTO[][] dtoBoard = new PieceDTO[8][8];
|
||||||
|
@ -146,6 +189,11 @@ public class ChessEngine {
|
||||||
return new PieceDTO(type, color, symbol);
|
return new PieceDTO(type, color, symbol);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setPositionFromFEN(String fen) {
|
||||||
|
board.loadFromFen(fen);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public boolean isMated() {
|
public boolean isMated() {
|
||||||
boolean mated = board.isMated();
|
boolean mated = board.isMated();
|
||||||
logger.info("isMated() = " + mated);
|
logger.info("isMated() = " + mated);
|
||||||
|
@ -186,10 +234,142 @@ public class ChessEngine {
|
||||||
|
|
||||||
logger.info("ChessEngine wurde initialisiert.");
|
logger.info("ChessEngine wurde initialisiert.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<Game> loadGamesFromPgn(String path) throws IOException {
|
||||||
|
|
||||||
|
PgnHolder pgnHolder = new PgnHolder(path);
|
||||||
|
try {
|
||||||
|
pgnHolder.loadPgn();
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
List<Game> games = pgnHolder.getGames();
|
||||||
|
return games;
|
||||||
|
}
|
||||||
|
|
||||||
public void setPositionFromFEN(String fen) {
|
public void initTimers(int min, int sec) {
|
||||||
board.loadFromFen(fen);
|
whiteTimer = new Timer(min, sec);
|
||||||
|
blackTimer = new Timer(min, sec);
|
||||||
|
}
|
||||||
|
|
||||||
|
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());
|
||||||
|
|
||||||
|
// 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");
|
||||||
|
|
||||||
|
// Züge als SAN holen
|
||||||
|
StringBuilder moves = new StringBuilder();
|
||||||
|
String[] sanArray = game.getHalfMoves().toSanArray();
|
||||||
|
|
||||||
|
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!
|
||||||
|
|
||||||
|
String file = header + moves.toString();
|
||||||
|
|
||||||
|
// Datei schreiben
|
||||||
|
try {
|
||||||
|
Files.writeString(Path.of(path, dateiname), file, StandardCharsets.UTF_8);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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 loadMoves(List<Move> moveList) {
|
||||||
|
board = new Board(); // Neues leeres Brett
|
||||||
|
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; }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,61 @@
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,177 @@
|
||||||
|
package de.hs_mannheim.informatik.chess.view;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
import java.awt.*;
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
public class CreativeGui {
|
||||||
|
private boolean isFlipped = false;
|
||||||
|
|
||||||
|
private JFrame frame;
|
||||||
|
private JLabel[][] fields = new JLabel[8][8];
|
||||||
|
private String selectedPiece = null;
|
||||||
|
private JTextField fenField;
|
||||||
|
private JButton updateBtn;
|
||||||
|
private JButton flipBoardButton;
|
||||||
|
|
||||||
|
public static final HashMap<String, String> UNICODE_MAP = new HashMap<String, String>() {{
|
||||||
|
put("BLACK_KING", "\u265A"); put("BLACK_QUEEN", "\u265B");
|
||||||
|
put("BLACK_ROOK", "\u265C"); put("BLACK_BISHOP", "\u265D");
|
||||||
|
put("BLACK_KNIGHT", "\u265E"); put("BLACK_PAWN", "\u265F");
|
||||||
|
put("WHITE_KING", "\u2654"); put("WHITE_QUEEN", "\u2655");
|
||||||
|
put("WHITE_ROOK", "\u2656"); put("WHITE_BISHOP", "\u2657");
|
||||||
|
put("WHITE_KNIGHT", "\u2658"); put("WHITE_PAWN", "\u2659");
|
||||||
|
put("ERASER", "\u2716");
|
||||||
|
}};
|
||||||
|
|
||||||
|
private final Color LIGHT = new Color(0xe0e1dd);
|
||||||
|
private final Color DARK = new Color(0x778da9);
|
||||||
|
|
||||||
|
public CreativeGui() {
|
||||||
|
frame = new JFrame("Creative Mode");
|
||||||
|
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
|
||||||
|
frame.setSize(1600, 1200);
|
||||||
|
frame.setLocationRelativeTo(null);
|
||||||
|
|
||||||
|
JPanel mainPanel = new JPanel(new GridBagLayout());
|
||||||
|
mainPanel.setBackground(LIGHT);
|
||||||
|
GridBagConstraints gbc = new GridBagConstraints();
|
||||||
|
|
||||||
|
// LINKS: chessPanel (Board+Toolbars)
|
||||||
|
gbc.gridx = 0;
|
||||||
|
gbc.gridy = 0;
|
||||||
|
gbc.weightx = 0.6;
|
||||||
|
gbc.weighty = 1.0;
|
||||||
|
gbc.insets = new Insets(5, 5, 5, 0);
|
||||||
|
gbc.fill = GridBagConstraints.BOTH;
|
||||||
|
mainPanel.add(chessPanel(), gbc);
|
||||||
|
|
||||||
|
// RECHTS: FEN & Optionen
|
||||||
|
gbc.gridx = 1;
|
||||||
|
gbc.gridy = 0;
|
||||||
|
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.setContentPane(mainPanel);
|
||||||
|
frame.setVisible(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private JPanel toolbarPanel(boolean white) {
|
||||||
|
JPanel panel = new JPanel();
|
||||||
|
panel.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
|
||||||
|
panel.setBackground(new Color(0x1b263b));
|
||||||
|
String prefix = white ? "WHITE_" : "BLACK_";
|
||||||
|
String[] pieces = {"KING", "QUEEN", "ROOK", "BISHOP", "KNIGHT", "PAWN"};
|
||||||
|
for (String type : pieces) {
|
||||||
|
JButton btn = new JButton(UNICODE_MAP.get(prefix + type));
|
||||||
|
btn.setFont(new Font("Serif", Font.BOLD, 40));
|
||||||
|
btn.setFocusPainted(false);
|
||||||
|
btn.setPreferredSize(new Dimension(70, 70));
|
||||||
|
btn.setBackground(white ? LIGHT : DARK);
|
||||||
|
btn.setBorder(BorderFactory.createEmptyBorder(20, 0, 20, 0));
|
||||||
|
String key = prefix + type;
|
||||||
|
btn.addActionListener(e -> selectedPiece = key);
|
||||||
|
panel.add(btn);
|
||||||
|
}
|
||||||
|
JButton del = new JButton(UNICODE_MAP.get("ERASER"));
|
||||||
|
del.setFont(new Font("Serif", Font.BOLD, 36));
|
||||||
|
del.setBackground(Color.PINK);
|
||||||
|
del.setPreferredSize(new Dimension(70, 70));
|
||||||
|
del.setFocusPainted(false);
|
||||||
|
del.addActionListener(e -> selectedPiece = "ERASER");
|
||||||
|
panel.add(del);
|
||||||
|
|
||||||
|
return panel;
|
||||||
|
}
|
||||||
|
|
||||||
|
private JPanel boardPanel() {
|
||||||
|
JPanel boardPanel = new JPanel(new GridLayout(8, 8));
|
||||||
|
boardPanel.setPreferredSize(new Dimension(800, 800));
|
||||||
|
for (int row = 0; row < 8; row++) {
|
||||||
|
for (int col = 0; col < 8; col++) {
|
||||||
|
JLabel label = new JLabel("", SwingConstants.CENTER);
|
||||||
|
label.setOpaque(true);
|
||||||
|
label.setFont(new Font("Serif", Font.BOLD, 70));
|
||||||
|
label.setBackground((row + col) % 2 == 0 ? LIGHT : DARK);
|
||||||
|
fields[row][col] = label;
|
||||||
|
boardPanel.add(label);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return boardPanel;
|
||||||
|
}
|
||||||
|
|
||||||
|
private JPanel chessPanel() {
|
||||||
|
JPanel chessPanel = new JPanel(new GridBagLayout());
|
||||||
|
chessPanel.setBackground(new Color(0x1b263b));
|
||||||
|
GridBagConstraints gbc = new GridBagConstraints();
|
||||||
|
|
||||||
|
// Toolbar oben
|
||||||
|
gbc.gridx = 0;
|
||||||
|
gbc.gridy = 0;
|
||||||
|
gbc.fill = GridBagConstraints.HORIZONTAL;
|
||||||
|
chessPanel.add(toolbarPanel(false), gbc);
|
||||||
|
|
||||||
|
// Board
|
||||||
|
gbc.gridx = 0;
|
||||||
|
gbc.gridy = 1;
|
||||||
|
gbc.fill = GridBagConstraints.BOTH;
|
||||||
|
chessPanel.add(boardPanel(), gbc);
|
||||||
|
|
||||||
|
// Toolbar unten
|
||||||
|
gbc.gridx = 0;
|
||||||
|
gbc.gridy = 2;
|
||||||
|
gbc.fill = GridBagConstraints.HORIZONTAL;
|
||||||
|
chessPanel.add(toolbarPanel(true), gbc);
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
private JPanel fenPanel() {
|
||||||
|
JPanel panel = new JPanel();
|
||||||
|
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
|
||||||
|
panel.setBackground(new Color(0xe0e1dd));
|
||||||
|
panel.setPreferredSize(new Dimension(420, 40));
|
||||||
|
panel.add(new JLabel("FEN:"));
|
||||||
|
fenField = new JTextField("");
|
||||||
|
fenField.setFont(new Font("Monospaced", Font.PLAIN, 22));
|
||||||
|
fenField.setMaximumSize(new Dimension(600, 50));
|
||||||
|
panel.add(fenField);
|
||||||
|
updateBtn = new JButton("Update Board");
|
||||||
|
updateBtn.setAlignmentX(Component.CENTER_ALIGNMENT);
|
||||||
|
panel.add(updateBtn);
|
||||||
|
return panel;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Für Controller
|
||||||
|
public JLabel[][] getFields() { return fields; }
|
||||||
|
public String getFenText() { return fenField.getText(); }
|
||||||
|
public void setFenText(String fen) { fenField.setText(fen); }
|
||||||
|
public JTextField getFenField() { return fenField; }
|
||||||
|
public JButton getUpdateButton() { return updateBtn; }
|
||||||
|
public void setSelectedPiece(String piece) { selectedPiece = piece; }
|
||||||
|
public String getSelectedPiece() { return selectedPiece; }
|
||||||
|
|
||||||
|
public boolean isFlipped() { return isFlipped; }
|
||||||
|
public void setFlipped(boolean f) { isFlipped = f; }
|
||||||
|
public JButton getFlipBoardButton() { return flipBoardButton; }
|
||||||
|
}
|
|
@ -27,12 +27,19 @@ 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 blackTimerLabel;
|
||||||
|
|
||||||
JButton btnFirst = new JButton("|<");
|
JButton btnFirst = new JButton("|<");
|
||||||
JButton btnPrev = new JButton("<");
|
JButton btnPrev = new JButton("<");
|
||||||
JButton btnNext = new JButton(">");
|
JButton btnNext = new JButton(">");
|
||||||
JButton btnLast = new JButton(">|");
|
JButton btnLast = new JButton(">|");
|
||||||
|
|
||||||
|
Color LIGHT = new Color(0xe0e1dd);
|
||||||
|
Color DARK = new Color(0x778da9);
|
||||||
|
|
||||||
private JPanel moveListPanel;
|
private JPanel moveListPanel;
|
||||||
private JScrollPane moveListScroll;
|
private JScrollPane moveListScroll;
|
||||||
|
|
||||||
|
@ -54,20 +61,21 @@ public class GameGui {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initFields() {
|
private void initFields() {
|
||||||
for (int row = 0; row < 8; row++) {
|
for (int row = 0; row < 8; row++) {
|
||||||
for (int col = 0; col < 8; col++) {
|
for (int col = 0; col < 8; col++) {
|
||||||
JLabel label = new JLabel("", SwingConstants.CENTER);
|
JLabel label = new JLabel("", SwingConstants.CENTER);
|
||||||
label.setOpaque(true);
|
label.setOpaque(true);
|
||||||
label.setFont(new Font("Serif", Font.BOLD, 40));
|
label.setFont(new Font("Serif", Font.BOLD, 40));
|
||||||
if ((row + col) % 2 == 0) {
|
// Richtige Schachfärbung:
|
||||||
label.setBackground(new Color(0x778da9));
|
if ((row + col) % 2 == 0) {
|
||||||
} else {
|
label.setBackground(LIGHT); // a1 ist jetzt hell!
|
||||||
label.setBackground(new Color(0xe0e1dd));
|
} else {
|
||||||
}
|
label.setBackground(DARK);
|
||||||
fields[row][col] = label;
|
}
|
||||||
}
|
fields[row][col] = label;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public JPanel mainPanel() {
|
public JPanel mainPanel() {
|
||||||
JPanel mainPanel = new JPanel(new GridBagLayout());
|
JPanel mainPanel = new JPanel(new GridBagLayout());
|
||||||
|
@ -97,29 +105,27 @@ public class GameGui {
|
||||||
}
|
}
|
||||||
|
|
||||||
public JPanel boardPanel() {
|
public JPanel boardPanel() {
|
||||||
JPanel boardPanel = new JPanel(new GridLayout(8, 8));
|
JPanel boardPanel = new JPanel(new GridLayout(8, 8));
|
||||||
boardPanel.setPreferredSize(new Dimension(800, 800));
|
boardPanel.setPreferredSize(new Dimension(800, 800));
|
||||||
|
|
||||||
for (int row = 0; row < 8; row++) {
|
for (int row = 0; row < 8; row++) {
|
||||||
|
for (int col = 0; col < 8; col++) {
|
||||||
for (int col = 0; col < 8; col++) {
|
JLabel label = new JLabel("", SwingConstants.CENTER);
|
||||||
|
label.setOpaque(true);
|
||||||
JLabel label = new JLabel("", SwingConstants.CENTER);
|
label.setFont(new Font("Serif", Font.BOLD, 70));
|
||||||
label.setOpaque(true);
|
// Richtige Schachfärbung:
|
||||||
label.setFont(new Font("Serif", Font.BOLD, 70));
|
if ((row + col) % 2 == 0) {
|
||||||
if ((row + col) % 2 == 0) {
|
label.setBackground(LIGHT);
|
||||||
label.setBackground(new Color(0x778da9));
|
} else {
|
||||||
} else {
|
label.setBackground(DARK);
|
||||||
label.setBackground(new Color(0xe0e1dd));
|
}
|
||||||
}
|
fields[row][col] = label;
|
||||||
fields[row][col] = label; // <-- Save the label
|
boardPanel.add(label);
|
||||||
boardPanel.add(label);
|
}
|
||||||
|
}
|
||||||
}
|
boardPanel.setBackground(new Color(0x1b263b));
|
||||||
}
|
return boardPanel;
|
||||||
boardPanel.setBackground(new Color(0x1b263b));
|
}
|
||||||
return boardPanel;
|
|
||||||
}
|
|
||||||
|
|
||||||
public JPanel chessPanel(JPanel panel) {
|
public JPanel chessPanel(JPanel panel) {
|
||||||
JPanel chessPanel = new JPanel(new GridBagLayout());
|
JPanel chessPanel = new JPanel(new GridBagLayout());
|
||||||
|
@ -158,7 +164,10 @@ public class GameGui {
|
||||||
JPanel statsPanel = new JPanel(new BorderLayout());
|
JPanel statsPanel = new JPanel(new BorderLayout());
|
||||||
statsPanel.setBackground(new Color(0x0d1b2a));
|
statsPanel.setBackground(new Color(0x0d1b2a));
|
||||||
|
|
||||||
// Move-Liste (scrollbar, wie gehabt)
|
// Panel für die Timer (NORD)
|
||||||
|
statsPanel.add(timerPanel(), BorderLayout.NORTH);
|
||||||
|
|
||||||
|
// Move-Liste
|
||||||
moveListPanel = new JPanel();
|
moveListPanel = new JPanel();
|
||||||
moveListPanel.setLayout(new BoxLayout(moveListPanel, BoxLayout.Y_AXIS));
|
moveListPanel.setLayout(new BoxLayout(moveListPanel, BoxLayout.Y_AXIS));
|
||||||
moveListPanel.setBackground(new Color(0x0d1b2a));
|
moveListPanel.setBackground(new Color(0x0d1b2a));
|
||||||
|
@ -166,30 +175,67 @@ public class GameGui {
|
||||||
moveListScroll.setPreferredSize(new Dimension(250, 800));
|
moveListScroll.setPreferredSize(new Dimension(250, 800));
|
||||||
statsPanel.add(moveListScroll, BorderLayout.CENTER);
|
statsPanel.add(moveListScroll, BorderLayout.CENTER);
|
||||||
|
|
||||||
// Button-Leiste
|
// Button-Leiste (SÜD)
|
||||||
JPanel buttonPanel = new JPanel();
|
JPanel buttonPanel = new JPanel();
|
||||||
buttonPanel.setBackground(new Color(0x0d1b2a));
|
buttonPanel.setBackground(new Color(0x0d1b2a));
|
||||||
// Grid oder Flow – je nach Geschmack
|
buttonPanel.setLayout(new GridLayout(1, 5, 10, 0)); // Jetzt 5 statt 4 Spalten!
|
||||||
buttonPanel.setLayout(new GridLayout(1, 4, 10, 0));
|
|
||||||
|
|
||||||
// Style (optional)
|
|
||||||
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);
|
||||||
// Hinzufügen
|
|
||||||
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);
|
||||||
// Unten ins BorderLayout
|
|
||||||
statsPanel.add(buttonPanel, BorderLayout.SOUTH);
|
statsPanel.add(buttonPanel, BorderLayout.SOUTH);
|
||||||
|
|
||||||
return statsPanel;
|
return statsPanel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private JPanel timerPanel() {
|
||||||
|
JPanel panel = new JPanel(new GridLayout(2, 1));
|
||||||
|
panel.setBackground(new Color(0x0d1b2a));
|
||||||
|
|
||||||
|
whiteTimerLabel = new JLabel("Weiß: 03:00", SwingConstants.CENTER);
|
||||||
|
blackTimerLabel = new JLabel("Schwarz: 03:00", 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"};
|
||||||
|
String choice = (String) JOptionPane.showInputDialog(
|
||||||
|
null,
|
||||||
|
color + "er Bauer wird umgewandelt – wähle Figur:",
|
||||||
|
"Bauernumwandlung",
|
||||||
|
JOptionPane.PLAIN_MESSAGE,
|
||||||
|
null,
|
||||||
|
choices,
|
||||||
|
choices[0]);
|
||||||
|
if (choice == null) return "QUEEN";
|
||||||
|
switch (choice) {
|
||||||
|
case "Turm": return "ROOK";
|
||||||
|
case "Springer": return "KNIGHT";
|
||||||
|
case "Läufer": return "BISHOP";
|
||||||
|
default: return "QUEEN";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void updateMoveList(List<String> moves) {
|
public void updateMoveList(List<String> moves) {
|
||||||
moveListPanel.removeAll();
|
moveListPanel.removeAll();
|
||||||
|
@ -223,6 +269,7 @@ 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 void updateBoard(BoardDTO boardDTO) {
|
public void updateBoard(BoardDTO boardDTO) {
|
||||||
PieceDTO[][] board = boardDTO.getBoard();
|
PieceDTO[][] board = boardDTO.getBoard();
|
||||||
|
@ -244,6 +291,24 @@ 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 displayMessage(String msg) {
|
public void displayMessage(String msg) {
|
||||||
JOptionPane.showMessageDialog(null, msg);
|
JOptionPane.showMessageDialog(null, msg);
|
||||||
|
|
|
@ -1,15 +1,19 @@
|
||||||
package de.hs_mannheim.informatik.chess.view;
|
package de.hs_mannheim.informatik.chess.view;
|
||||||
|
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
|
import java.awt.event.ActionListener;
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
|
|
||||||
public class MainGui {
|
public class MainGui {
|
||||||
|
|
||||||
private JFrame frame;
|
private JFrame frame;
|
||||||
private Runnable onStartGame;
|
|
||||||
|
|
||||||
public MainGui(Runnable onStartGame) {
|
JButton btnMode1 = new JButton("Normal Mode");
|
||||||
this.onStartGame = onStartGame;
|
JButton btnCreative = new JButton("Creative Mode");
|
||||||
|
JButton btnLoadGame = new JButton("Load Game (PGN)");
|
||||||
|
|
||||||
|
public MainGui() {
|
||||||
|
|
||||||
frame = new JFrame("Chess - Hauptmenü");
|
frame = new JFrame("Chess - Hauptmenü");
|
||||||
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||||
|
@ -38,44 +42,38 @@ public class MainGui {
|
||||||
gbc.ipady = 15;
|
gbc.ipady = 15;
|
||||||
mainPanel.add(Box.createRigidArea(new Dimension(0, 20)), gbc);
|
mainPanel.add(Box.createRigidArea(new Dimension(0, 20)), gbc);
|
||||||
|
|
||||||
//Buttons
|
|
||||||
JButton btnMode1 = new JButton("Normal Mode");
|
|
||||||
JButton btnMode2 = new JButton("Mode 2 (coming soon)");
|
|
||||||
JButton btnMode3 = new JButton("Mode 3 (coming soon)");
|
|
||||||
JButton btnCreative = new JButton("Creative Mode");
|
|
||||||
JButton btnLoadGame = new JButton("Load Game (PGN)");
|
|
||||||
|
|
||||||
styleButton(btnMode1);
|
styleButton(btnMode1);
|
||||||
styleButton(btnMode2);
|
|
||||||
styleButton(btnMode3);
|
|
||||||
styleButton(btnCreative);
|
styleButton(btnCreative);
|
||||||
styleButton(btnLoadGame);
|
styleButton(btnLoadGame);
|
||||||
|
|
||||||
gbc.gridy = 2; gbc.ipady = 25;
|
gbc.gridy = 1; gbc.ipady = 25;
|
||||||
mainPanel.add(btnMode1, gbc);
|
mainPanel.add(btnMode1, gbc);
|
||||||
|
|
||||||
gbc.gridy = 3;
|
|
||||||
mainPanel.add(btnMode2, gbc);
|
|
||||||
|
|
||||||
gbc.gridy = 4;
|
|
||||||
mainPanel.add(btnMode3, gbc);
|
|
||||||
|
|
||||||
gbc.gridy = 5;
|
gbc.gridy = 2;
|
||||||
mainPanel.add(btnCreative, gbc);
|
mainPanel.add(btnCreative, gbc);
|
||||||
|
|
||||||
gbc.gridy = 6;
|
gbc.gridy = 3;
|
||||||
mainPanel.add(btnLoadGame, gbc);
|
mainPanel.add(btnLoadGame, gbc);
|
||||||
|
|
||||||
frame.add(mainPanel);
|
frame.add(mainPanel);
|
||||||
frame.setVisible(true);
|
frame.setVisible(true);
|
||||||
|
|
||||||
//Button ActionListener für "Normal Modus"
|
}
|
||||||
btnMode1.addActionListener(e -> {
|
// --- Methoden für Controller zum Setzen der Listener ---
|
||||||
frame.dispose(); // Hauptmenü schließen
|
public void setNormalModeListener(ActionListener l) {
|
||||||
onStartGame.run(); // **Ruft den Callback auf**
|
btnMode1.addActionListener(l);
|
||||||
});
|
}
|
||||||
|
public void setCreativeModeListener(ActionListener l) {
|
||||||
|
btnCreative.addActionListener(l);
|
||||||
|
}
|
||||||
|
public void setLoadGameListener(ActionListener l) {
|
||||||
|
btnLoadGame.addActionListener(l);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void close() {
|
||||||
|
frame.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
// Helper für Button Styling
|
// Helper für Button Styling
|
||||||
private void styleButton(JButton btn) {
|
private void styleButton(JButton btn) {
|
||||||
btn.setFont(new Font("Serif", Font.BOLD, 30));
|
btn.setFont(new Font("Serif", Font.BOLD, 30));
|
||||||
|
|
|
@ -0,0 +1,273 @@
|
||||||
|
package de.hs_mannheim.informatik.chess.view;
|
||||||
|
|
||||||
|
import java.awt.BorderLayout;
|
||||||
|
import java.awt.Color;
|
||||||
|
import java.awt.Dimension;
|
||||||
|
import java.awt.Font;
|
||||||
|
import java.awt.GridBagConstraints;
|
||||||
|
import java.awt.GridBagLayout;
|
||||||
|
import java.awt.GridLayout;
|
||||||
|
import java.awt.Insets;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.swing.BoxLayout;
|
||||||
|
import javax.swing.JButton;
|
||||||
|
import javax.swing.JFrame;
|
||||||
|
import javax.swing.JLabel;
|
||||||
|
import javax.swing.JOptionPane;
|
||||||
|
import javax.swing.JPanel;
|
||||||
|
import javax.swing.JScrollPane;
|
||||||
|
import javax.swing.SwingConstants;
|
||||||
|
|
||||||
|
import de.hs_mannheim.informatik.chess.model.BoardDTO;
|
||||||
|
import de.hs_mannheim.informatik.chess.model.PieceDTO;
|
||||||
|
|
||||||
|
public class PgnGui {
|
||||||
|
|
||||||
|
private JLabel[][] fields = new JLabel[8][8];
|
||||||
|
private JButton flipBoardButton;
|
||||||
|
private boolean isFlipped = false;
|
||||||
|
|
||||||
|
JButton btnFirst = new JButton("|<");
|
||||||
|
JButton btnPrev = new JButton("<");
|
||||||
|
JButton btnNext = new JButton(">");
|
||||||
|
JButton btnLast = new JButton(">|");
|
||||||
|
|
||||||
|
Color LIGHT = new Color(0xe0e1dd);
|
||||||
|
Color DARK = new Color(0x778da9);
|
||||||
|
|
||||||
|
private JPanel moveListPanel;
|
||||||
|
private JScrollPane moveListScroll;
|
||||||
|
|
||||||
|
public PgnGui(){
|
||||||
|
initFields();
|
||||||
|
mainFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public JFrame mainFrame() {
|
||||||
|
JFrame frame = new JFrame();
|
||||||
|
frame.setSize(1600, 1000);
|
||||||
|
frame.setLocationRelativeTo(null);
|
||||||
|
frame.add(mainPanel());
|
||||||
|
|
||||||
|
frame.setDefaultCloseOperation(2);
|
||||||
|
frame.setVisible(true);
|
||||||
|
return frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initFields() {
|
||||||
|
for (int row = 0; row < 8; row++) {
|
||||||
|
for (int col = 0; col < 8; col++) {
|
||||||
|
JLabel label = new JLabel("", SwingConstants.CENTER);
|
||||||
|
label.setOpaque(true);
|
||||||
|
label.setFont(new Font("Serif", Font.BOLD, 40));
|
||||||
|
// Richtige Schachfärbung:
|
||||||
|
if ((row + col) % 2 == 0) {
|
||||||
|
label.setBackground(LIGHT); // a1 ist jetzt hell!
|
||||||
|
} else {
|
||||||
|
label.setBackground(DARK);
|
||||||
|
}
|
||||||
|
fields[row][col] = label;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public JPanel mainPanel() {
|
||||||
|
JPanel mainPanel = new JPanel(new GridBagLayout());
|
||||||
|
GridBagConstraints gbc = new GridBagConstraints();
|
||||||
|
mainPanel.setBackground(new Color(0xe0e1dd));
|
||||||
|
// Links (Schach)
|
||||||
|
gbc.gridx = 0;
|
||||||
|
gbc.gridy = 0;
|
||||||
|
gbc.weightx = 0.6;
|
||||||
|
gbc.weighty = 1.0;
|
||||||
|
gbc.insets = new Insets(5, 5, 5, 0);
|
||||||
|
//oben, links, unten, rechts
|
||||||
|
gbc.fill = GridBagConstraints.BOTH;
|
||||||
|
mainPanel.add(chessPanel(boardPanel()), gbc);
|
||||||
|
|
||||||
|
// Rechts (Stats)
|
||||||
|
gbc.gridx = 1;
|
||||||
|
gbc.gridy = 0;
|
||||||
|
gbc.weightx = 0.4;
|
||||||
|
gbc.weighty = 1.0;
|
||||||
|
gbc.insets = new Insets(5, 0, 5, 5);
|
||||||
|
//oben, links, unten, rechts
|
||||||
|
gbc.fill = GridBagConstraints.BOTH;
|
||||||
|
mainPanel.add(statsPanel(), gbc);
|
||||||
|
|
||||||
|
return mainPanel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public JPanel boardPanel() {
|
||||||
|
JPanel boardPanel = new JPanel(new GridLayout(8, 8));
|
||||||
|
boardPanel.setPreferredSize(new Dimension(800, 800));
|
||||||
|
|
||||||
|
for (int row = 0; row < 8; row++) {
|
||||||
|
for (int col = 0; col < 8; col++) {
|
||||||
|
JLabel label = new JLabel("", SwingConstants.CENTER);
|
||||||
|
label.setOpaque(true);
|
||||||
|
label.setFont(new Font("Serif", Font.BOLD, 70));
|
||||||
|
// Richtige Schachfärbung:
|
||||||
|
if ((row + col) % 2 == 0) {
|
||||||
|
label.setBackground(LIGHT);
|
||||||
|
} else {
|
||||||
|
label.setBackground(DARK);
|
||||||
|
}
|
||||||
|
fields[row][col] = label;
|
||||||
|
boardPanel.add(label);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
boardPanel.setBackground(new Color(0x1b263b));
|
||||||
|
return boardPanel;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
chessPanel.add(flipBoardButton, btn);
|
||||||
|
|
||||||
|
return chessPanel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public JPanel statsPanel() {
|
||||||
|
JPanel statsPanel = new JPanel(new BorderLayout());
|
||||||
|
statsPanel.setBackground(new Color(0x0d1b2a));
|
||||||
|
|
||||||
|
// Move-Liste
|
||||||
|
moveListPanel = new JPanel();
|
||||||
|
moveListPanel.setLayout(new BoxLayout(moveListPanel, BoxLayout.Y_AXIS));
|
||||||
|
moveListPanel.setBackground(new Color(0x0d1b2a));
|
||||||
|
moveListScroll = new JScrollPane(moveListPanel);
|
||||||
|
moveListScroll.setPreferredSize(new Dimension(250, 800));
|
||||||
|
statsPanel.add(moveListScroll, BorderLayout.CENTER);
|
||||||
|
|
||||||
|
// Button-Leiste
|
||||||
|
JPanel buttonPanel = new JPanel();
|
||||||
|
buttonPanel.setBackground(new Color(0x0d1b2a));
|
||||||
|
// 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);
|
||||||
|
|
||||||
|
// Hinzufügen
|
||||||
|
buttonPanel.add(btnFirst);
|
||||||
|
buttonPanel.add(btnPrev);
|
||||||
|
buttonPanel.add(btnNext);
|
||||||
|
buttonPanel.add(btnLast);
|
||||||
|
|
||||||
|
// Unten ins BorderLayout
|
||||||
|
statsPanel.add(buttonPanel, BorderLayout.SOUTH);
|
||||||
|
|
||||||
|
return statsPanel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String showPromotionDialog(String color) {
|
||||||
|
String[] choices = {"Dame", "Turm", "Springer", "Läufer"};
|
||||||
|
String choice = (String) JOptionPane.showInputDialog(
|
||||||
|
null,
|
||||||
|
color + "er Bauer wird umgewandelt – wähle Figur:",
|
||||||
|
"Bauernumwandlung",
|
||||||
|
JOptionPane.PLAIN_MESSAGE,
|
||||||
|
null,
|
||||||
|
choices,
|
||||||
|
choices[0]);
|
||||||
|
if (choice == null) return "QUEEN";
|
||||||
|
switch (choice) {
|
||||||
|
case "Turm": return "ROOK";
|
||||||
|
case "Springer": return "KNIGHT";
|
||||||
|
case "Läufer": return "BISHOP";
|
||||||
|
default: return "QUEEN";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateMoveList(List<String> moves) {
|
||||||
|
moveListPanel.removeAll();
|
||||||
|
for (String move : moves) {
|
||||||
|
JLabel moveLabel = new JLabel(move);
|
||||||
|
moveLabel.setForeground(Color.WHITE);
|
||||||
|
moveLabel.setFont(new Font("SansSerif", Font.PLAIN, 18));
|
||||||
|
moveListPanel.add(moveLabel);
|
||||||
|
}
|
||||||
|
moveListPanel.revalidate();
|
||||||
|
moveListPanel.repaint();
|
||||||
|
}
|
||||||
|
|
||||||
|
public JLabel getField(int row, int col) {
|
||||||
|
return fields[row][col];
|
||||||
|
}
|
||||||
|
|
||||||
|
public JButton getFlipBoardButton() {
|
||||||
|
return flipBoardButton;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isFlipped() {
|
||||||
|
return isFlipped;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFlipped(boolean flipped) {
|
||||||
|
this.isFlipped = flipped;
|
||||||
|
}
|
||||||
|
|
||||||
|
public JButton getBtnFirst() { return btnFirst; }
|
||||||
|
public JButton getBtnPrev() { return btnPrev; }
|
||||||
|
public JButton getBtnNext() { return btnNext; }
|
||||||
|
public JButton getBtnLast() { return btnLast; }
|
||||||
|
|
||||||
|
public void updateBoard(BoardDTO boardDTO) {
|
||||||
|
PieceDTO[][] board = boardDTO.getBoard();
|
||||||
|
if (!isFlipped) {
|
||||||
|
for (int row = 0; row < 8; row++) {
|
||||||
|
for (int col = 0; col < 8; col++) {
|
||||||
|
PieceDTO piece = board[row][col];
|
||||||
|
fields[row][col].setText(piece != null ? piece.getUnicodeSymbol() : "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Invertiere Zeilen und Spalten
|
||||||
|
for (int row = 0; row < 8; row++) {
|
||||||
|
for (int col = 0; col < 8; col++) {
|
||||||
|
PieceDTO piece = board[7 - row][7 - col];
|
||||||
|
fields[row][col].setText(piece != null ? piece.getUnicodeSymbol() : "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void displayMessage(String msg) {
|
||||||
|
JOptionPane.showMessageDialog(null, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
package de.hs_mannheim.informatik.chess.view;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
import javax.swing.BoxLayout;
|
||||||
|
import javax.swing.JButton;
|
||||||
|
import javax.swing.JFrame;
|
||||||
|
import javax.swing.JPanel;
|
||||||
|
import javax.swing.JScrollPane;
|
||||||
|
|
||||||
|
import com.github.bhlangonijr.chesslib.game.Game;
|
||||||
|
|
||||||
|
public class PgnSelectionGui extends JFrame {
|
||||||
|
public PgnSelectionGui(List<Game> games, Consumer<Game> onGameSelected) {
|
||||||
|
setTitle("Geladene Partien");
|
||||||
|
setSize(600, 800);
|
||||||
|
setLocationRelativeTo(null);
|
||||||
|
JPanel panel = new JPanel();
|
||||||
|
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
|
||||||
|
JScrollPane scrollPane = new JScrollPane(panel);
|
||||||
|
|
||||||
|
int index = 1;
|
||||||
|
for (Game game : games) {
|
||||||
|
String white = game.getWhitePlayer().getName();
|
||||||
|
String black = game.getBlackPlayer().getName();
|
||||||
|
String title = "Spiel " + index++ + ": " + white + " vs. " + black;
|
||||||
|
JButton btn = new JButton(title);
|
||||||
|
btn.addActionListener(e -> {
|
||||||
|
dispose();
|
||||||
|
onGameSelected.accept(game);
|
||||||
|
});
|
||||||
|
panel.add(btn);
|
||||||
|
}
|
||||||
|
add(scrollPane);
|
||||||
|
setVisible(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ package de.hs_mannheim.informatik.chess.test;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
import de.hs_mannheim.informatik.chess.controller.Controller;
|
import de.hs_mannheim.informatik.chess.controller.GameController;
|
||||||
import de.hs_mannheim.informatik.chess.model.*;
|
import de.hs_mannheim.informatik.chess.model.*;
|
||||||
import de.hs_mannheim.informatik.chess.view.GameGui;
|
import de.hs_mannheim.informatik.chess.view.GameGui;
|
||||||
|
|
||||||
|
@ -20,9 +20,10 @@ import javax.swing.JLabel;
|
||||||
public class ControllerTest {
|
public class ControllerTest {
|
||||||
|
|
||||||
|
|
||||||
private Controller controller;
|
private GameController controller;
|
||||||
private ChessEngine engineMock;
|
private ChessEngine engineMock;
|
||||||
private GameGui guiMock;
|
private GameGui guiMock;
|
||||||
|
private GameEndCallback callback;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -43,7 +44,7 @@ public class ControllerTest {
|
||||||
when(guiMock.getFlipBoardButton()).thenReturn(new javax.swing.JButton());
|
when(guiMock.getFlipBoardButton()).thenReturn(new javax.swing.JButton());
|
||||||
|
|
||||||
// Jetzt ist der Controller sicher
|
// Jetzt ist der Controller sicher
|
||||||
controller = new Controller(guiMock, engineMock);
|
controller = new GameController(guiMock, engineMock, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test //Testet dass keine Fehlermeldung bei legalen Move kommt
|
@Test //Testet dass keine Fehlermeldung bei legalen Move kommt
|
||||||
|
|
Loading…
Reference in New Issue