Compare commits
22 Commits
12bea41b1e
...
8447ce5fe3
| Author | SHA1 | Date |
|---|---|---|
|
|
8447ce5fe3 | |
|
|
6d3154d0e3 | |
|
|
5770d13cdc | |
|
|
ae07b4d719 | |
|
|
aaa4317c9c | |
|
|
3aa8897ff1 | |
|
|
3c3dd5e8ab | |
|
|
35b7d9aa9a | |
|
|
66a8c1a51d | |
|
|
24374030be | |
|
|
b56813d6dc | |
|
|
c864f88e1c | |
|
|
a669a4b2ff | |
|
|
d16aa13804 | |
|
|
ea2c0066fd | |
|
|
ffbdb8b6e0 | |
|
|
d23f7097f7 | |
|
|
69c4e44671 | |
|
|
7ebfecc6c4 | |
|
|
993fa89371 | |
|
|
9e095418a2 | |
|
|
4c58eebc65 |
File diff suppressed because it is too large
Load Diff
|
|
@ -33,13 +33,20 @@
|
|||
<artifactId>chesslib</artifactId>
|
||||
<version>1.3.4</version>
|
||||
</dependency>
|
||||
<!-- JUnit 3 (wie im Template, ggf. auf JUnit 4/5 upgraden für moderne Projekte) -->
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter</artifactId>
|
||||
<version>5.10.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<!-- Mockito damit man Controller und Gui besser testen kann-->
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>3.8.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<version>5.11.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
|
@ -82,7 +89,7 @@
|
|||
<version>3.1.2</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
</pluginManagement>
|
||||
</build>
|
||||
|
||||
<reporting>
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@ import java.util.List;
|
|||
|
||||
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.MoveDTO;
|
||||
import de.hs_mannheim.informatik.chess.model.PieceDTO;
|
||||
|
|
@ -81,6 +83,25 @@ public class GameController {
|
|||
engine.setPositionToMoveIndex(engine.getMoveListSize());
|
||||
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 -> {
|
||||
|
|
@ -101,14 +122,89 @@ public class GameController {
|
|||
// 3. Board neu zeichnen
|
||||
updateGuiBoard();
|
||||
});
|
||||
|
||||
// --- AUFGEBEN-BUTTON ---
|
||||
gui.getResignButton().addActionListener(e -> {
|
||||
if (gameOver) return;
|
||||
|
||||
int answer = javax.swing.JOptionPane.showConfirmDialog(
|
||||
null,
|
||||
"Willst du wirklich aufgeben?",
|
||||
"Aufgeben",
|
||||
javax.swing.JOptionPane.YES_NO_OPTION
|
||||
);
|
||||
if (answer == javax.swing.JOptionPane.YES_OPTION) {
|
||||
gameOver = true;
|
||||
String winner = engine.getCurrentPlayer().equals("WHITE") ? "SCHWARZ" : "WEIß";
|
||||
gui.displayMessage(winner + " gewinnt durch Aufgabe!");
|
||||
engine.getWhiteTimer().stop();
|
||||
engine.getBlackTimer().stop();
|
||||
askForRestart();
|
||||
}
|
||||
});
|
||||
|
||||
// --- PATT-/REMIS-BUTTON ---
|
||||
gui.getDrawButton().addActionListener(e -> {
|
||||
if (gameOver) return;
|
||||
|
||||
int answer = javax.swing.JOptionPane.showConfirmDialog(
|
||||
null,
|
||||
"Remis anbieten? (Das Spiel endet sofort unentschieden)",
|
||||
"Remis",
|
||||
javax.swing.JOptionPane.YES_NO_OPTION
|
||||
);
|
||||
if (answer == javax.swing.JOptionPane.YES_OPTION) {
|
||||
gameOver = true;
|
||||
gui.displayMessage("Remis! (durch Einigung)");
|
||||
engine.getWhiteTimer().stop();
|
||||
engine.getBlackTimer().stop();
|
||||
askForRestart();
|
||||
}
|
||||
});
|
||||
|
||||
gui.getUndoButton().addActionListener(e -> {
|
||||
// Wer ist am Zug? (Das ist der, der gefragt wird)
|
||||
String currentPlayer = engine.getCurrentPlayer(); // "WHITE" oder "BLACK"
|
||||
// Wer möchte zurücknehmen? (Das ist der, der NICHT am Zug ist)
|
||||
String currentName = currentPlayer.equals("WHITE") ? "Weiß" : "Schwarz";
|
||||
String previousName = currentPlayer.equals("WHITE") ? "Schwarz" : "Weiß";
|
||||
|
||||
int answer = javax.swing.JOptionPane.showConfirmDialog(
|
||||
null,
|
||||
currentName + " ist am Zug. " +
|
||||
previousName + " möchte seinen letzten Zug zurücknehmen.\n" +
|
||||
currentName + ", erlaubst du das?",
|
||||
"Zug zurücknehmen?",
|
||||
javax.swing.JOptionPane.YES_NO_OPTION
|
||||
);
|
||||
|
||||
if (answer == javax.swing.JOptionPane.YES_OPTION) {
|
||||
engine.undoLastMove();
|
||||
updateGuiBoard();
|
||||
gui.updateMoveList(engine.getMoveListStringsGrouped());
|
||||
gui.setOpeningLabel(engine.getOpeningName());
|
||||
gui.displayMessage("Der letzte Zug wurde zurückgenommen.");
|
||||
} else if (answer == javax.swing.JOptionPane.NO_OPTION) {
|
||||
gui.displayMessage("Das Zurücknehmen wurde abgelehnt.");
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
private boolean isAtLatestMove() {
|
||||
return engine.getCurrentMoveIndex() == engine.getMoveListSize();
|
||||
}
|
||||
|
||||
private void handleClick(int guiRow, int guiCol) {
|
||||
|
||||
if (gameOver) return;
|
||||
|
||||
if (!isAtLatestMove()) {
|
||||
gui.displayMessage("Du bist im Zug-Archiv und kannst keine Figuren bewegen. Klick auf '>|', um zum letzten Zug zu gehen.");
|
||||
return;
|
||||
}
|
||||
|
||||
int modelRow = flipRow(guiRow);
|
||||
int modelCol = flipCol(guiCol);
|
||||
|
||||
|
|
@ -205,6 +301,7 @@ public class GameController {
|
|||
public void updateGuiBoard() {
|
||||
BoardDTO board = engine.getBoardAsDTO();
|
||||
gui.updateBoard(board);
|
||||
gui.setOpeningLabel(engine.getOpeningName());
|
||||
}
|
||||
|
||||
private void switchTimers() {
|
||||
|
|
|
|||
|
|
@ -47,6 +47,24 @@ public class MainController {
|
|||
CreativeGui creativegui = new CreativeGui();
|
||||
ChessEngine engine = new ChessEngine();
|
||||
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() {
|
||||
|
|
|
|||
|
|
@ -65,7 +65,8 @@ public class PgnController {
|
|||
public void updateGuiBoard() {
|
||||
BoardDTO board = engine.getBoardAsDTO();
|
||||
gui.updateBoard(board);
|
||||
gui.updateMoveList(engine.getMoveListStringsGrouped());
|
||||
gui.updateMoveList(engine.getMoveListStringsGrouped());
|
||||
gui.setOpeningLabel(engine.getOpeningName());
|
||||
}
|
||||
|
||||
private void resetFieldBackground(int row, int col) {
|
||||
|
|
|
|||
|
|
@ -14,24 +14,30 @@ import java.util.logging.SimpleFormatter;
|
|||
import com.github.bhlangonijr.chesslib.Board;
|
||||
import com.github.bhlangonijr.chesslib.Piece;
|
||||
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.pgn.PgnHolder;
|
||||
import com.github.bhlangonijr.chesslib.game.*;
|
||||
import com.github.bhlangonijr.chesslib.move.MoveList;
|
||||
import java.time.LocalDate;
|
||||
import com.github.bhlangonijr.chesslib.Side;
|
||||
|
||||
|
||||
public class ChessEngine {
|
||||
private Board board;
|
||||
private List<Move> moves = new ArrayList<>();
|
||||
private String initialFen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
|
||||
private static final Logger logger = Logger.getLogger(ChessEngine.class.getName());
|
||||
|
||||
private int currentMoveIndex = 0;
|
||||
private Timer whiteTimer;
|
||||
private Timer blackTimer;
|
||||
|
||||
private Opening detectedOpening = null;
|
||||
|
||||
public ChessEngine() {
|
||||
logging();
|
||||
board = new Board();
|
||||
}
|
||||
|
||||
public boolean move(MoveDTO move) {
|
||||
String from = "" + (char)('A' + move.getFromCol()) + (8 - move.getFromRow());
|
||||
String to = "" + (char)('A' + move.getToCol()) + (8 - move.getToRow());
|
||||
|
|
@ -39,19 +45,44 @@ public class ChessEngine {
|
|||
if (board.legalMoves().contains(libMove)) {
|
||||
board.doMove(libMove);
|
||||
|
||||
//Replay? Dann abschneiden
|
||||
// Replay? Dann abschneiden
|
||||
if (currentMoveIndex < moves.size()) {
|
||||
logger.info("Replay-Modus: Züge nach " + currentMoveIndex + " werden entfernt.");
|
||||
logger.info("Replay-Modus: Züge nach " + currentMoveIndex + " werden entfernt.");
|
||||
moves = new ArrayList<>(moves.subList(0, currentMoveIndex));
|
||||
}
|
||||
moves.add(libMove);
|
||||
currentMoveIndex++;
|
||||
logger.info("Zug erfolgreich durchgeführt: " + libMove);
|
||||
|
||||
// Opening-Erkennung nach jedem erfolgreichen Zug
|
||||
String playedMovesUci = movesToUciString(moves);
|
||||
detectedOpening = Opening.detect(playedMovesUci);
|
||||
|
||||
if (detectedOpening != null) {
|
||||
logger.info("Aktuelles Opening erkannt: " + detectedOpening.getEco() + " - " + detectedOpening.getName());
|
||||
// Optional: Speichere das Opening in ein Feld, falls benötigt
|
||||
}
|
||||
return true;
|
||||
}
|
||||
logger.warning("Ungültiger Zug: " + libMove);
|
||||
return false;
|
||||
}
|
||||
|
||||
public String getOpeningName() {
|
||||
if (detectedOpening != null) {
|
||||
return detectedOpening.getEco() + " - " + detectedOpening.getName();
|
||||
} else {
|
||||
return "unbekannt";
|
||||
}
|
||||
}
|
||||
|
||||
private String movesToUciString(List<Move> moves) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (Move m : moves) {
|
||||
sb.append(m.toString()).append(" ");
|
||||
}
|
||||
return sb.toString().trim();
|
||||
}
|
||||
|
||||
public List<MoveDTO> getLegalDestinations(String from) {
|
||||
logger.info("Hole legale Züge von: " + from);
|
||||
|
|
@ -158,15 +189,17 @@ public class ChessEngine {
|
|||
}
|
||||
|
||||
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.loadFromFen(initialFen); // Statt new Board() -> initialFen!
|
||||
for (int i = 0; i < idx; i++) {
|
||||
board.doMove(moves.get(i));
|
||||
}
|
||||
currentMoveIndex = idx;
|
||||
|
||||
String playedMovesUci = movesToUciString(moves.subList(0, idx));
|
||||
detectedOpening = Opening.detect(playedMovesUci);
|
||||
}
|
||||
|
||||
public int getCurrentMoveIndex() {
|
||||
logger.info("Hole aktuellen Zug-Index: " + currentMoveIndex);
|
||||
return currentMoveIndex;
|
||||
|
|
@ -187,6 +220,7 @@ public class ChessEngine {
|
|||
|
||||
public void setPositionFromFEN(String fen) {
|
||||
board.loadFromFen(fen);
|
||||
initialFen = fen;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -230,7 +264,7 @@ public class ChessEngine {
|
|||
|
||||
logger.info("ChessEngine wurde initialisiert.");
|
||||
}
|
||||
|
||||
|
||||
public List<Game> loadGamesFromPgn(String path) throws IOException {
|
||||
|
||||
PgnHolder pgnHolder = new PgnHolder(path);
|
||||
|
|
@ -249,14 +283,17 @@ public class ChessEngine {
|
|||
}
|
||||
|
||||
public void saveAsPgn(Game game, String path, String dateiname) {
|
||||
String event = game.getRound().getEvent().getName();
|
||||
String site = game.getRound().getEvent().getSite();
|
||||
// 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();
|
||||
String date = game.getRound().getEvent().getStartDate();
|
||||
String wName = game.getWhitePlayer().getName();
|
||||
String bName = game.getBlackPlayer().getName();
|
||||
String result = game.getResult().getDescription();
|
||||
// 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");
|
||||
|
|
@ -264,29 +301,102 @@ public class ChessEngine {
|
|||
header.append("[Round \"" + round + "\"]\n");
|
||||
header.append("[White \"" + wName + "\"]\n");
|
||||
header.append("[Black \"" + bName + "\"]\n");
|
||||
header.append("[Result \"" + result + "\"]\n");
|
||||
header.append("\n");
|
||||
header.append("[Result \"" + result + "\"]\n\n");
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
// 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) {
|
||||
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.toString() + sb.toString();
|
||||
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 undoLastMove() {
|
||||
if (currentMoveIndex > 0 && moves.size() > 0) {
|
||||
board.undoMove(); // 1. Brett zurücksetzen
|
||||
moves.remove(currentMoveIndex - 1); // 2. Zug aus Move-Liste löschen
|
||||
currentMoveIndex--; // 3. Index anpassen
|
||||
|
||||
// 4. Erkennung Opening neu machen!
|
||||
String playedMovesUci = movesToUciString(moves.subList(0, currentMoveIndex));
|
||||
detectedOpening = Opening.detect(playedMovesUci);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void loadMoves(List<Move> moveList) {
|
||||
board = new Board(); // Neues leeres Brett
|
||||
|
|
@ -302,6 +412,6 @@ public class ChessEngine {
|
|||
}
|
||||
|
||||
public Timer getWhiteTimer() { return whiteTimer; }
|
||||
public Timer getBlackTimer() { return blackTimer; }
|
||||
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,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;
|
||||
}
|
||||
}
|
||||
|
|
@ -5,6 +5,11 @@ import java.awt.*;
|
|||
import java.util.HashMap;
|
||||
|
||||
public class CreativeGui {
|
||||
|
||||
public interface StartGameCallback {
|
||||
void onStartGame(String fen);
|
||||
}
|
||||
|
||||
private boolean isFlipped = false;
|
||||
|
||||
private JFrame frame;
|
||||
|
|
@ -13,6 +18,10 @@ public class CreativeGui {
|
|||
private JTextField fenField;
|
||||
private JButton updateBtn;
|
||||
private JButton flipBoardButton;
|
||||
|
||||
private StartGameCallback startGameCallback;
|
||||
|
||||
private JButton startGameButton;
|
||||
|
||||
public static final HashMap<String, String> UNICODE_MAP = new HashMap<String, String>() {{
|
||||
put("BLACK_KING", "\u265A"); put("BLACK_QUEEN", "\u265B");
|
||||
|
|
@ -30,7 +39,8 @@ public class CreativeGui {
|
|||
public CreativeGui() {
|
||||
frame = new JFrame("Creative Mode");
|
||||
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
|
||||
frame.setSize(1600, 1200);
|
||||
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
|
||||
frame.setUndecorated(false);
|
||||
frame.setLocationRelativeTo(null);
|
||||
|
||||
JPanel mainPanel = new JPanel(new GridBagLayout());
|
||||
|
|
@ -40,7 +50,7 @@ public class CreativeGui {
|
|||
// LINKS: chessPanel (Board+Toolbars)
|
||||
gbc.gridx = 0;
|
||||
gbc.gridy = 0;
|
||||
gbc.weightx = 0.6;
|
||||
gbc.weightx = 0.7;
|
||||
gbc.weighty = 1.0;
|
||||
gbc.insets = new Insets(5, 5, 5, 0);
|
||||
gbc.fill = GridBagConstraints.BOTH;
|
||||
|
|
@ -49,7 +59,7 @@ public class CreativeGui {
|
|||
// RECHTS: FEN & Optionen
|
||||
gbc.gridx = 1;
|
||||
gbc.gridy = 0;
|
||||
gbc.weightx = 0.4;
|
||||
gbc.weightx = 0.3;
|
||||
gbc.weighty = 1.0;
|
||||
gbc.insets = new Insets(5, 0, 5, 5);
|
||||
gbc.fill = GridBagConstraints.BOTH;
|
||||
|
|
@ -71,7 +81,7 @@ public class CreativeGui {
|
|||
btn.setFocusPainted(false);
|
||||
btn.setPreferredSize(new Dimension(70, 70));
|
||||
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;
|
||||
btn.addActionListener(e -> selectedPiece = key);
|
||||
panel.add(btn);
|
||||
|
|
@ -104,47 +114,76 @@ public class CreativeGui {
|
|||
}
|
||||
|
||||
private JPanel chessPanel() {
|
||||
JPanel chessPanel = new JPanel(new GridBagLayout());
|
||||
JPanel chessPanel = new JPanel(new BorderLayout());
|
||||
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 UND Toolbars in EINEM Panel, damit sie linksbündig mit dem Brett starten!
|
||||
JPanel boardAndToolbars = new JPanel(new BorderLayout());
|
||||
boardAndToolbars.setOpaque(false);
|
||||
|
||||
// Board
|
||||
gbc.gridx = 0;
|
||||
gbc.gridy = 1;
|
||||
gbc.fill = GridBagConstraints.BOTH;
|
||||
chessPanel.add(boardPanel(), gbc);
|
||||
// Toolbar Schwarz (oben)
|
||||
JPanel blackToolbar = toolbarPanel(false);
|
||||
boardAndToolbars.add(blackToolbar, BorderLayout.NORTH);
|
||||
|
||||
// Toolbar unten
|
||||
gbc.gridx = 0;
|
||||
gbc.gridy = 2;
|
||||
gbc.fill = GridBagConstraints.HORIZONTAL;
|
||||
chessPanel.add(toolbarPanel(true), gbc);
|
||||
// Board (zentriert im Panel)
|
||||
JPanel board = boardPanel();
|
||||
boardAndToolbars.add(board, BorderLayout.CENTER);
|
||||
|
||||
// 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);
|
||||
// Toolbar Weiß (unten)
|
||||
JPanel whiteToolbar = toolbarPanel(true);
|
||||
boardAndToolbars.add(whiteToolbar, BorderLayout.SOUTH);
|
||||
|
||||
// Board+Toolbars mittig in einem Panel mit FlowLayout, damit sie zentriert sind
|
||||
JPanel centerPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 0, 0));
|
||||
centerPanel.setOpaque(false);
|
||||
centerPanel.add(boardAndToolbars);
|
||||
|
||||
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);
|
||||
blackToolbar.setPreferredSize(new Dimension(0, 70)); // 70 px hoch
|
||||
whiteToolbar.setPreferredSize(new Dimension(0, 70));
|
||||
// Dynamisch skalieren wie gehabt
|
||||
centerPanel.addComponentListener(new java.awt.event.ComponentAdapter() {
|
||||
public void componentResized(java.awt.event.ComponentEvent evt) {
|
||||
int totalHeight = centerPanel.getHeight();
|
||||
int totalWidth = centerPanel.getWidth();
|
||||
int toolbarHeight = blackToolbar.getPreferredSize().height + whiteToolbar.getPreferredSize().height;
|
||||
// Falls Toolbars keine PrefSize haben, nimm getHeight()
|
||||
if (toolbarHeight == 0) toolbarHeight = blackToolbar.getHeight() + whiteToolbar.getHeight();
|
||||
int boardMaxHeight = totalHeight - toolbarHeight;
|
||||
int size = Math.min(totalWidth, boardMaxHeight);
|
||||
board.setPreferredSize(new Dimension(size, size));
|
||||
board.revalidate();
|
||||
}
|
||||
});
|
||||
|
||||
chessPanel.add(centerPanel, BorderLayout.CENTER);
|
||||
|
||||
// Drehknopf rechts, schön mittig
|
||||
JPanel eastPanel = new JPanel();
|
||||
eastPanel.setOpaque(false);
|
||||
eastPanel.setLayout(new BoxLayout(eastPanel, BoxLayout.Y_AXIS));
|
||||
eastPanel.add(Box.createVerticalGlue());
|
||||
eastPanel.add(flipBoardButton = createFlipButton());
|
||||
eastPanel.add(Box.createVerticalGlue());
|
||||
chessPanel.add(eastPanel, BorderLayout.EAST);
|
||||
|
||||
// Buffer links, wenn du willst
|
||||
chessPanel.add(Box.createRigidArea(new Dimension(40, 0)), BorderLayout.WEST);
|
||||
|
||||
return chessPanel;
|
||||
}
|
||||
|
||||
|
||||
// Flip-Knopf Builder, damit du’s an mehreren Stellen nutzen kannst:
|
||||
private JButton createFlipButton() {
|
||||
JButton btn = new JButton("⇵");
|
||||
btn.setPreferredSize(new Dimension(70, 70));
|
||||
btn.setFont(new Font("SansSerif", Font.BOLD, 40));
|
||||
btn.setBackground(new Color(0x5500ff));
|
||||
btn.setForeground(Color.WHITE);
|
||||
btn.setFocusPainted(false);
|
||||
return btn;
|
||||
}
|
||||
|
||||
|
||||
private JPanel fenPanel() {
|
||||
JPanel panel = new JPanel();
|
||||
|
|
@ -159,7 +198,20 @@ public class CreativeGui {
|
|||
updateBtn = new JButton("Update Board");
|
||||
updateBtn.setAlignmentX(Component.CENTER_ALIGNMENT);
|
||||
panel.add(updateBtn);
|
||||
|
||||
startGameButton = new JButton("🟢 Partie starten");
|
||||
startGameButton.setAlignmentX(Component.CENTER_ALIGNMENT);
|
||||
startGameButton.setBackground(new Color(0x218838));
|
||||
startGameButton.setForeground(Color.WHITE);
|
||||
panel.add(startGameButton);
|
||||
|
||||
startGameButton.addActionListener(e -> {
|
||||
if (startGameCallback != null) {
|
||||
startGameCallback.onStartGame(getFenText());
|
||||
}
|
||||
});
|
||||
return panel;
|
||||
|
||||
}
|
||||
|
||||
// Für Controller
|
||||
|
|
@ -171,6 +223,12 @@ public class CreativeGui {
|
|||
public void setSelectedPiece(String piece) { selectedPiece = piece; }
|
||||
public String getSelectedPiece() { return selectedPiece; }
|
||||
|
||||
public JButton getStartGameButton() { return startGameButton; }
|
||||
|
||||
public void setStartGameCallback(StartGameCallback callback) {
|
||||
this.startGameCallback = callback;
|
||||
}
|
||||
|
||||
public boolean isFlipped() { return isFlipped; }
|
||||
public void setFlipped(boolean f) { isFlipped = f; }
|
||||
public JButton getFlipBoardButton() { return flipBoardButton; }
|
||||
|
|
|
|||
|
|
@ -7,9 +7,12 @@ import java.awt.Font;
|
|||
import java.awt.GridBagConstraints;
|
||||
import java.awt.GridBagLayout;
|
||||
import java.awt.GridLayout;
|
||||
import java.awt.FlowLayout;
|
||||
|
||||
import java.awt.Insets;
|
||||
import java.util.List;
|
||||
|
||||
import javax.swing.Box;
|
||||
import javax.swing.BoxLayout;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JFrame;
|
||||
|
|
@ -27,14 +30,21 @@ public class GameGui {
|
|||
private JLabel[][] fields = new JLabel[8][8];
|
||||
private JButton flipBoardButton;
|
||||
private boolean isFlipped = false;
|
||||
JButton btnSave = new JButton("💾");
|
||||
|
||||
private JLabel whiteTimerLabel;
|
||||
private JLabel blackTimerLabel;
|
||||
private JLabel openingLabel;
|
||||
|
||||
JButton btnFirst = new JButton("|<");
|
||||
JButton btnPrev = new JButton("<");
|
||||
JButton btnNext = new JButton(">");
|
||||
JButton btnLast = new JButton(">|");
|
||||
private JButton btnFirst = new JButton("|<");
|
||||
private JButton btnPrev = new JButton("<");
|
||||
private JButton btnNext = new JButton(">");
|
||||
private JButton btnLast = new JButton(">|");
|
||||
|
||||
private JButton resignButton;
|
||||
private JButton drawButton;
|
||||
private JButton quickSaveButton;
|
||||
private JButton undoButton;
|
||||
|
||||
Color LIGHT = new Color(0xe0e1dd);
|
||||
Color DARK = new Color(0x778da9);
|
||||
|
|
@ -50,7 +60,8 @@ public class GameGui {
|
|||
|
||||
public JFrame mainFrame() {
|
||||
JFrame frame = new JFrame();
|
||||
frame.setSize(1600, 1000);
|
||||
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
|
||||
frame.setUndecorated(false);
|
||||
frame.setLocationRelativeTo(null);
|
||||
frame.add(mainPanel());
|
||||
|
||||
|
|
@ -126,38 +137,82 @@ public class GameGui {
|
|||
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);
|
||||
public JPanel chessPanel(JPanel boardPanel) {
|
||||
JPanel chessPanel = new JPanel(new BorderLayout());
|
||||
chessPanel.setBackground(new Color(0x1b263b));
|
||||
|
||||
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);
|
||||
// --- Eröffnungslabel oben ---
|
||||
openingLabel = new JLabel("Eröffnung: unbekannt", SwingConstants.CENTER);
|
||||
openingLabel.setFont(new Font("SansSerif", Font.BOLD, 24));
|
||||
openingLabel.setForeground(Color.WHITE);
|
||||
openingLabel.setOpaque(true);
|
||||
openingLabel.setBackground(new Color(0x283655));
|
||||
openingLabel.setPreferredSize(new Dimension(800, 50));
|
||||
chessPanel.add(openingLabel, BorderLayout.NORTH);
|
||||
|
||||
chessPanel.add(flipBoardButton, btn);
|
||||
|
||||
return chessPanel;
|
||||
// --- Board in ein zentriertes Panel mit fixer Größe ---
|
||||
JPanel centerPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 0, 0));
|
||||
centerPanel.setOpaque(false);
|
||||
centerPanel.add(boardPanel);
|
||||
|
||||
centerPanel.addComponentListener(new java.awt.event.ComponentAdapter() {
|
||||
public void componentResized(java.awt.event.ComponentEvent evt) {
|
||||
int size = Math.min(centerPanel.getWidth(), centerPanel.getHeight());
|
||||
boardPanel.setPreferredSize(new Dimension(size, size));
|
||||
boardPanel.revalidate();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
chessPanel.add(centerPanel, BorderLayout.CENTER);
|
||||
|
||||
// --- Dummy-Buffer für WEST und EAST ---
|
||||
chessPanel.add(Box.createRigidArea(new Dimension(40, 0)), BorderLayout.WEST);
|
||||
chessPanel.add(Box.createRigidArea(new Dimension(40, 0)), BorderLayout.EAST);
|
||||
|
||||
// --- Buttonleiste unten bauen ---
|
||||
JPanel buttonRow = new JPanel();
|
||||
buttonRow.setOpaque(false);
|
||||
buttonRow.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.RIGHT, 10, 0));
|
||||
|
||||
resignButton = new JButton("🏳");
|
||||
resignButton.setPreferredSize(new Dimension(70, 70));
|
||||
resignButton.setFont(new Font("SansSerif", Font.BOLD, 35));
|
||||
resignButton.setBackground(new Color(0xff0044));
|
||||
resignButton.setForeground(Color.WHITE);
|
||||
resignButton.setFocusPainted(false);
|
||||
|
||||
drawButton = new JButton("½");
|
||||
drawButton.setPreferredSize(new Dimension(70, 70));
|
||||
drawButton.setFont(new Font("SansSerif", Font.BOLD, 35));
|
||||
drawButton.setBackground(new Color(0x0080ff));
|
||||
drawButton.setForeground(Color.WHITE);
|
||||
drawButton.setFocusPainted(false);
|
||||
|
||||
flipBoardButton = new JButton("⇵");
|
||||
flipBoardButton.setPreferredSize(new Dimension(70, 70));
|
||||
flipBoardButton.setFont(new Font("SansSerif", Font.BOLD, 40));
|
||||
flipBoardButton.setBackground(new Color(0x5500ff));
|
||||
flipBoardButton.setForeground(Color.WHITE);
|
||||
flipBoardButton.setFocusPainted(false);
|
||||
|
||||
undoButton = new JButton("↧");
|
||||
undoButton.setPreferredSize(new Dimension(70, 70));
|
||||
undoButton.setFont(new Font("SansSerif", Font.BOLD, 40));
|
||||
undoButton.setBackground(new Color(0xffa500)); // Orange
|
||||
undoButton.setForeground(Color.WHITE);
|
||||
undoButton.setFocusPainted(false);
|
||||
|
||||
buttonRow.add(undoButton);
|
||||
buttonRow.add(resignButton);
|
||||
buttonRow.add(drawButton);
|
||||
buttonRow.add(flipBoardButton);
|
||||
|
||||
chessPanel.add(buttonRow, BorderLayout.SOUTH);
|
||||
|
||||
return chessPanel;
|
||||
}
|
||||
|
||||
|
||||
public JPanel statsPanel() {
|
||||
JPanel statsPanel = new JPanel(new BorderLayout());
|
||||
|
|
@ -177,15 +232,18 @@ public class GameGui {
|
|||
// Button-Leiste (SÜD)
|
||||
JPanel buttonPanel = new JPanel();
|
||||
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);
|
||||
btnPrev.setBackground(new Color(0x212529)); btnPrev.setForeground(Color.WHITE);
|
||||
btnNext.setBackground(new Color(0x212529)); btnNext.setForeground(Color.WHITE);
|
||||
btnLast.setBackground(new Color(0x212529)); btnLast.setForeground(Color.WHITE);
|
||||
btnSave.setBackground(new Color(0x218838)); btnSave.setForeground(Color.WHITE);
|
||||
|
||||
buttonPanel.add(btnFirst);
|
||||
buttonPanel.add(btnPrev);
|
||||
buttonPanel.add(btnNext);
|
||||
buttonPanel.add(btnLast);
|
||||
buttonPanel.add(btnSave);
|
||||
statsPanel.add(buttonPanel, BorderLayout.SOUTH);
|
||||
|
||||
return statsPanel;
|
||||
|
|
@ -266,6 +324,9 @@ public class GameGui {
|
|||
public JButton getBtnPrev() { return btnPrev; }
|
||||
public JButton getBtnNext() { return btnNext; }
|
||||
public JButton getBtnLast() { return btnLast; }
|
||||
public JButton getBtnSave() { return btnSave; }
|
||||
public JButton getResignButton() { return resignButton; }
|
||||
public JButton getDrawButton() { return drawButton; }
|
||||
|
||||
public void updateBoard(BoardDTO boardDTO) {
|
||||
PieceDTO[][] board = boardDTO.getBoard();
|
||||
|
|
@ -305,6 +366,13 @@ public class GameGui {
|
|||
public JLabel getWhiteTimerLabel() { return whiteTimerLabel; }
|
||||
public JLabel getBlackTimerLabel() { return blackTimerLabel; }
|
||||
|
||||
public void setOpeningLabel(String text) {
|
||||
openingLabel.setText("Eröffnung: " + text);
|
||||
}
|
||||
|
||||
public JButton getUndoButton() {
|
||||
return undoButton;
|
||||
}
|
||||
|
||||
public void displayMessage(String msg) {
|
||||
JOptionPane.showMessageDialog(null, msg);
|
||||
|
|
|
|||
|
|
@ -17,7 +17,8 @@ public class MainGui {
|
|||
|
||||
frame = new JFrame("Chess - Hauptmenü");
|
||||
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||
frame.setSize(1600, 1000);
|
||||
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
|
||||
frame.setUndecorated(false);
|
||||
frame.setLocationRelativeTo(null);
|
||||
|
||||
//Haupt-Panel mit GridBagLayout
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package de.hs_mannheim.informatik.chess.view;
|
|||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.FlowLayout;
|
||||
import java.awt.Font;
|
||||
import java.awt.GridBagConstraints;
|
||||
import java.awt.GridBagLayout;
|
||||
|
|
@ -10,6 +11,7 @@ import java.awt.GridLayout;
|
|||
import java.awt.Insets;
|
||||
import java.util.List;
|
||||
|
||||
import javax.swing.Box;
|
||||
import javax.swing.BoxLayout;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JFrame;
|
||||
|
|
@ -33,6 +35,8 @@ public class PgnGui {
|
|||
JButton btnNext = new JButton(">");
|
||||
JButton btnLast = new JButton(">|");
|
||||
|
||||
private JLabel openingLabel;
|
||||
|
||||
Color LIGHT = new Color(0xe0e1dd);
|
||||
Color DARK = new Color(0x778da9);
|
||||
|
||||
|
|
@ -47,7 +51,8 @@ public class PgnGui {
|
|||
|
||||
public JFrame mainFrame() {
|
||||
JFrame frame = new JFrame();
|
||||
frame.setSize(1600, 1000);
|
||||
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
|
||||
frame.setUndecorated(false);
|
||||
frame.setLocationRelativeTo(null);
|
||||
frame.add(mainPanel());
|
||||
|
||||
|
|
@ -123,37 +128,57 @@ public class PgnGui {
|
|||
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);
|
||||
public JPanel chessPanel(JPanel boardPanel) {
|
||||
JPanel chessPanel = new JPanel(new BorderLayout());
|
||||
chessPanel.setBackground(new Color(0x1b263b));
|
||||
|
||||
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);
|
||||
// --- Eröffnungslabel oben ---
|
||||
openingLabel = new JLabel("Eröffnung: unbekannt", SwingConstants.CENTER);
|
||||
openingLabel.setFont(new Font("SansSerif", Font.BOLD, 24));
|
||||
openingLabel.setForeground(Color.WHITE);
|
||||
openingLabel.setOpaque(true);
|
||||
openingLabel.setBackground(new Color(0x283655));
|
||||
openingLabel.setPreferredSize(new Dimension(800, 50));
|
||||
chessPanel.add(openingLabel, BorderLayout.NORTH);
|
||||
|
||||
chessPanel.add(flipBoardButton, btn);
|
||||
|
||||
return chessPanel;
|
||||
// --- Board in ein zentriertes Panel mit fixer Größe ---
|
||||
JPanel centerPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 0, 0));
|
||||
centerPanel.setOpaque(false);
|
||||
centerPanel.add(boardPanel);
|
||||
|
||||
centerPanel.addComponentListener(new java.awt.event.ComponentAdapter() {
|
||||
public void componentResized(java.awt.event.ComponentEvent evt) {
|
||||
int size = Math.min(centerPanel.getWidth(), centerPanel.getHeight());
|
||||
boardPanel.setPreferredSize(new Dimension(size, size));
|
||||
boardPanel.revalidate();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
chessPanel.add(centerPanel, BorderLayout.CENTER);
|
||||
|
||||
// --- Dummy-Buffer für WEST und EAST ---
|
||||
chessPanel.add(Box.createRigidArea(new Dimension(40, 0)), BorderLayout.WEST);
|
||||
chessPanel.add(Box.createRigidArea(new Dimension(40, 0)), BorderLayout.EAST);
|
||||
|
||||
// --- Buttonleiste unten bauen ---
|
||||
JPanel buttonRow = new JPanel();
|
||||
buttonRow.setOpaque(false);
|
||||
buttonRow.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.RIGHT, 10, 0));
|
||||
|
||||
|
||||
flipBoardButton = new JButton("⇵");
|
||||
flipBoardButton.setPreferredSize(new Dimension(70, 70));
|
||||
flipBoardButton.setFont(new Font("SansSerif", Font.BOLD, 40));
|
||||
flipBoardButton.setBackground(new Color(0x5500ff));
|
||||
flipBoardButton.setForeground(Color.WHITE);
|
||||
flipBoardButton.setFocusPainted(false);
|
||||
|
||||
buttonRow.add(flipBoardButton);
|
||||
|
||||
chessPanel.add(buttonRow, BorderLayout.SOUTH);
|
||||
|
||||
return chessPanel;
|
||||
}
|
||||
|
||||
public JPanel statsPanel() {
|
||||
|
|
@ -239,6 +264,11 @@ public class PgnGui {
|
|||
this.isFlipped = flipped;
|
||||
}
|
||||
|
||||
public void setOpeningLabel(String text) {
|
||||
openingLabel.setText("Eröffnung: " + text);
|
||||
}
|
||||
|
||||
|
||||
public JButton getBtnFirst() { return btnFirst; }
|
||||
public JButton getBtnPrev() { return btnPrev; }
|
||||
public JButton getBtnNext() { return btnNext; }
|
||||
|
|
|
|||
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
|
|
@ -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());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -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>
|
||||
Loading…
Reference in New Issue