almost working
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
package chess;
|
package chess;
|
||||||
|
|
||||||
|
import chess.ai.AlphaBetaAI;
|
||||||
import chess.ai.DumbAI;
|
import chess.ai.DumbAI;
|
||||||
import chess.ai.HungryAI;
|
import chess.ai.HungryAI;
|
||||||
import chess.controller.CommandExecutor;
|
import chess.controller.CommandExecutor;
|
||||||
@@ -18,12 +19,15 @@ public class SwingMain {
|
|||||||
Window window = new Window(commandExecutor, false);
|
Window window = new Window(commandExecutor, false);
|
||||||
commandExecutor.addListener(window);
|
commandExecutor.addListener(window);
|
||||||
|
|
||||||
DumbAI ai = new DumbAI(commandExecutor, Color.Black);
|
DumbAI ai = new DumbAI(commandExecutor, Color.White);
|
||||||
commandExecutor.addListener(ai);
|
commandExecutor.addListener(ai);
|
||||||
|
|
||||||
HungryAI ai2 = new HungryAI(commandExecutor, Color.White);
|
AlphaBetaAI ai2 = new AlphaBetaAI(commandExecutor, Color.Black, 3);
|
||||||
commandExecutor.addListener(ai2);
|
commandExecutor.addListener(ai2);
|
||||||
|
|
||||||
|
// Window window2 = new Window(ai2.getSimulation(), false);
|
||||||
|
// ai2.getSimulation().addListener(window2);
|
||||||
|
|
||||||
commandExecutor.addListener(new GameAdaptator(){
|
commandExecutor.addListener(new GameAdaptator(){
|
||||||
@Override
|
@Override
|
||||||
public void onGameEnd() {
|
public void onGameEnd() {
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import java.util.List;
|
|||||||
|
|
||||||
import chess.controller.Command;
|
import chess.controller.Command;
|
||||||
import chess.controller.CommandExecutor;
|
import chess.controller.CommandExecutor;
|
||||||
|
import chess.controller.Command.CommandResult;
|
||||||
import chess.controller.commands.GetPieceAtCommand;
|
import chess.controller.commands.GetPieceAtCommand;
|
||||||
import chess.controller.commands.GetPlayerMovesCommand;
|
import chess.controller.commands.GetPlayerMovesCommand;
|
||||||
import chess.controller.commands.GetAllowedCastlingsCommand;
|
import chess.controller.commands.GetAllowedCastlingsCommand;
|
||||||
@@ -50,8 +51,12 @@ public abstract class AI extends GameAdaptator{
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected List<Move> getAllowedMoves() {
|
protected List<Move> getAllowedMoves() {
|
||||||
|
return getAllowedMoves(this.commandExecutor);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected List<Move> getAllowedMoves(CommandExecutor commandExecutor) {
|
||||||
GetPlayerMovesCommand cmd = new GetPlayerMovesCommand();
|
GetPlayerMovesCommand cmd = new GetPlayerMovesCommand();
|
||||||
sendCommand(cmd);
|
sendCommand(cmd, commandExecutor);
|
||||||
return cmd.getMoves();
|
return cmd.getMoves();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,8 +66,16 @@ public abstract class AI extends GameAdaptator{
|
|||||||
return cmd2.getCastlingResult();
|
return cmd2.getCastlingResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void sendCommand(Command command) {
|
protected CommandResult sendCommand(Command command) {
|
||||||
this.commandExecutor.executeCommand(command);
|
return sendCommand(command, this.commandExecutor);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected CommandResult sendCommand(Command command, CommandExecutor commandExecutor) {
|
||||||
|
CommandResult result = commandExecutor.executeCommand(command);
|
||||||
|
if(result == CommandResult.NotAllowed){
|
||||||
|
System.out.println("eeeeee");
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
141
app/src/main/java/chess/ai/AlphaBetaAI.java
Normal file
141
app/src/main/java/chess/ai/AlphaBetaAI.java
Normal file
@@ -0,0 +1,141 @@
|
|||||||
|
package chess.ai;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
import chess.controller.CommandExecutor;
|
||||||
|
import chess.controller.commands.CastlingCommand;
|
||||||
|
import chess.controller.commands.MoveCommand;
|
||||||
|
import chess.controller.commands.NewGameCommand;
|
||||||
|
import chess.controller.commands.PromoteCommand;
|
||||||
|
import chess.controller.commands.PromoteCommand.PromoteType;
|
||||||
|
import chess.controller.commands.UndoCommand;
|
||||||
|
import chess.model.ChessBoard;
|
||||||
|
import chess.model.Color;
|
||||||
|
import chess.model.Coordinate;
|
||||||
|
import chess.model.Game;
|
||||||
|
import chess.model.Move;
|
||||||
|
|
||||||
|
public class AlphaBetaAI extends AI {
|
||||||
|
|
||||||
|
private final int searchDepth;
|
||||||
|
private final PieceCost pieceCost;
|
||||||
|
private final CommandExecutor simulation;
|
||||||
|
private final Game gameSimulation;
|
||||||
|
|
||||||
|
public AlphaBetaAI(CommandExecutor commandExecutor, Color color, int searchDepth) {
|
||||||
|
super(commandExecutor, color);
|
||||||
|
this.searchDepth = 3;
|
||||||
|
this.pieceCost = new PieceCost(color);
|
||||||
|
this.gameSimulation = new Game();
|
||||||
|
this.simulation = new CommandExecutor(this.gameSimulation);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CommandExecutor getSimulation() {
|
||||||
|
return simulation;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getBoardEvaluation() {
|
||||||
|
final ChessBoard board = this.gameSimulation.getBoard();
|
||||||
|
int result = 0;
|
||||||
|
for (int i = 0; i < Coordinate.VALUE_MAX; i++) {
|
||||||
|
for (int j = 0; j < Coordinate.VALUE_MAX; j++) {
|
||||||
|
result += pieceCost.getCost(board.pieceAt(new Coordinate(i, j)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int negaMax(int depth, int alpha, int beta) {
|
||||||
|
if (depth == 0)
|
||||||
|
return getBoardEvaluation();
|
||||||
|
|
||||||
|
int value = Integer.MIN_VALUE;
|
||||||
|
|
||||||
|
List<Move> moves = getAllowedMoves(this.simulation);
|
||||||
|
|
||||||
|
if (moves.isEmpty()) {
|
||||||
|
System.out.println("oaaaaaaaaa");
|
||||||
|
int board = getBoardEvaluation();
|
||||||
|
int result = board + (this.gameSimulation.getPlayerTurn() == this.color ? -100 : 100);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Move move : moves) {
|
||||||
|
sendCommand(new MoveCommand(move), this.simulation);
|
||||||
|
if (this.gameSimulation.getBoard().pawnShouldBePromoted())
|
||||||
|
sendCommand(new PromoteCommand(PromoteType.Queen), this.simulation);
|
||||||
|
int leaveValue = -negaMax(depth - 1, -beta, -alpha);
|
||||||
|
value = Integer.max(value, leaveValue);
|
||||||
|
sendCommand(new UndoCommand(), this.simulation);
|
||||||
|
alpha = Integer.max(alpha, value);
|
||||||
|
if (alpha >= beta)
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Move getBestMove() {
|
||||||
|
List<Move> moves = getAllowedMoves(this.simulation);
|
||||||
|
int bestMove = Integer.MIN_VALUE;
|
||||||
|
List<Move> bestMoves = new ArrayList<>(20);
|
||||||
|
|
||||||
|
for (Move move : moves) {
|
||||||
|
sendCommand(new MoveCommand(move), this.simulation);
|
||||||
|
if (this.gameSimulation.getBoard().pawnShouldBePromoted())
|
||||||
|
sendCommand(new PromoteCommand(PromoteType.Queen), this.simulation);
|
||||||
|
int value = -negaMax(this.searchDepth - 1, Integer.MIN_VALUE, Integer.MAX_VALUE);
|
||||||
|
sendCommand(new UndoCommand(), this.simulation);
|
||||||
|
if (value > bestMove) {
|
||||||
|
bestMove = value;
|
||||||
|
bestMoves.clear();
|
||||||
|
bestMoves.add(move);
|
||||||
|
} else if (value == bestMove) {
|
||||||
|
bestMoves.add(move);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.println("Best move : " + bestMove + " count : " + bestMoves.size());
|
||||||
|
|
||||||
|
return bestMoves.get(new Random().nextInt(bestMoves.size()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onGameStart() {
|
||||||
|
sendCommand(new NewGameCommand(), this.simulation);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPawnPromoted(PromoteType promotion, Color player) {
|
||||||
|
// if (player == this.color)
|
||||||
|
// return;
|
||||||
|
sendCommand(new PromoteCommand(promotion), this.simulation);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCastling(boolean bigCastling) {
|
||||||
|
sendCommand(new CastlingCommand(bigCastling), this.simulation);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onMove(Move move) {
|
||||||
|
sendCommand(new MoveCommand(move), this.simulation);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void play() {
|
||||||
|
long current = System.currentTimeMillis();
|
||||||
|
Move move = getBestMove();
|
||||||
|
long elapsed = System.currentTimeMillis() - current;
|
||||||
|
System.out.println("Took " + elapsed + "ms");
|
||||||
|
sendCommand(new MoveCommand(move));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void promote(Coordinate pawnCoords) {
|
||||||
|
sendCommand(new PromoteCommand(PromoteType.Queen));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -55,7 +55,6 @@ public class CommandExecutor {
|
|||||||
this.dispatcher.onBoardUpdate();
|
this.dispatcher.onBoardUpdate();
|
||||||
if (checkGameStatus()) {
|
if (checkGameStatus()) {
|
||||||
this.dispatcher.onGameEnd();
|
this.dispatcher.onGameEnd();
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
switchPlayerTurn(command instanceof UndoCommand);
|
switchPlayerTurn(command instanceof UndoCommand);
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -49,6 +49,8 @@ public class CastlingCommand extends PlayerCommand {
|
|||||||
board.applyMove(this.kingMove);
|
board.applyMove(this.kingMove);
|
||||||
board.applyMove(this.rookMove);
|
board.applyMove(this.rookMove);
|
||||||
|
|
||||||
|
outputSystem.onCastling(this.bigCastling);
|
||||||
|
|
||||||
return CommandResult.Moved;
|
return CommandResult.Moved;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -37,7 +37,6 @@ public class MoveCommand extends PlayerCommand {
|
|||||||
return result;
|
return result;
|
||||||
|
|
||||||
case Moved:
|
case Moved:
|
||||||
outputSystem.onMove(this.move);
|
|
||||||
game.saveTraitPiecesPos();
|
game.saveTraitPiecesPos();
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
@@ -76,11 +75,14 @@ public class MoveCommand extends PlayerCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (tryPromote(game, outputSystem)) {
|
if (tryPromote(game, outputSystem)) {
|
||||||
|
outputSystem.onMove(this.move);
|
||||||
return CommandResult.ActionNeeded;
|
return CommandResult.ActionNeeded;
|
||||||
}
|
}
|
||||||
|
|
||||||
board.setLastMove(this.move);
|
board.setLastMove(this.move);
|
||||||
|
|
||||||
|
outputSystem.onMove(this.move);
|
||||||
|
|
||||||
return CommandResult.Moved;
|
return CommandResult.Moved;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -55,6 +55,8 @@ public class PromoteCommand extends PlayerCommand {
|
|||||||
this.oldPawn = pawn;
|
this.oldPawn = pawn;
|
||||||
board.pieceComes(createPiece(this.promoteType, pawn.getColor()), this.pieceCoords);
|
board.pieceComes(createPiece(this.promoteType, pawn.getColor()), this.pieceCoords);
|
||||||
|
|
||||||
|
outputSystem.onPawnPromoted(this.promoteType, game.getPlayerTurn());
|
||||||
|
|
||||||
return CommandResult.Moved;
|
return CommandResult.Moved;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package chess.controller.event;
|
package chess.controller.event;
|
||||||
|
|
||||||
|
import chess.controller.commands.PromoteCommand.PromoteType;
|
||||||
import chess.model.Color;
|
import chess.model.Color;
|
||||||
import chess.model.Coordinate;
|
import chess.model.Coordinate;
|
||||||
import chess.model.Move;
|
import chess.model.Move;
|
||||||
@@ -45,4 +46,10 @@ public abstract class GameAdaptator implements GameListener {
|
|||||||
@Override
|
@Override
|
||||||
public void onDraw() {}
|
public void onDraw() {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCastling(boolean bigCastling) {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPawnPromoted(PromoteType promotion, Color player) {}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import java.util.concurrent.ExecutorService;
|
|||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
import chess.controller.commands.PromoteCommand.PromoteType;
|
||||||
import chess.model.Color;
|
import chess.model.Color;
|
||||||
import chess.model.Coordinate;
|
import chess.model.Coordinate;
|
||||||
import chess.model.Move;
|
import chess.model.Move;
|
||||||
@@ -93,6 +94,16 @@ public class GameDispatcher implements GameListener {
|
|||||||
asyncForEachCall((l) -> l.onDraw());
|
asyncForEachCall((l) -> l.onDraw());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCastling(boolean bigCastling) {
|
||||||
|
asyncForEachCall((l) -> l.onCastling(bigCastling));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPawnPromoted(PromoteType promotion, Color player) {
|
||||||
|
asyncForEachCall((l) -> l.onPawnPromoted(promotion, player));
|
||||||
|
}
|
||||||
|
|
||||||
public void stopService() {
|
public void stopService() {
|
||||||
this.executor.shutdown();
|
this.executor.shutdown();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package chess.controller.event;
|
package chess.controller.event;
|
||||||
|
|
||||||
|
import chess.controller.commands.PromoteCommand.PromoteType;
|
||||||
import chess.model.Color;
|
import chess.model.Color;
|
||||||
import chess.model.Coordinate;
|
import chess.model.Coordinate;
|
||||||
import chess.model.Move;
|
import chess.model.Move;
|
||||||
@@ -15,7 +16,7 @@ public interface GameListener {
|
|||||||
* Invoked when a draw occurs (same position is repeated three times)
|
* Invoked when a draw occurs (same position is repeated three times)
|
||||||
*/
|
*/
|
||||||
void onDraw();
|
void onDraw();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invoked when the game has ended (by a win or a draw)
|
* Invoked when the game has ended (by a win or a draw)
|
||||||
*/
|
*/
|
||||||
@@ -25,7 +26,7 @@ public interface GameListener {
|
|||||||
* Invoked when the game has started
|
* Invoked when the game has started
|
||||||
*/
|
*/
|
||||||
void onGameStart();
|
void onGameStart();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invoked when a king is in check
|
* Invoked when a king is in check
|
||||||
*/
|
*/
|
||||||
@@ -35,47 +36,68 @@ public interface GameListener {
|
|||||||
* Invoked when a checkmate occurs
|
* Invoked when a checkmate occurs
|
||||||
*/
|
*/
|
||||||
void onKingInMat();
|
void onKingInMat();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invoked when a valid move on the board occurs
|
* Invoked when a valid move on the board occurs
|
||||||
|
*
|
||||||
* @param move the move to be processed
|
* @param move the move to be processed
|
||||||
*/
|
*/
|
||||||
void onMove(Move move);
|
void onMove(Move move);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invoked when a sent move is not allowed
|
* Invoked when a sent move is not allowed
|
||||||
|
*
|
||||||
* @param move the move to be processed
|
* @param move the move to be processed
|
||||||
*/
|
*/
|
||||||
void onMoveNotAllowed(Move move);
|
void onMoveNotAllowed(Move move);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invoked when a pat situation occurs
|
* Invoked when a pat situation occurs
|
||||||
*/
|
*/
|
||||||
void onPatSituation();
|
void onPatSituation();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invoked when it's the player turn
|
* Invoked when it's the player turn
|
||||||
* @param color the color of the player who should play
|
*
|
||||||
|
* @param color the color of the player who should play
|
||||||
* @param undone true if it's a result of an undo command
|
* @param undone true if it's a result of an undo command
|
||||||
*/
|
*/
|
||||||
void onPlayerTurn(Color color, boolean undone);
|
void onPlayerTurn(Color color, boolean undone);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invoked when a pawn should be promoted
|
* Invoked when a pawn should be promoted
|
||||||
|
*
|
||||||
* @param pieceCoords the coordinates of the pawn
|
* @param pieceCoords the coordinates of the pawn
|
||||||
*/
|
*/
|
||||||
void onPromotePawn(Coordinate pieceCoords);
|
void onPromotePawn(Coordinate pieceCoords);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invoked when a players surrenders
|
* Invoked when a players surrenders
|
||||||
|
*
|
||||||
* @param coward the player who gave up
|
* @param coward the player who gave up
|
||||||
*/
|
*/
|
||||||
void onSurrender(Color coward);
|
void onSurrender(Color coward);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invoked when a player wins (by checkmate or if the other one surrenders)
|
* Invoked when a player wins (by checkmate or if the other one surrenders)
|
||||||
|
*
|
||||||
* @param winner
|
* @param winner
|
||||||
*/
|
*/
|
||||||
void onWin(Color winner);
|
void onWin(Color winner);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoked when a castling is done
|
||||||
|
*
|
||||||
|
* @param bigCastling if it's queen side castling
|
||||||
|
*/
|
||||||
|
void onCastling(boolean bigCastling);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoked when a pawn is promoted
|
||||||
|
*
|
||||||
|
* @param promotion the type of promotion
|
||||||
|
* @param player the player who promoted the pawns
|
||||||
|
*/
|
||||||
|
void onPawnPromoted(PromoteType promotion, Color player);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -333,4 +333,11 @@ public class Console implements GameListener {
|
|||||||
this.captureInput = captureInput;
|
this.captureInput = captureInput;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCastling(boolean bigCastling) {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPawnPromoted(PromoteType promotion, Color player) {}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -318,4 +318,10 @@ public class Window extends JFrame implements GameListener {
|
|||||||
JOptionPane.showMessageDialog(this, "Same position was repeated three times. It's a draw!");
|
JOptionPane.showMessageDialog(this, "Same position was repeated three times. It's a draw!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCastling(boolean bigCastling) {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPawnPromoted(PromoteType promotion, chess.model.Color player) {}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user