This repository has been archived on 2021-02-18. You can view files and clone it, but cannot push or open issues or pull requests.
chess/src/main/java/dev/kske/chess/game/Game.java

200 lines
5.8 KiB
Java

package dev.kske.chess.game;
import java.util.*;
import javax.swing.JOptionPane;
import dev.kske.chess.board.*;
import dev.kske.chess.board.Piece.Color;
import dev.kske.chess.event.*;
import dev.kske.chess.game.ai.AIPlayer;
import dev.kske.chess.io.EngineUtil;
import dev.kske.chess.io.EngineUtil.EngineInfo;
import dev.kske.chess.ui.*;
import dev.kske.eventbus.EventBus;
/**
* Project: <strong>Chess</strong><br>
* File: <strong>Game.java</strong><br>
* Created: <strong>06.07.2019</strong><br>
*
* @since Chess v0.1-alpha
* @author Kai S. K. Engelbart
*/
public class Game {
private Map<Color, Player> players = new EnumMap<>(Color.class);
private Board board;
private OverlayComponent overlayComponent;
private BoardComponent boardComponent;
/**
* Initializes game with a new {@link Board}.
*
* @param boardPane the board pane which will display the newly created
* board
* @param whiteName the name of the player controlling the white pieces
* @param blackName the name of the player controlling the black pieces
*/
public Game(BoardPane boardPane, String whiteName, String blackName) {
board = new Board();
init(boardPane, whiteName, blackName);
}
/**
* Initializes game with an existing {@link Board}.
*
* @param boardPane the board pane which will display the newly created
* board
* @param whiteName the name of the player controlling the white pieces
* @param blackName the name of the player controlling the black pieces
* @param board the board on which the game will be played
*/
public Game(
BoardPane boardPane, String whiteName, String blackName, Board board
) {
this.board = board;
init(boardPane, whiteName, blackName);
}
private void init(BoardPane boardPane, String whiteName, String blackName) {
// Initialize / synchronize UI
overlayComponent = boardPane.getOverlayComponent();
boardComponent = boardPane.getBoardComponent();
boardComponent.setBoard(board);
// Initialize players
players.put(Color.WHITE, getPlayer(whiteName, Color.WHITE));
players.put(Color.BLACK, getPlayer(blackName, Color.BLACK));
}
/**
* Initializes player subclass.
*
* @param name the name of the player. {@code Natural Player} will
* initialize a
* {@link NaturalPlayer}, {@code AI Player} will initialize an
* {@link AIPlayer}. Everything else will attempt to load an
* engine
* with that name
* @param color the color of the player
* @return the instantiated player or {@code null} if the name could not be
* recognized
*/
private Player getPlayer(String name, Color color) {
switch (name) {
case "Natural Player":
return new NaturalPlayer(this, color, overlayComponent);
case "AI Player":
return new AIPlayer(this, color, 4, -10);
default:
for (EngineInfo info : EngineUtil.getEngineInfos())
if (info.name.equals(name))
return new UCIPlayer(this, color, info.path);
System.err.println("Invalid player name: " + name);
return null;
}
}
/**
* Should be called once a player makes a move. Depending on the legality of
* that move and the state of the game another move might be requested from
* one
* of the players.
*
* @param player the player who generated the move
* @param move the generated move
*/
public synchronized void onMove(Player player, Move move) {
if (
board.getPos(move).getColor() == player.color
&& board.attemptMove(move)
) {
// Redraw
boardComponent.repaint();
overlayComponent.displayArrow(move);
// Run garbage collection
System.gc();
BoardState boardState
= board.getState(board.getDest(move).getColor().opposite());
EventBus.getInstance().dispatch(new MoveEvent(move, boardState));
switch (boardState) {
case CHECKMATE:
case STALEMATE:
String result = String.format(
"%s in %s!%n",
player.color.opposite(),
boardState
);
System.out.print(result);
JOptionPane.showMessageDialog(boardComponent, result);
break;
case CHECK:
System.out
.printf("%s in check!%n", player.color.opposite());
default:
players.get(board.getLog().getActiveColor()).requestMove();
}
} else
player.requestMove();
}
/**
* Starts the game by requesting a move from the player of the currently
* active
* color.
*/
public synchronized void start() {
EventBus.getInstance().dispatch(new GameStartEvent(this));
players.get(board.getLog().getActiveColor()).requestMove();
}
/**
* Cancels move calculations, initializes the default position and clears
* the
* {@link OverlayComponent}.
*/
public synchronized void reset() {
players.values().forEach(Player::cancelMove);
board.initDefaultPositions();
boardComponent.repaint();
overlayComponent.clearDots();
overlayComponent.clearArrow();
}
/**
* Stops the game by disconnecting its players from the UI.
*/
public synchronized void stop() {
players.values().forEach(Player::disconnect);
}
/**
* Assigns the players their opposite colors.
*/
public synchronized void swapColors() {
players.values().forEach(Player::cancelMove);
Player white = players.get(Color.WHITE);
Player black = players.get(Color.BLACK);
white.setColor(Color.BLACK);
black.setColor(Color.WHITE);
players.put(Color.WHITE, black);
players.put(Color.BLACK, white);
players.get(board.getLog().getActiveColor()).requestMove();
}
/**
* @return The board on which this game's moves are made
*/
public Board getBoard() { return board; }
/**
* @return The players participating in this game
*/
public Map<Color, Player> getPlayers() { return players; }
}