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
73316c6681
commit
dd5170066b
@ -131,6 +131,36 @@ public class Board {
|
||||
: 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) {
|
||||
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.Move;
|
||||
import dev.kske.chess.board.Piece.Color;
|
||||
import dev.kske.chess.ui.BoardPanel;
|
||||
|
||||
/**
|
||||
* Project: <strong>Chess</strong><br>
|
||||
@ -16,10 +17,12 @@ public class Game {
|
||||
|
||||
private Map<Color, Player> players;
|
||||
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.board = board;
|
||||
this.boardPanel = boardPanel;
|
||||
|
||||
// Initialize the game variable in each player
|
||||
players.values().forEach(player -> player.setGame(this));
|
||||
@ -32,6 +35,7 @@ public class Game {
|
||||
public void onMove(Player player, Move move) {
|
||||
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();
|
||||
} else {
|
||||
System.out.printf("%s: Illegal move!%n", player.getColor());
|
||||
|
@ -8,6 +8,7 @@ import javax.swing.JButton;
|
||||
import javax.swing.JDialog;
|
||||
|
||||
import dev.kske.chess.board.Piece.Color;
|
||||
import dev.kske.chess.game.AIPlayer;
|
||||
import dev.kske.chess.game.Game;
|
||||
import dev.kske.chess.game.NaturalPlayer;
|
||||
import dev.kske.chess.game.Player;
|
||||
@ -29,7 +30,7 @@ public class GameModeDialog extends JDialog {
|
||||
super();
|
||||
setModal(true);
|
||||
setTitle("Game Mode Selection");
|
||||
setBounds(100, 100, 231, 99);
|
||||
setBounds(100, 100, 231, 133);
|
||||
setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
|
||||
getContentPane().setLayout(new FlowLayout(FlowLayout.CENTER, 5, 5));
|
||||
|
||||
@ -38,12 +39,29 @@ public class GameModeDialog extends JDialog {
|
||||
Map<Color, Player> players = new HashMap<>();
|
||||
players.put(Color.WHITE, new NaturalPlayer(boardPanel.getBoard(), Color.WHITE, 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();
|
||||
});
|
||||
getContentPane().add(btnNatural);
|
||||
|
||||
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);
|
||||
|
||||
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