Added simple (yet surprisingly effective) AI player
+ AIPlayer class + Evaluation method in Board + AI vs AI button in GameModeDialog (produces a rendering delay)
This commit is contained in:
parent
716c84bf49
commit
9ab00fe674
@ -131,6 +131,36 @@ public class Board {
|
|||||||
: getMoves(color).isEmpty() ? GameEventType.STALEMATE : GameEventType.NONE;
|
: getMoves(color).isEmpty() ? GameEventType.STALEMATE : GameEventType.NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Evaluated the board.
|
||||||
|
*
|
||||||
|
* @param color The color to evaluate for
|
||||||
|
* @return An positive number representing how good the position is
|
||||||
|
*/
|
||||||
|
public int evaluate(Color color) {
|
||||||
|
int score = 0;
|
||||||
|
for (int i = 0; i < 8; i++)
|
||||||
|
for (int j = 0; j < 8; j++)
|
||||||
|
if (boardArr[i][j] != null && boardArr[i][j].getColor() == color) switch (boardArr[i][j].getType()) {
|
||||||
|
case QUEEN:
|
||||||
|
score += 8;
|
||||||
|
break;
|
||||||
|
case ROOK:
|
||||||
|
score += 5;
|
||||||
|
break;
|
||||||
|
case KNIGHT:
|
||||||
|
score += 3;
|
||||||
|
break;
|
||||||
|
case BISHOP:
|
||||||
|
score += 3;
|
||||||
|
break;
|
||||||
|
case PAWN:
|
||||||
|
score += 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return score;
|
||||||
|
}
|
||||||
|
|
||||||
public void registerGameEventListener(GameEventListener listener) {
|
public void registerGameEventListener(GameEventListener listener) {
|
||||||
gameEventListeners.add(listener);
|
gameEventListeners.add(listener);
|
||||||
}
|
}
|
||||||
|
47
src/dev/kske/chess/game/AIPlayer.java
Normal file
47
src/dev/kske/chess/game/AIPlayer.java
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
package dev.kske.chess.game;
|
||||||
|
|
||||||
|
import dev.kske.chess.board.Board;
|
||||||
|
import dev.kske.chess.board.Move;
|
||||||
|
import dev.kske.chess.board.Piece;
|
||||||
|
import dev.kske.chess.board.Piece.Color;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Project: <strong>Chess</strong><br>
|
||||||
|
* File: <strong>AIPlayer.java</strong><br>
|
||||||
|
* Created: <strong>06.07.2019</strong><br>
|
||||||
|
* Author: <strong>Kai S. K. Engelbart</strong>
|
||||||
|
*/
|
||||||
|
public class AIPlayer extends Player {
|
||||||
|
|
||||||
|
private Move bestMove;
|
||||||
|
|
||||||
|
public AIPlayer(Board board, Color color) {
|
||||||
|
super(board, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void requestMove() {
|
||||||
|
findBestMove(board, color, 0);
|
||||||
|
game.onMove(this, bestMove);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int findBestMove(Board board, Color color, int depth) {
|
||||||
|
int bestValue = Integer.MIN_VALUE;
|
||||||
|
for (Move move : board.getMoves(color)) {
|
||||||
|
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 (valueChange > bestValue) {
|
||||||
|
bestValue = valueChange;
|
||||||
|
if (depth == 0) bestMove = move;
|
||||||
|
}
|
||||||
|
|
||||||
|
board.revert(move, capturePiece);
|
||||||
|
}
|
||||||
|
return bestValue;
|
||||||
|
}
|
||||||
|
}
|
@ -5,6 +5,7 @@ import java.util.Map;
|
|||||||
import dev.kske.chess.board.Board;
|
import dev.kske.chess.board.Board;
|
||||||
import dev.kske.chess.board.Move;
|
import dev.kske.chess.board.Move;
|
||||||
import dev.kske.chess.board.Piece.Color;
|
import dev.kske.chess.board.Piece.Color;
|
||||||
|
import dev.kske.chess.ui.BoardPanel;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Project: <strong>Chess</strong><br>
|
* Project: <strong>Chess</strong><br>
|
||||||
@ -16,10 +17,12 @@ public class Game {
|
|||||||
|
|
||||||
private Map<Color, Player> players;
|
private Map<Color, Player> players;
|
||||||
private Board board;
|
private Board board;
|
||||||
|
private BoardPanel boardPanel;
|
||||||
|
|
||||||
public Game(Map<Color, Player> players, Board board) {
|
public Game(Map<Color, Player> players, Board board, BoardPanel boardPanel) {
|
||||||
this.players = players;
|
this.players = players;
|
||||||
this.board = board;
|
this.board = board;
|
||||||
|
this.boardPanel = boardPanel;
|
||||||
|
|
||||||
// Initialize the game variable in each player
|
// Initialize the game variable in each player
|
||||||
players.values().forEach(player -> player.setGame(this));
|
players.values().forEach(player -> player.setGame(this));
|
||||||
@ -32,6 +35,7 @@ public class Game {
|
|||||||
public void onMove(Player player, Move move) {
|
public void onMove(Player player, Move move) {
|
||||||
if (board.getPos(move).getColor() == player.color && board.attemptMove(move)) {
|
if (board.getPos(move).getColor() == player.color && board.attemptMove(move)) {
|
||||||
System.out.printf("%s: %s%n", player.color, move);
|
System.out.printf("%s: %s%n", player.color, move);
|
||||||
|
boardPanel.repaint();
|
||||||
players.get(player.color.opposite()).requestMove();
|
players.get(player.color.opposite()).requestMove();
|
||||||
} else {
|
} else {
|
||||||
System.out.printf("%s: Illegal move!%n", player.getColor());
|
System.out.printf("%s: Illegal move!%n", player.getColor());
|
||||||
|
@ -8,6 +8,7 @@ import javax.swing.JButton;
|
|||||||
import javax.swing.JDialog;
|
import javax.swing.JDialog;
|
||||||
|
|
||||||
import dev.kske.chess.board.Piece.Color;
|
import dev.kske.chess.board.Piece.Color;
|
||||||
|
import dev.kske.chess.game.AIPlayer;
|
||||||
import dev.kske.chess.game.Game;
|
import dev.kske.chess.game.Game;
|
||||||
import dev.kske.chess.game.NaturalPlayer;
|
import dev.kske.chess.game.NaturalPlayer;
|
||||||
import dev.kske.chess.game.Player;
|
import dev.kske.chess.game.Player;
|
||||||
@ -29,7 +30,7 @@ public class GameModeDialog extends JDialog {
|
|||||||
super();
|
super();
|
||||||
setModal(true);
|
setModal(true);
|
||||||
setTitle("Game Mode Selection");
|
setTitle("Game Mode Selection");
|
||||||
setBounds(100, 100, 231, 99);
|
setBounds(100, 100, 231, 133);
|
||||||
setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
|
setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
|
||||||
getContentPane().setLayout(new FlowLayout(FlowLayout.CENTER, 5, 5));
|
getContentPane().setLayout(new FlowLayout(FlowLayout.CENTER, 5, 5));
|
||||||
|
|
||||||
@ -38,12 +39,29 @@ public class GameModeDialog extends JDialog {
|
|||||||
Map<Color, Player> players = new HashMap<>();
|
Map<Color, Player> players = new HashMap<>();
|
||||||
players.put(Color.WHITE, new NaturalPlayer(boardPanel.getBoard(), Color.WHITE, boardPanel));
|
players.put(Color.WHITE, new NaturalPlayer(boardPanel.getBoard(), Color.WHITE, boardPanel));
|
||||||
players.put(Color.BLACK, new NaturalPlayer(boardPanel.getBoard(), Color.BLACK, boardPanel));
|
players.put(Color.BLACK, new NaturalPlayer(boardPanel.getBoard(), Color.BLACK, boardPanel));
|
||||||
new Game(players, boardPanel.getBoard()).start();
|
new Game(players, boardPanel.getBoard(), boardPanel).start();
|
||||||
dispose();
|
dispose();
|
||||||
});
|
});
|
||||||
getContentPane().add(btnNatural);
|
getContentPane().add(btnNatural);
|
||||||
|
|
||||||
JButton btnAI = new JButton("Game against AI");
|
JButton btnAI = new JButton("Game against AI");
|
||||||
|
btnAI.addActionListener((evt) -> {
|
||||||
|
Map<Color, Player> 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();
|
||||||
|
});
|
||||||
getContentPane().add(btnAI);
|
getContentPane().add(btnAI);
|
||||||
|
|
||||||
|
JButton btnAI2 = new JButton("AI against AI");
|
||||||
|
btnAI2.addActionListener((evt) -> {
|
||||||
|
Map<Color, Player> 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();
|
||||||
|
});
|
||||||
|
getContentPane().add(btnAI2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user