diff --git a/src/dev/kske/chess/board/Board.java b/src/dev/kske/chess/board/Board.java
index 9c29145..b34c68c 100644
--- a/src/dev/kske/chess/board/Board.java
+++ b/src/dev/kske/chess/board/Board.java
@@ -7,9 +7,6 @@ import java.util.Map;
import dev.kske.chess.board.Piece.Color;
import dev.kske.chess.board.Piece.Type;
-import dev.kske.chess.event.GameEvent;
-import dev.kske.chess.event.GameEvent.GameEventType;
-import dev.kske.chess.event.GameEventListener;
/**
* Project: Chess
@@ -22,12 +19,9 @@ public class Board {
private Piece[][] boardArr;
private Map kingPos;
- private List gameEventListeners;
-
public Board() {
boardArr = new Piece[8][8];
kingPos = new HashMap<>();
- gameEventListeners = new ArrayList<>();
initializeDefaultPositions();
}
@@ -53,11 +47,6 @@ public class Board {
return false;
}
- // Detect check and stalemate on the opposite team
- Color oppositeColor = piece.getColor().opposite();
- GameEventType eventType = getGameEventType(oppositeColor);
- if (eventType != GameEventType.NONE) notifyListeners(new GameEvent(this, eventType, oppositeColor));
-
return true;
}
}
@@ -114,6 +103,12 @@ public class Board {
return get(pos).getMoves(pos);
}
+ /**
+ * Checks, if the king is in check.
+ *
+ * @param color The color of the king to check
+ * @return {@code true}, if the king is in check
+ */
public boolean checkCheck(Color color) {
for (int i = 0; i < 8; i++)
for (int j = 0; j < 8; j++) {
@@ -125,10 +120,31 @@ public class Board {
return false;
}
- public GameEventType getGameEventType(Color color) {
+ /**
+ * Checks, if the king is in checkmate.
+ * This requires the king to already be in check!
+ *
+ * @param color The color of the king to check
+ * @return {@code true}, if the king is in checkmate
+ */
+ public boolean checkCheckmate(Color color) {
+ // Return false immediately if the king can move
+ if (!getMoves(kingPos.get(color)).isEmpty()) return false;
+ else {
+ for (Move move : getMoves(color)) {
+ Piece capturePiece = move(move);
+ boolean check = checkCheck(color);
+ revert(move, capturePiece);
+ if (!check) return false;
+ }
+ return true;
+ }
+ }
+
+ public GameState getGameEventType(Color color) {
return checkCheck(color)
- ? getMoves(kingPos.get(color)).isEmpty() ? GameEventType.CHECKMATE : GameEventType.CHECK
- : getMoves(color).isEmpty() ? GameEventType.STALEMATE : GameEventType.NONE;
+ ? checkCheckmate(color) ? GameState.CHECKMATE : GameState.CHECK
+ : getMoves(color).isEmpty() ? GameState.STALEMATE : GameState.NORMAL;
}
/**
@@ -161,14 +177,6 @@ public class Board {
return score;
}
- public void registerGameEventListener(GameEventListener listener) {
- gameEventListeners.add(listener);
- }
-
- private void notifyListeners(GameEvent evt) {
- gameEventListeners.forEach(listener -> listener.onGameEvent(evt));
- }
-
/**
* Initialized the board array with the default chess pieces and positions.
*/
diff --git a/src/dev/kske/chess/board/GameState.java b/src/dev/kske/chess/board/GameState.java
new file mode 100644
index 0000000..07579dd
--- /dev/null
+++ b/src/dev/kske/chess/board/GameState.java
@@ -0,0 +1,11 @@
+package dev.kske.chess.board;
+
+/**
+ * Project: Chess
+ * File: GameState.java
+ * Created: 07.07.2019
+ * Author: Kai S. K. Engelbart
+ */
+public enum GameState {
+ CHECK, CHECKMATE, STALEMATE, NORMAL;
+}
diff --git a/src/dev/kske/chess/event/GameEvent.java b/src/dev/kske/chess/event/GameEvent.java
deleted file mode 100644
index ae5d6c9..0000000
--- a/src/dev/kske/chess/event/GameEvent.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package dev.kske.chess.event;
-
-import java.util.EventObject;
-
-import dev.kske.chess.board.Board;
-import dev.kske.chess.board.Piece.Color;
-
-/**
- * Project: Chess
- * File: GameEvent.java
- * Created: 03.07.2019
- * Author: Kai S. K. Engelbart
- */
-public class GameEvent extends EventObject {
-
- private static final long serialVersionUID = -6783035746521826589L;
-
- private final Board source;
- private final GameEventType eventType;
- private final Color color;
-
- public GameEvent(Board source, GameEventType eventType, Color color) {
- super(source);
- this.source = source;
- this.eventType = eventType;
- this.color = color;
- }
-
- public Board getSource() { return source; }
-
- public GameEventType getEventType() { return eventType; }
-
- public Color getColor() { return color; }
-
- public static enum GameEventType {
- CHECK, CHECKMATE, STALEMATE, NONE;
- }
-}
diff --git a/src/dev/kske/chess/event/GameEventListener.java b/src/dev/kske/chess/event/GameEventListener.java
deleted file mode 100644
index f01ee6a..0000000
--- a/src/dev/kske/chess/event/GameEventListener.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package dev.kske.chess.event;
-
-/**
- * Project: Chess
- * File: GameEventListener.java
- * Created: 03.07.2019
- * Author: Kai S. K. Engelbart
- */
-public interface GameEventListener {
-
- void onGameEvent(GameEvent evt);
-}
diff --git a/src/dev/kske/chess/game/AIPlayer.java b/src/dev/kske/chess/game/AIPlayer.java
index 4dad40d..4cfc702 100644
--- a/src/dev/kske/chess/game/AIPlayer.java
+++ b/src/dev/kske/chess/game/AIPlayer.java
@@ -14,6 +14,7 @@ import dev.kske.chess.board.Piece.Color;
public class AIPlayer extends Player {
private Move bestMove;
+ private int count;
public AIPlayer(Board board, Color color) {
super(board, color);
@@ -21,19 +22,22 @@ public class AIPlayer extends Player {
@Override
public void requestMove() {
+ count = 0;
findBestMove(board, color, 0);
+ System.out.println("Moved processes: " + count);
game.onMove(this, bestMove);
}
private int findBestMove(Board board, Color color, int depth) {
int bestValue = Integer.MIN_VALUE;
for (Move move : board.getMoves(color)) {
+ ++count;
Piece capturePiece = board.move(move);
int teamValue = board.evaluate(color);
int enemyValue = board.evaluate(color.opposite());
int valueChange = teamValue - enemyValue;
- if (depth < 4) valueChange -= findBestMove(board, color.opposite(), depth + 1);
+ if (depth <= 3 && valueChange >= 0) valueChange -= findBestMove(board, color.opposite(), depth + 1);
if (valueChange > bestValue) {
bestValue = valueChange;
diff --git a/src/dev/kske/chess/game/Game.java b/src/dev/kske/chess/game/Game.java
index 487a421..2179d64 100644
--- a/src/dev/kske/chess/game/Game.java
+++ b/src/dev/kske/chess/game/Game.java
@@ -3,6 +3,7 @@ package dev.kske.chess.game;
import java.util.Map;
import dev.kske.chess.board.Board;
+import dev.kske.chess.board.GameState;
import dev.kske.chess.board.Move;
import dev.kske.chess.board.Piece.Color;
import dev.kske.chess.ui.BoardPanel;
@@ -36,7 +37,18 @@ public class Game {
if (board.getPos(move).getColor() == player.color && board.attemptMove(move)) {
System.out.printf("%s: %s%n", player.color, move);
boardPanel.repaint();
- players.get(player.color.opposite()).requestMove();
+
+ GameState eventType = board.getGameEventType(board.getDest(move).getColor().opposite());
+ switch (eventType) {
+ case CHECKMATE:
+ case STALEMATE:
+ System.out.printf("%s in %s!%n", player.color, eventType);
+ break;
+ case CHECK:
+ System.out.printf("%s in check!%n", player.color);
+ default:
+ players.get(player.color.opposite()).requestMove();
+ }
} else {
System.out.printf("%s: Illegal move!%n", player.getColor());
player.requestMove();
diff --git a/src/dev/kske/chess/ui/BoardPanel.java b/src/dev/kske/chess/ui/BoardPanel.java
index a068ce5..5cf4b3c 100644
--- a/src/dev/kske/chess/ui/BoardPanel.java
+++ b/src/dev/kske/chess/ui/BoardPanel.java
@@ -8,13 +8,10 @@ import java.awt.event.ComponentEvent;
import java.util.ArrayList;
import java.util.List;
-import javax.swing.JOptionPane;
import javax.swing.JPanel;
import dev.kske.chess.board.Board;
import dev.kske.chess.board.Move;
-import dev.kske.chess.event.GameEvent;
-import dev.kske.chess.event.GameEventListener;
/**
* Project: Chess
@@ -26,7 +23,7 @@ import dev.kske.chess.event.GameEventListener;
* this must be added to a parent component that allows the child to decide the
* size.
*/
-public class BoardPanel extends JPanel implements GameEventListener {
+public class BoardPanel extends JPanel {
private static final long serialVersionUID = 6771148331334310216L;
@@ -90,18 +87,6 @@ public class BoardPanel extends JPanel implements GameEventListener {
}
}
- @Override
- public void onGameEvent(GameEvent evt) {
- switch (evt.getEventType()) {
- case CHECK:
- JOptionPane.showMessageDialog(this, evt.getColor().toString() + " in check!");
- break;
- case CHECKMATE:
- JOptionPane.showMessageDialog(this, evt.getColor().toString() + " in checkmate!");
- break;
- }
- }
-
/**
* Displays move destinations on the board.
*
@@ -142,10 +127,5 @@ public class BoardPanel extends JPanel implements GameEventListener {
public Board getBoard() { return board; }
- public void setBoard(Board board) {
- this.board = board;
-
- // Register this BoardPanel as a GameEventListener to the board
- board.registerGameEventListener(this);
- }
+ public void setBoard(Board board) { this.board = board; }
}
diff --git a/src/dev/kske/chess/ui/GameModeDialog.java b/src/dev/kske/chess/ui/GameModeDialog.java
index fbc8835..0db92ee 100644
--- a/src/dev/kske/chess/ui/GameModeDialog.java
+++ b/src/dev/kske/chess/ui/GameModeDialog.java
@@ -49,8 +49,7 @@ public class GameModeDialog extends JDialog {
Map players = new HashMap<>();
players.put(Color.WHITE, new NaturalPlayer(boardPanel.getBoard(), Color.WHITE, boardPanel));
players.put(Color.BLACK, new AIPlayer(boardPanel.getBoard(), Color.BLACK));
- new Game(players, boardPanel.getBoard(), boardPanel).start();
- dispose();
+ startGame(players, boardPanel);
});
getContentPane().add(btnAI);
@@ -59,9 +58,13 @@ public class GameModeDialog extends JDialog {
Map players = new HashMap<>();
players.put(Color.WHITE, new AIPlayer(boardPanel.getBoard(), Color.WHITE));
players.put(Color.BLACK, new AIPlayer(boardPanel.getBoard(), Color.BLACK));
- new Game(players, boardPanel.getBoard(), boardPanel).start();
- dispose();
+ startGame(players, boardPanel);
});
getContentPane().add(btnAI2);
}
+
+ private void startGame(Map players, BoardPanel boardPanel) {
+ new Game(players, boardPanel.getBoard(), boardPanel).start();
+ dispose();
+ }
}