Merge remote-tracking branch 'github/main'

main
Brett 2022-12-19 22:28:55 -05:00
commit 5aba3bb6c8
9 changed files with 607 additions and 0 deletions

View File

@ -0,0 +1,31 @@
package project.chess;
import java.awt.*;
import java.util.ArrayList;
import static project.ui.Display.loadImage;
public class Bishop extends ChessPiece {
private Image whiteBishop = loadImage("./resources/chess_piece_2_black_bishop.png");
private Image blackBishop = loadImage("./resources/chess_piece_2_white_bishop.png");
public Bishop(Board b, boolean isWhite, int x, int y) {
super(b,isWhite,x,y);
}
public Image getImage(){
if (isWhite)
return whiteBishop;
return blackBishop;
}
@Override
public ArrayList<Move> getMoves() {
return new ArrayList<Move>(super.getDiagonalMoves(b.size()));
}
public Bishop clone () {
return new Bishop(this.b,this.isWhite,this.x,this.y);
}
}

View File

@ -0,0 +1,141 @@
package project.chess;
import java.util.ArrayList;
public class Board {
private final ChessPiece[][] board = new ChessPiece[8][8];
/**
* create a basic chess board in default configuration
*/
public Board(){
for (int i = 0; i < size(); i++) {
board[i][1] = new Pawn(this, true, i, 1);
board[i][size() - 2] = new Pawn(this, false, i, size() - 2);
}
// white
board[0][0] = new Rook(this, true,0, 0);
board[size()-1][0] = new Rook(this, true, size() - 1, 0);
board[1][0] = new Knight(this, true, 1, 0);
board[size()-2][0] = new Knight(this, true, size() - 2, 0);
board[2][0] = new Bishop(this, true, 2, 0);
board[size()-3][0] = new Bishop(this, true, size() - 3, 0);
board[3][0] = new Queen(this, true, 3, 0);
board[size()-4][0] = new King(this, true, size() - 4, 0);
// black
board[0][size()-1] = new Rook(this, false,0, size()-1);
board[size()-1][size()-1] = new Rook(this, false, size() - 1, size()-1);
board[1][size()-1] = new Knight(this, false, 1, size()-1);
board[size()-2][size()-1] = new Knight(this, false, size() - 2, size()-1);
board[2][size()-1] = new Bishop(this, false, 2, size()-1);
board[size()-3][size()-1] = new Bishop(this, false, size() - 3, size()-1);
board[3][size()-1] = new Queen(this, false, 3, size()-1);
board[size()-4][size()-1] = new King(this, false, size() - 4, size()-1);
}
public boolean movePiece(Move movingPiece, Move newPos){
return movePiece(movingPiece.getX(), movingPiece.getY(), newPos.getX(), newPos.getY());
}
public boolean movePiece(int x, int y, int newX, int newY){
// System.out.println(x + " " + y + " || " + newX + " " + newY);
ChessPiece selectedPiece;
// make sure the place we are moving from has a piece
if ((selectedPiece = get(x, y)) == null)
return false;
ArrayList<Move> moves;
moves = selectedPiece.getMoves();
for (Move m : moves){
// reject the moves that don't correspond to where we want to move to.
if (m.getX() != newX || m.getY() != newY)
continue;
ChessPiece movedPiece = get(m);
// make sure they are of the same color. Since we know this move is the position we want to move to
// we can early exit because we are not allowed to move on top of our own pieces
if (movedPiece != null && selectedPiece.isWhite == movedPiece.isWhite)
return false;
// if we were unable to set the piece down we failed to move the piece
if (!set(m, selectedPiece))
return false;
// run special conditions. Only matters for pieces which have special conditions, since is defaulted to empty body.
if (movedPiece != null)
selectedPiece.applySpecialMove(m);
set(x, y, null);
return true;
}
return false;
}
public ArrayList<Board> getMoves(boolean isWhitesTurn) {
ArrayList<Board> moveStates = new ArrayList<>();
Board curr;
for (int i = 0; i < board.length; i++) {
for (int j = 0; j < board[0].length; j++) {
if ((board[i][j] = get(i, j)) == null || (isWhitesTurn && !board[i][j].isWhite()) ||
(!isWhitesTurn && board[i][j].isWhite()) ) continue;
for (Move pieceMove : board[i][j].getMoves()) {
curr = deepCopy();
curr.movePiece(board[i][j].x,board[i][j].y,pieceMove.getX(),pieceMove.getY());
moveStates.add(deepCopy());
}
}
}
return moveStates;
}
public int evaluate () { // !!!!!!!! Fix this, add actual heuristic evaluation
return (int)Math.random()*900;
}
public Board deepCopy () {
Board temp = new Board();
for (int i = 0; i < temp.board.length; i++) {
for (int j = 0; j < temp.board[0].length; j++) {
try {
if (this.board[i][j] == null) {
temp.board[i][j] = null;
continue;
}
temp.board[i][j] = this.board[i][j].clone();
} catch (Exception e) { e.printStackTrace();}
}
}
return temp;
}
public ChessPiece get(Move m){
return get(m.getX(), m.getY());
}
public ChessPiece get(int x, int y){
if (x < 0 || x >= board.length)
return null;
if (y < 0 || y >= board.length)
return null;
return board[x][y];
}
public boolean set(Move m, ChessPiece piece) {
return set(m.getX(), m.getY(), piece);
}
protected boolean set(int x, int y, ChessPiece piece){
if (x < 0 || x >= board.length)
return false;
if (y < 0 || y >= board.length)
return false;
board[x][y] = piece;
return true;
}
public int size(){
return board.length;
}
}

View File

@ -0,0 +1,68 @@
package project.chess;
import java.awt.*;
import java.util.ArrayList;
public abstract class ChessPiece {
protected Board b;
protected int x, y;
protected boolean isInDanger, isWhite;
protected boolean isFirstMove = true;
public ChessPiece(Board b, boolean isWhite, int x, int y) {
this.b = b;
this.x = x;
this.y = y;
this.isWhite = isWhite;
}
public void setInDanger(boolean isInDanger){
this.isInDanger = isInDanger;
}
public boolean isWhite(){
return isWhite;
}
public Move getPosition(){
return new Move(x, y);
}
public boolean isFirstMove(){
return isFirstMove;
}
public void setMoved(){
isFirstMove = false;
}
public abstract ArrayList<Move> getMoves();
public abstract Image getImage();
public void applySpecialMove(Move moveWithSpecial){}
protected ArrayList<Move> getCardinalMoves(int length){
ArrayList<Move> moves = new ArrayList<Move>();
for (int i = 1; i <= length; i++){
// cardinals
moves.add(new Move(x - i, y));
moves.add(new Move(x + i, y));
moves.add(new Move(x, y - i));
moves.add(new Move(x, y + i));
}
return moves;
}
protected ArrayList<Move> getDiagonalMoves(int length){
ArrayList<Move> moves = new ArrayList<Move>();
for (int i = 1; i <= length; i++){
// cardinals
moves.add(new Move(x - i, y - i));
moves.add(new Move(x + i, y + i));
moves.add(new Move(x + i, y - i));
moves.add(new Move(x - i, y + i));
}
return moves;
}
public abstract ChessPiece clone();
}

View File

@ -0,0 +1,79 @@
package project.chess;
import java.awt.*;
import java.util.ArrayList;
import static project.ui.Display.loadImage;
public class King extends ChessPiece {
private final Image whiteKing = loadImage("./resources/chess_piece_2_black_king.png");
private final Image blackKing = loadImage("./resources/chess_piece_2_white_king.png");
public King(Board b, boolean isWhite, int x, int y) {
super(b,isWhite,x,y);
}
public Image getImage(){
if (isWhite)
return whiteKing;
return blackKing;
}
@Override
public ArrayList<Move> getMoves() {
ArrayList<Move> moves = new ArrayList<Move>();
moves.addAll(super.getCardinalMoves(1));
moves.addAll(super.getDiagonalMoves(1));
if (isFirstMove){
ChessPiece rook = null;
// castling
if (isWhite){
if ((rook = b.get(0, 0)) != null && checkIfRookValid(rook))
moves.add(new Move(2, 0, Move.SpecialConditions.leftCastle));
if ((rook = b.get(b.size() - 1, 0)) != null && checkIfRookValid(rook))
moves.add(new Move(b.size() - 2, 0, Move.SpecialConditions.rightCastle));
} else {
if ((rook = b.get(0, b.size()-1)) != null && checkIfRookValid(rook))
moves.add(new Move(2, b.size()-1, Move.SpecialConditions.leftCastle));
if ((rook = b.get(b.size() - 1, b.size()-1)) != null && checkIfRookValid(rook))
moves.add(new Move(b.size() - 2, b.size()-1, Move.SpecialConditions.rightCastle));
}
}
return moves;
}
@Override
public void applySpecialMove(Move moveWithSpecial){
Move.SpecialConditions specialCondition;
specialCondition = moveWithSpecial.getSpecialCondition();
if(specialCondition == Move.SpecialConditions.leftCastle)
castleLeft();
else if (specialCondition == Move.SpecialConditions.rightCastle)
castleRight();
}
private void castleRight(){
// casting has to move the rook on the right size of the king from white's perspective
if (this.isWhite)
b.set(b.size()-3, 0, b.get(b.size()-1, 0));
else
b.set(b.size()-3, b.size()-1, b.get(b.size()-1, b.size()-1));
}
private boolean checkIfRookValid(ChessPiece piece){
return piece.isFirstMove() && piece instanceof Rook;
}
private void castleLeft(){
// casting has to move the rook on the left size of the king from white's perspective
if (this.isWhite)
b.set(3, 0, b.get(0, 0));
else
b.set(3, b.size()-1, b.get(0, b.size()-1));
}
public King clone () {
return new King(this.b,this.isWhite,this.x,this.y);
}
}

View File

@ -0,0 +1,40 @@
package project.chess;
import java.awt.*;
import java.util.ArrayList;
import static project.ui.Display.loadImage;
public class Knight extends ChessPiece {
private Image whiteKnight = loadImage("./resources/chess_piece_2_black_knight.png");
private Image blackKnight = loadImage("./resources/chess_piece_2_white_knight.png");
public Knight(Board b, boolean isWhite, int x, int y) {
super(b,isWhite,x,y);
}
public Image getImage(){
if (isWhite)
return whiteKnight;
return blackKnight;
}
@Override
public ArrayList<Move> getMoves() {
ArrayList<Move> moves = new ArrayList<Move>();
moves.add(new Move(x + 2, y + 1));
moves.add(new Move(x + 2, y - 1));
moves.add(new Move(x - 2, y + 1));
moves.add(new Move(x - 2, y - 1));
moves.add(new Move(x - 1, y - 2));
moves.add(new Move(x + 1, y - 2));
moves.add(new Move(x - 1, y + 2));
moves.add(new Move(x + 1, y + 2));
return moves;
}
public Knight clone () {
return new Knight(this.b,this.isWhite,this.x,this.y);
}
}

View File

@ -0,0 +1,97 @@
package project;
import project.chess.Board;
import project.chess.Move;
import project.ui.Display;
import java.util.ArrayList;
import java.util.concurrent.TimeUnit;
public class Main {
public static void main(String[] args) {
Board mainBoard = new Board();
int maxDepth = 2;
Board[] bestStates = new Board[maxDepth];
minMax(mainBoard,bestStates,maxDepth,true);
System.out.println("Ai Done Computing");
int counter = 0;
// mainBoard.getMoves();
// display stuff //
Display display = new Display(mainBoard);
long frames = 0;
long lastTime = System.currentTimeMillis();
long frameTime = System.currentTimeMillis();
while(display.update(mainBoard)){
display.repaint();
// limit usage of system resources by slowing the speed down to 60 fps.
while ((System.currentTimeMillis() - frameTime) < 64f){
Thread.yield();
}
frameTime = System.currentTimeMillis();
// print out the FPS of the display.
frames++;
if (System.currentTimeMillis() - lastTime > 1000){
System.out.println("FPS: " + frames);
frames = 0;
lastTime = System.currentTimeMillis();
}
try {
TimeUnit.SECONDS.sleep(1);
} catch (Exception ignored) {}
mainBoard = bestStates[counter%maxDepth];
counter++;
}
System.out.println("Hello world!");
}
/*
public int alphaBeta (Board position, int depth, int alpha, int beta, boolean maximizing) {
if (depth == 0 || position.kingInDanger) return Board.evaluate(position);
if (maximizing) {
int maxEval = Integer.MIN_VALUE;
position.
}
} */
public static int minMax (Board position, Board[] bestStates, int depth, boolean maximizing) {
if (depth == 0) {
bestStates[depth] = position;
return position.evaluate();
}
System.out.println(depth);
if (maximizing) {
int maxEval = Integer.MIN_VALUE;
for (Board state: position.getMoves(maximizing) ) {
int eval = minMax(state,bestStates,depth-1, false);
maxEval = Math.max(maxEval,eval);
}
bestStates[depth-1] = position;
return maxEval;
} else {
int minEval = Integer.MAX_VALUE;
for (Board state: position.getMoves(maximizing) ) {
int eval = minMax(state,bestStates,depth-1, true);
minEval = Math.min(minEval,eval);
}
bestStates[depth-1] = position;
return minEval;
}
}
}

View File

@ -0,0 +1,88 @@
package project.chess;
import project.ui.Display;
import java.awt.*;
import java.util.ArrayList;
public class Pawn extends ChessPiece {
private Image white = Display.loadImage("./resources/chess_piece_2_black_pawn.png");
private Image black = Display.loadImage("./resources/chess_piece_2_white_pawn.png");
public Pawn(Board b, boolean isWhite, int x, int y) {
super(b,isWhite,x,y);
}
public Image getImage(){
if (isWhite)
return white;
return black;
}
@Override
public ArrayList<Move> getMoves() {
ArrayList<Move> moves = new ArrayList<Move>();
if (isWhite) {
moves.add(new Move(x, y + 1));
if (isFirstMove)
moves.add(new Move(x, y + 2));
} else {
moves.add(new Move(x, y - 1));
if (isFirstMove)
moves.add(new Move(x, y - 2));
}
ChessPiece neighbour = null;
if (isWhite){
// En passant
if ((neighbour = b.get(x-1, y)) != null && checkNeighbourEnPassant(neighbour))
moves.add(new Move(x-1, y + 1, Move.SpecialConditions.leftEnPassant));
// En passant
if ((neighbour = b.get(x+1, y)) != null && checkNeighbourEnPassant(neighbour))
moves.add(new Move(x+1, + 1, Move.SpecialConditions.rightEnPassant));
} else {
// unfortunately have to flip the direction depending on player type
// En passant
if ((neighbour = b.get(x-1, y)) != null && checkNeighbourEnPassant(neighbour))
moves.add(new Move(x-1, y - 1, Move.SpecialConditions.leftEnPassant));
// En passant
if ((neighbour = b.get(x+1, y)) != null && checkNeighbourEnPassant(neighbour))
moves.add(new Move(x+1, - 1, Move.SpecialConditions.rightEnPassant));
}
return moves;
}
private boolean checkNeighbourEnPassant(ChessPiece neighbour){
return neighbour instanceof Pawn && ((Pawn) neighbour).isFirstMove() && neighbour.isWhite != this.isWhite;
}
@Override
public void applySpecialMove(Move moveWithSpecial){
Move.SpecialConditions specialCondition;
specialCondition = moveWithSpecial.getSpecialCondition();
if(specialCondition == Move.SpecialConditions.leftEnPassant)
enPassantLeft();
else if (specialCondition == Move.SpecialConditions.rightEnPassant)
enPassantRight();
}
private void enPassantLeft(){
if (isWhite)
b.set(x-1, y, null);
else
b.set(x+1, y, null);
}
private void enPassantRight(){
if (isWhite)
b.set(x+1, y, null);
else
b.set(x-1, y, null);
}
public Pawn clone () {
return new Pawn(this.b,this.isWhite,this.x,this.y);
}
}

View File

@ -0,0 +1,34 @@
package project.chess;
import java.awt.*;
import java.util.ArrayList;
import static project.ui.Display.loadImage;
public class Queen extends ChessPiece {
private Image whiteQueen = loadImage("./resources/chess_piece_2_black_queen.png");
private Image blackQueen = loadImage("./resources/chess_piece_2_white_queen.png");
public Queen(Board b, boolean isWhite, int x, int y) {
super(b,isWhite,x,y);
}
public Image getImage(){
if (isWhite)
return whiteQueen;
return blackQueen;
}
@Override
public ArrayList<Move> getMoves() {
ArrayList<Move> moves = new ArrayList<Move>();
moves.addAll(super.getCardinalMoves(b.size()));
moves.addAll(super.getDiagonalMoves(b.size()));
return moves;
}
public Queen clone () {
return new Queen(this.b,this.isWhite,this.x,this.y);
}
}

View File

@ -0,0 +1,29 @@
package project.chess;
import java.awt.*;
import java.util.ArrayList;
import static project.ui.Display.loadImage;
public class Rook extends ChessPiece {
private Image whiteRook = loadImage("./resources/chess_piece_2_black_rook.png");
private Image blackRook = loadImage("./resources/chess_piece_2_white_rook.png");
public Rook(Board b, boolean isWhite, int x, int y) {
super(b,isWhite,x,y);
}
public Image getImage(){
return isWhite ? whiteRook : blackRook;
}
@Override
public ArrayList<Move> getMoves() {
return new ArrayList<Move>(super.getCardinalMoves(b.size()));
}
public Rook clone () {
return new Rook(this.b,this.isWhite,this.x,this.y);
}
}