Not an answer, but a simulation to help
I added a new class: GamePanel and edited Game and Controller
It isn't very pretty...yet. Did you know Unicode had chess characters!?!? (totally awesome!)
By the way, you need UTF-8 for these characters to show. It worked for me, but not sure how it will work on other operating systems.
Fixed end of games bug (thanks to tim for pointing that out).
GamePanel:
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class GamePanel extends JPanel{
private static final long serialVersionUID = 1L;
JFrame container;
Board currentBoard;
Game currentGame;
ArrayList<Game> games;
public GamePanel(ArrayList<Game> Games){
games = Games;
currentGame = games.get(0);
currentBoard = currentGame.allBoards.get(0);
container = new JFrame();
container.setSize(new Dimension(500,500));
container.setMinimumSize(new Dimension(150,150));
this.setMinimumSize(new Dimension(150,150));
JButton skipButton = new JButton("skip game");
skipButton.addMouseListener(new MouseListener(){
@Override
public void mouseClicked(MouseEvent arg0) {
nextGame();
}
@Override
public void mouseEntered(MouseEvent arg0) {
// TODO Auto-generated method stub
}
@Override
public void mouseExited(MouseEvent arg0) {
// TODO Auto-generated method stub
}
@Override
public void mousePressed(MouseEvent arg0) {
// TODO Auto-generated method stub
}
@Override
public void mouseReleased(MouseEvent arg0) {
// TODO Auto-generated method stub
}
});
JButton undoButton = new JButton("go back");
undoButton.addMouseListener(new MouseListener(){
@Override
public void mouseClicked(MouseEvent e) {
unStep();
}
@Override
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void mousePressed(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void mouseReleased(MouseEvent e) {
// TODO Auto-generated method stub
}
});
JButton continueButton = new JButton("continue");
undoButton.setSize(40,40);
skipButton.setSize(40,40);
continueButton.setSize(40,40);
continueButton.addMouseListener(new MouseListener(){
@Override
public void mouseClicked(MouseEvent arg0) {
step();
}
@Override
public void mouseEntered(MouseEvent arg0) {
}
@Override
public void mouseExited(MouseEvent arg0) {
}
@Override
public void mousePressed(MouseEvent arg0) {
}
@Override
public void mouseReleased(MouseEvent arg0) {
}
});
JPanel buttonPanel = new JPanel();
buttonPanel.setLayout(new FlowLayout());
buttonPanel.add(continueButton);
buttonPanel.add(undoButton);
buttonPanel.add(skipButton);
container.setLayout(new BorderLayout());
container.getContentPane().add(this,BorderLayout.CENTER);
container.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
container.getContentPane().add(buttonPanel,BorderLayout.NORTH);
container.setTitle("White: " + currentGame.players[0].getClass().getSimpleName()
+ " vs "+ "Black: " + currentGame.players[1].getClass().getSimpleName());
container.setVisible(true);
container.invalidate();
container.repaint();
}
private void unStep(){
if(currentBoard!=currentGame.allBoards.get(0)){
currentBoard=currentGame.allBoards.get(currentGame.allBoards.indexOf(currentBoard)-1);
}
container.invalidate();
container.repaint();
}
private void unGame(){
if(currentGame != games.get(0)){
currentGame = games.get(games.indexOf(currentGame)-1);
currentBoard = currentGame.allBoards.get(0);
}
container.invalidate();
container.repaint();
}
private void step(){
if(currentGame.allBoards.indexOf(currentBoard)==currentGame.allBoards.size()-1){
nextGame();
}
else{
currentBoard = currentGame.allBoards.get(currentGame.allBoards.indexOf(currentBoard)+1);
}
container.invalidate();
container.repaint();
}
private void nextGame(){
container.setTitle("White: " + currentGame.players[0].getClass().getSimpleName()
+ " vs "+ "Black: " + currentGame.players[1].getClass().getSimpleName());
if(currentGame != games.get(games.size()-1)){
currentGame = games.get(games.indexOf(currentGame)+1);
}
else{
//games complete
container.dispose();
}
currentBoard = currentGame.allBoards.get(0);
container.invalidate();
container.repaint();
}
@Override
public void paintComponent(Graphics g){
if(getWidth()>150 && getHeight() > 150){
int leftBounds,topBounds,width,height;
topBounds = 50;
leftBounds = 50;
if(getWidth() > getHeight()){
width = (int) (getHeight()-100);
height = (int) (getHeight()-100);
}
else{
width = (int) (getWidth()-100);
height = (int) (getWidth()-100);
}
//draw grid
java.awt.Color dark = new java.awt.Color(128, 78, 41);
java.awt.Color light = new java.awt.Color(250, 223, 173);
Field[][] feilds = currentBoard.getFields();
for(int x = leftBounds; x < leftBounds+width-width/8; x+=width/8){
for(int y = topBounds; y < topBounds+height-height/8; y+=height/8){
int xPos = (int)Math.round(((double)(x-leftBounds)/(double)width)*8);
int yPos = (int)Math.round(((double)(y-topBounds)/(double)height)*8);
String piece = "";
java.awt.Color stringColor = java.awt.Color.black;
if(feilds[xPos][yPos].hasPiece()){
piece = getPiece(feilds[xPos][yPos].getPiece());
if(feilds[xPos][yPos].getPiece().getTeam()==Color.WHITE){stringColor = java.awt.Color.WHITE;}
}
if(yPos % 2 == 1){
if(xPos % 2 == 1){
g.setColor(dark);
g.fillRect(x, y, width/8, height/8);
}
else{
g.setColor(light);
g.fillRect(x, y, width/8, height/8);
}
}
else{
if(xPos % 2 == 1){
g.setColor(light);
g.fillRect(x, y, width/8, height/8);
}
else{
g.setColor(dark);
g.fillRect(x, y, width/8, height/8);
}
}
g.setColor(java.awt.Color.black);
g.setFont(new Font(Font.SANS_SERIF, Font.BOLD, width/8));
g.drawString(piece, x, y+width/8);
}
}
}
}
public String getPiece(Piece p){
if(p.getTeam() == Color.WHITE){
if(p.getType() == PieceType.BISHOP){return "\u2657";}
if(p.getType() == PieceType.PAWN){return "\u2659";}
if(p.getType() == PieceType.KING){return "\u2654";}
if(p.getType() == PieceType.QUEEN){return "\u2655";}
if(p.getType() == PieceType.ROOK){return "\u2656";}
if(p.getType() == PieceType.KNIGHT){return "\u2658";}
}
else{
if(p.getType() == PieceType.BISHOP){return "\u265D";}
if(p.getType() == PieceType.PAWN){return "\u265F";}
if(p.getType() == PieceType.KING){return "\u265A";}
if(p.getType() == PieceType.QUEEN){return "\u265B";}
if(p.getType() == PieceType.ROOK){return "\u265C";}
if(p.getType() == PieceType.KNIGHT){return "\u265E";}
}
return p.toString();
}
}
Game:
import java.util.ArrayList;
public class Game {
private static final int MAX_TURNS_WITHOUT_CAPTURES = 100; //=50, counts for both teams
private static final int MAX_MILLISECONDS = 2000;
private Board board;
Player[] players = new Player[2];
private int turnsWithoutCaptures = 0;
private boolean draw = false;
ArrayList<Board> allBoards = new ArrayList<Board>();
public Game(Player player1, Player player2) {
board = new Board();
board.initialize();
players[0] = player1;
players[0].setTeam(Color.WHITE);
players[1] = player2;
players[1].setTeam(Color.BLACK);
allBoards.add(board.copy());
}
int run() {
int i = 0;
while (!gameOver()) {
if (!turnAvailable(players[i])) {
draw = true;
} else {
makeTurn(players[i], players[(i+1) % 2]);
i = (i + 1) % 2;
}
}
if (loses(players[0]) && !loses(players[1])) {
return Controller.LOSE_POINTS;
} else if (loses(players[1]) && !loses(players[0])) {
return Controller.WIN_POINTS;
} else {
return Controller.DRAW_POINTS;
}
}
private boolean loses(Player player) {
if (player.isDisqualified() || board.getKing(player) == null) {
return true;
}
return false;
}
// player can make a turn
private boolean turnAvailable(Player player) {
for (Piece piece : player.getPieces(board)) {
if (piece.getValidDestinationSet(board).size() > 0) {
return true;
}
}
return false;
}
private void makeTurn(Player player, Player enemy) {
player.setCheck(board.isCheck(player, enemy));
enemy.setCheck(board.isCheck(enemy, player));
try {
long start = System.currentTimeMillis();
Move move = player.getMove(board.copy(), enemy);
if ((System.currentTimeMillis() - start) > MAX_MILLISECONDS) {
player.setDisqualified();
}
if (move.isValid(board, player)) {
if (board.movePiece(move) || move.getPiece().getType() == PieceType.PAWN) {
turnsWithoutCaptures = 0;
} else {
turnsWithoutCaptures++;
}
} else {
player.setDisqualified(); //invalid move
}
} catch (Exception e) {
player.setDisqualified();
e.printStackTrace();
System.out.println("Exception while moving " + player);
}
allBoards.add(board.copy());
}
public boolean gameOver() {
for (Player player : players) {
if (player.isDisqualified() || board.getKing(player) == null
|| turnsWithoutCaptures >= MAX_TURNS_WITHOUT_CAPTURES || draw) {
return true;
}
}
return false;
}
}
Controller:
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import players.*;
public class Controller {
public static final int WIN_POINTS = 3;
public static final int DRAW_POINTS = 1;
public static final int LOSE_POINTS = 0;
private static final int GAMES_PER_PAIR = 10;
private final Class[] classes = {StretchPlayer.class,TestPlayer.class};
private final Map<Class<? extends Player>, Integer> scores = new HashMap<Class<? extends Player>, Integer>();
public static void main(String... args) {
new Controller().generateResult();
}
public Controller() {
for (Class player : classes) {
scores.put(player, 0);
}
}
ArrayList<Game> games = new ArrayList<Game>();
private void generateResult() {
for (int i = 0; i < classes.length - 1; i++) {
for (int j = i + 1; j < classes.length; j++) {
for (int k = 0; k < GAMES_PER_PAIR; k++) {
runGame(classes[i], classes[j], k>=GAMES_PER_PAIR);
}
}
}
GamePanel panel = new GamePanel(games);
printScores();
}
private void runGame(Class class1, Class class2, boolean switchSides) {
if (switchSides) { //switch sides
Class tempClass = class2;
class2 = class1;
class1 = tempClass;
}
try {
Player player1 = (Player) class1.newInstance();
Player player2 = (Player) class2.newInstance();
Game game = new Game(player1, player2);
games.add(game);
int result = game.run();
addResult(class1, result, false);
addResult(class2, result, true);
} catch (Exception e) {
System.out.println("Error in game between " + class1 + " and " + class2);
}
}
private void addResult(Class player, int result, boolean reverse) {
if (reverse) {
if (result == WIN_POINTS) {
result = LOSE_POINTS;
} else if (result == LOSE_POINTS) {
result = WIN_POINTS;
}
}
int newScore = scores.get(player) + result;
scores.put(player, newScore);
}
private void printScores() {
int bestScore = 0;
Class currPlayer = null;
int place = 1;
while (scores.size() > 0) {
bestScore = 0;
currPlayer = null;
for (Class player : scores.keySet()) {
int playerScore = scores.get(player);
if (scores.get(player) >= bestScore) {
bestScore = playerScore;
currPlayer = player;
}
}
System.out.println(String.format("%02d", place++) + ") " + currPlayer + ": " + bestScore);
scores.remove(currPlayer);
}
}
}
you can profit from the methods provided by the controller
: This isn't all that true. Most of the useful methods are package private, so they cannot be used. Would you mind maybe adding asimulateMove
method to theBoard
class, which returns a deep copy of the board with the given move applied? That way, we don't have to write it ourselves (or copy-paste your entire code^^). \$\endgroup\$public
now ;) \$\endgroup\$Throwable
or evenError
since it will avoid losing. I'd call it the BoardTipper. \$\endgroup\$