refaktor till maven
BIN
src/main/java/com/billenius/img/BlackBishop.png
Normal file
After Width: | Height: | Size: 9.7 KiB |
BIN
src/main/java/com/billenius/img/BlackHorse.png
Normal file
After Width: | Height: | Size: 9.8 KiB |
BIN
src/main/java/com/billenius/img/BlackKing.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
src/main/java/com/billenius/img/BlackPawn.png
Normal file
After Width: | Height: | Size: 6.2 KiB |
BIN
src/main/java/com/billenius/img/BlackQueen.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
src/main/java/com/billenius/img/BlackRook.png
Normal file
After Width: | Height: | Size: 4.5 KiB |
BIN
src/main/java/com/billenius/img/WhiteBishop.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
src/main/java/com/billenius/img/WhiteHorse.png
Normal file
After Width: | Height: | Size: 9.6 KiB |
BIN
src/main/java/com/billenius/img/WhiteKing.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
src/main/java/com/billenius/img/WhitePawn.png
Normal file
After Width: | Height: | Size: 5.9 KiB |
BIN
src/main/java/com/billenius/img/WhiteQueen.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
src/main/java/com/billenius/img/WhiteRook.png
Normal file
After Width: | Height: | Size: 4.0 KiB |
21
src/main/java/com/billenius/schack/Bishop.java
Normal file
@ -0,0 +1,21 @@
|
||||
package com.billenius.schack;
|
||||
|
||||
import java.awt.Point;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
public class Bishop extends LongWalkers {
|
||||
|
||||
public Bishop(boolean isWhite, Point startingPosition) throws IOException {
|
||||
super(isWhite, startingPosition);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Point> validMoves(Piece[][] pieces, boolean allowedToRecurse) {
|
||||
return getMoves(
|
||||
new int[][] { { -1, -1 }, { 1, 1 }, { -1, 1 }, { 1, -1 } },
|
||||
pieces,
|
||||
allowedToRecurse);
|
||||
}
|
||||
|
||||
}
|
245
src/main/java/com/billenius/schack/Board.java
Normal file
@ -0,0 +1,245 @@
|
||||
package com.billenius.schack;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Point;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.MouseListener;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JPanel;
|
||||
|
||||
public class Board extends JPanel implements MouseListener {
|
||||
|
||||
public static final int SIZE_OF_TILE = 100;
|
||||
private Piece[][] pieces = new Piece[8][8];
|
||||
private List<Point> validMovesToDraw = new ArrayList<>();
|
||||
private Point previouslyClickedPoint = new Point();
|
||||
private final Color moveableColor = new Color(255, 191, 0);
|
||||
short turnCount = 0;
|
||||
private boolean whitesTurn = true;
|
||||
|
||||
public Board() throws IOException {
|
||||
this.pieces = getPieces();
|
||||
setPreferredSize(new Dimension(800, 800));
|
||||
}
|
||||
|
||||
/**
|
||||
* Nollställ brädet
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
public void restartGame() throws IOException {
|
||||
this.pieces = getPieces();
|
||||
this.whitesTurn = true;
|
||||
getParent().repaint();
|
||||
}
|
||||
|
||||
private Piece[][] getPieces() throws IOException {
|
||||
Piece[][] piecesRet = {
|
||||
{ new Rook(false, new Point(0, 0)), null, null, null, null, null, null,
|
||||
new Rook(true, new Point(0, 7)) },
|
||||
{ new Horse(false, new Point(1, 0)), null, null, null, null, null, null,
|
||||
new Horse(true, new Point(1, 7)) },
|
||||
{ new Bishop(false, new Point(2, 0)), null, null, null, null, null, null,
|
||||
new Bishop(true, new Point(2, 7)) },
|
||||
{ new Queen(false, new Point(3, 0)), null, null, null, null, null, null,
|
||||
new Queen(true, new Point(3, 7)) },
|
||||
{ new King(false, new Point(4, 0)), null, null, null, null, null, null,
|
||||
new King(true, new Point(4, 7)) },
|
||||
{ new Bishop(false, new Point(5, 0)), null, null, null, null, null, null,
|
||||
new Bishop(true, new Point(5, 7)) },
|
||||
{ new Horse(false, new Point(6, 0)), null, null, null, null, null, null,
|
||||
new Horse(true, new Point(6, 7)) },
|
||||
{ new Rook(false, new Point(7, 0)), null, null, null, null, null, null,
|
||||
new Rook(true, new Point(7, 7)) }
|
||||
};
|
||||
|
||||
// Sätt ut bönder
|
||||
for (int i = 0; i < pieces.length; i++) {
|
||||
piecesRet[i][1] = new Pawn(false, new Point(i, 1));
|
||||
piecesRet[i][6] = new Pawn(true, new Point(i, 6));
|
||||
}
|
||||
|
||||
return piecesRet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paintComponent(Graphics g) {
|
||||
Graphics2D g2 = (Graphics2D) g;
|
||||
drawSquares(g2);
|
||||
|
||||
// Måla alla ställen man kan gå till
|
||||
g2.setColor(moveableColor);
|
||||
for (Point validMove : validMovesToDraw) {
|
||||
if (validMove == null) {
|
||||
continue;
|
||||
}
|
||||
g2.fillOval(validMove.x * SIZE_OF_TILE, validMove.y * SIZE_OF_TILE, SIZE_OF_TILE, SIZE_OF_TILE);
|
||||
}
|
||||
|
||||
// Måla alla pjäser
|
||||
for (Piece[] pieceArr : pieces) {
|
||||
for (Piece piece : pieceArr) {
|
||||
if (piece == null) {
|
||||
continue;
|
||||
}
|
||||
piece.draw(g2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void drawSquares(Graphics2D g2) {
|
||||
g2.setBackground(Color.WHITE);
|
||||
g2.setColor(Color.DARK_GRAY);
|
||||
|
||||
for (int i = 0; i < 8; i += 2) {
|
||||
for (int j = 0; j < 8; j += 2) {
|
||||
g2.fillRect(i * SIZE_OF_TILE, j * SIZE_OF_TILE, SIZE_OF_TILE, SIZE_OF_TILE);
|
||||
g2.fillRect((i + 1) * SIZE_OF_TILE, (j + 1) * SIZE_OF_TILE, SIZE_OF_TILE, SIZE_OF_TILE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mousePressed(MouseEvent mouseEvent) {
|
||||
final int mouseCoordinateX = (int) (mouseEvent.getX() / SIZE_OF_TILE);
|
||||
final int mouseCoordinateY = (int) (mouseEvent.getY() / SIZE_OF_TILE);
|
||||
final Point clickedCoordinate = new Point(mouseCoordinateX, mouseCoordinateY);
|
||||
|
||||
// Ifall vi har tryckt på en pjäs och sedan ska gå dit
|
||||
if (validMovesToDraw.contains(clickedCoordinate)) {
|
||||
Piece selectedPiece = pieces[previouslyClickedPoint.x][previouslyClickedPoint.y];
|
||||
if (selectedPiece == null) {
|
||||
validMovesToDraw.clear();
|
||||
return;
|
||||
}
|
||||
selectedPiece.move(pieces, clickedCoordinate);
|
||||
turnCount++;
|
||||
whitesTurn = !whitesTurn;
|
||||
|
||||
SchackState state = getSchackState();
|
||||
switch (state) {
|
||||
case SCHACK:
|
||||
JOptionPane.showMessageDialog(this, "Du står i schack");
|
||||
break;
|
||||
case SCHACKMATT:
|
||||
case PATT:
|
||||
String stateStr = state.toString();
|
||||
String msg = stateStr.charAt(0) + stateStr.substring(1, stateStr.length()).toLowerCase();
|
||||
int choice = JOptionPane.showConfirmDialog(this, msg + "\nVill du starta om?");
|
||||
|
||||
if (choice == JOptionPane.YES_OPTION) {
|
||||
try {
|
||||
restartGame();
|
||||
} catch (IOException ex) {
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
}
|
||||
|
||||
} else {
|
||||
previouslyClickedPoint = new Point(clickedCoordinate);
|
||||
validMovesToDraw = new ArrayList<>(); // Snabbare än .clear
|
||||
}
|
||||
|
||||
// Om vi inte redan har valt en pjäs klickar vi på en pjäs
|
||||
if (!validMovesToDraw.contains(clickedCoordinate)) {
|
||||
Piece selectedPiece = pieces[clickedCoordinate.x][clickedCoordinate.y];
|
||||
|
||||
if (selectedPiece != null && selectedPiece.isWhite() == whitesTurn) {
|
||||
validMovesToDraw.addAll(selectedPiece.validMoves(pieces, true));
|
||||
} else {
|
||||
validMovesToDraw = new ArrayList<>(); // Snabbare än .clear
|
||||
}
|
||||
} else {
|
||||
validMovesToDraw = new ArrayList<>(); // Snabbare än .clear
|
||||
}
|
||||
|
||||
getParent().repaint();
|
||||
}
|
||||
|
||||
/**
|
||||
* Få status över brädet
|
||||
*
|
||||
* @return SCHACK, SCHACKMATT, PATT, NORMAL
|
||||
*/
|
||||
private SchackState getSchackState() {
|
||||
List<Point> allValidMoves = getMoves(whitesTurn);
|
||||
List<Point> opposingAttacks = getAttacks(!whitesTurn);
|
||||
boolean weCanMove = !allValidMoves.isEmpty();
|
||||
|
||||
boolean inSchack = false;
|
||||
for (Point attack : opposingAttacks) {
|
||||
final Piece attacked = pieces[attack.x][attack.y];
|
||||
if (attacked == null) {
|
||||
continue;
|
||||
}
|
||||
if (attacked.supremeRuler) {
|
||||
inSchack = true;
|
||||
validMovesToDraw = new ArrayList<>(); // Snabbare än .clear
|
||||
getParent().repaint();
|
||||
if (weCanMove) {
|
||||
return SchackState.SCHACK;
|
||||
} else {
|
||||
return SchackState.SCHACKMATT;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!inSchack && !weCanMove) {
|
||||
return SchackState.PATT;
|
||||
}
|
||||
return SchackState.NORMAL;
|
||||
}
|
||||
|
||||
private List<Point> getMoves(boolean whiteMovesAreWanted) {
|
||||
List<Point> allValidMoves = new ArrayList<>();
|
||||
for (Piece[] pieceArr : pieces) {
|
||||
for (Piece piece : pieceArr) {
|
||||
if (piece == null || whiteMovesAreWanted != piece.isWhite()) {
|
||||
continue;
|
||||
}
|
||||
allValidMoves.addAll(piece.validMoves(pieces, true));
|
||||
}
|
||||
}
|
||||
return allValidMoves;
|
||||
}
|
||||
|
||||
public List<Point> getAttacks(boolean whiteAttacksAreWanted) {
|
||||
List attacks = new ArrayList();
|
||||
for (Piece[] pieceArr : pieces) {
|
||||
for (Piece piece : pieceArr) {
|
||||
if (piece == null || whiteAttacksAreWanted != piece.isWhite()) {
|
||||
continue;
|
||||
}
|
||||
attacks.addAll(piece.validAttacks(pieces, true));
|
||||
}
|
||||
}
|
||||
return attacks;
|
||||
}
|
||||
|
||||
public boolean isWhitesTurn() {
|
||||
return whitesTurn;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseReleased(MouseEvent e) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseEntered(MouseEvent e) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseExited(MouseEvent e) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent mouseEvent) {
|
||||
}
|
||||
}
|
29
src/main/java/com/billenius/schack/Horse.java
Normal file
@ -0,0 +1,29 @@
|
||||
package com.billenius.schack;
|
||||
|
||||
import java.awt.Point;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class Horse extends Piece {
|
||||
|
||||
public Horse(boolean isWhite, Point startingPosition) throws IOException {
|
||||
super(isWhite, startingPosition);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Point> validMoves(Piece[][] pieces, boolean allowedToRecurse) {
|
||||
List<Point> movable = new ArrayList<>();
|
||||
|
||||
for (int dx : new int[] { -2, -1, 1, 2 }) {
|
||||
for (int direction : new int[] { -1, 1 }) {
|
||||
int stepLength = (3 - Math.abs(dx)),
|
||||
dy = direction * stepLength;
|
||||
Point potentialMove = new Point(this.position.x + dx, this.position.y + dy);
|
||||
addMovesIfCan(potentialMove, movable, pieces, allowedToRecurse);
|
||||
}
|
||||
}
|
||||
return movable;
|
||||
}
|
||||
|
||||
}
|
101
src/main/java/com/billenius/schack/King.java
Normal file
@ -0,0 +1,101 @@
|
||||
package com.billenius.schack;
|
||||
|
||||
import java.awt.Point;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public final class King extends Piece {
|
||||
|
||||
public King(boolean isWhite, Point startingPosition) throws IOException {
|
||||
super(isWhite, startingPosition);
|
||||
supremeRuler = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Få en ArrayList med möjliga rockader
|
||||
*
|
||||
* @param pieces
|
||||
* @return
|
||||
*/
|
||||
private List<Point> getCastlingIfPossible(Piece[][] pieces) {
|
||||
List<Point> possibleCastling = new ArrayList<>();
|
||||
if (this.isMoved()) {
|
||||
return possibleCastling;
|
||||
}
|
||||
|
||||
boolean[] somethingBetweenOrSchackOnTheWay = new boolean[2]; // Vänster, höger
|
||||
int leftModifier = -1, rightModifier = 1;
|
||||
for (int modifier : new int[] { leftModifier, rightModifier }) {
|
||||
for (int loopX = this.position.x + modifier; loopX > 0 && loopX < 7; loopX += modifier) {
|
||||
if (pieces[loopX][this.position.y] != null || isInSchack(pieces, new Point(loopX, this.position.y))) {
|
||||
somethingBetweenOrSchackOnTheWay[(modifier == leftModifier) ? 0 : 1] = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
leftModifier = 0;
|
||||
rightModifier = 1;
|
||||
for (int direction : new int[] { leftModifier, rightModifier }) {
|
||||
if (!somethingBetweenOrSchackOnTheWay[direction]) {
|
||||
Piece possibleRook = pieces[direction == leftModifier ? 0 : 7][this.position.y];
|
||||
if (possibleRook != null && !possibleRook.isMoved()) {
|
||||
possibleCastling.add(new Point(direction == leftModifier ? 2 : 6, this.position.y));
|
||||
}
|
||||
}
|
||||
}
|
||||
return possibleCastling;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gör en rockad
|
||||
*
|
||||
* @param pieces
|
||||
* @param shouldGoToLeftSide avgör ifall rockaden är åt vänster håll
|
||||
*/
|
||||
private void castle(Piece[][] pieces, boolean shouldGoToLeftSide) {
|
||||
Piece rook = pieces[shouldGoToLeftSide ? 0 : 7][this.position.y];
|
||||
Piece king = this;
|
||||
|
||||
// Null där de stod
|
||||
pieces[king.position.x][king.position.y] = null;
|
||||
pieces[rook.position.x][rook.position.y] = null;
|
||||
// Uppdatera internt minne
|
||||
king.position.x = shouldGoToLeftSide ? 2 : 6;
|
||||
rook.position.x = shouldGoToLeftSide ? 3 : 5;
|
||||
// Uppdatera brädet
|
||||
pieces[king.position.x][king.position.y] = king;
|
||||
pieces[rook.position.x][rook.position.y] = rook;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void move(Piece[][] pieces, Point toMove) {
|
||||
if (Math.abs(position.x - toMove.x) == 2) {
|
||||
boolean goToLeftSide = toMove.x < 5;
|
||||
castle(pieces, goToLeftSide);
|
||||
} else {
|
||||
super.move(pieces, toMove);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Point> validMoves(Piece[][] pieces, boolean allowedToRecurse) {
|
||||
List<Point> movable = new ArrayList<>();
|
||||
|
||||
for (int loopX = -1; loopX < 2; loopX++) {
|
||||
for (int loopY = -1; loopY < 2; loopY++) {
|
||||
if (loopY == 0 && loopX == 0) {
|
||||
continue;
|
||||
}
|
||||
addMovesIfCan(new Point(this.position.x + loopX, this.position.y + loopY), movable, pieces,
|
||||
allowedToRecurse);
|
||||
}
|
||||
|
||||
}
|
||||
if (allowedToRecurse && !isInSchack(pieces)) {
|
||||
movable.addAll(getCastlingIfPossible(pieces));
|
||||
}
|
||||
return movable;
|
||||
}
|
||||
|
||||
}
|
49
src/main/java/com/billenius/schack/LongWalkers.java
Normal file
@ -0,0 +1,49 @@
|
||||
package com.billenius.schack;
|
||||
|
||||
import java.awt.Point;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public abstract class LongWalkers extends Piece {
|
||||
|
||||
public LongWalkers(boolean isWhite, Point startingPosition) throws IOException {
|
||||
super(isWhite, startingPosition);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generell metod för att generera möjliga drag för LongWalkers
|
||||
*
|
||||
* @param directions vilka håll. Exempel:
|
||||
*
|
||||
* <pre>
|
||||
* {@code
|
||||
* new int[][] { { 1, 0 }, { -1, 0 }, { 0, 1 }, { 0, -1 } }
|
||||
* }</pre>
|
||||
*
|
||||
* för att gå
|
||||
* som ett torn
|
||||
*
|
||||
* @param pieces
|
||||
* @param allowedToRecurse
|
||||
* @return
|
||||
*/
|
||||
List<Point> getMoves(int[][] directions, Piece[][] pieces, boolean allowedToRecurse) {
|
||||
List<Point> movable = new ArrayList<>();
|
||||
|
||||
for (int[] xy : directions) {
|
||||
int loopX = this.position.x, loopY = this.position.y;
|
||||
while (loopX + xy[0] >= 0 && loopX + xy[0] <= 7 && loopY + xy[1] >= 0 && loopY + xy[1] <= 7) {
|
||||
loopX += xy[0];
|
||||
loopY += xy[1];
|
||||
boolean shouldBreak = addMovesIfCan(new Point(loopX, loopY), movable, pieces, allowedToRecurse);
|
||||
if (shouldBreak) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return movable;
|
||||
}
|
||||
|
||||
}
|
153
src/main/java/com/billenius/schack/Pawn.java
Normal file
@ -0,0 +1,153 @@
|
||||
package com.billenius.schack;
|
||||
|
||||
import java.awt.HeadlessException;
|
||||
import java.awt.Point;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.swing.JOptionPane;
|
||||
|
||||
public class Pawn extends Piece {
|
||||
|
||||
public Pawn(boolean isWhite, Point startingPosition) throws IOException {
|
||||
super(isWhite, startingPosition);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ger tillbaks alla ställen pjäsen kan attackera
|
||||
*
|
||||
* @param pieces
|
||||
* @param shouldNotCareIfAttackSpaceIsEmptyOrNot Ifall man ska kolla ifall
|
||||
* det är något i möjliga
|
||||
* attackrutor ifall
|
||||
* @return Alla lämpliga attackMoves
|
||||
*/
|
||||
@Override
|
||||
public List<Point> validAttacks(Piece[][] pieces, boolean shouldNotCareIfAttackSpaceIsEmptyOrNot) {
|
||||
List<Point> movable = new ArrayList<>();
|
||||
|
||||
// Kolla ifall vi kan ta någon
|
||||
for (int pawnX : new int[] { -1, 1 }) {
|
||||
// Position vi kollar just nu, snett upp åt höger & vänster
|
||||
Point pos = new Point(this.position.x + pawnX, this.position.y + (this.isWhite() ? -1 : 1));
|
||||
if (pos.x < 0 || pos.x > 7 || pos.y < 0 || pos.y > 7) {
|
||||
continue;
|
||||
}
|
||||
Piece piece = pieces[pos.x][pos.y];
|
||||
if (piece == null || piece.isWhite() != this.isWhite()
|
||||
|| (shouldNotCareIfAttackSpaceIsEmptyOrNot && piece.isWhite() != this.isWhite())) {
|
||||
movable.add(pos);
|
||||
}
|
||||
}
|
||||
|
||||
return movable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Point> validMoves(Piece[][] pieces, boolean allowedToRecurse) {
|
||||
List<Point> movable = new ArrayList<>();
|
||||
|
||||
// Om bonden har gått en gång, får gå 1 steg, annars 2
|
||||
final int upTo = this.isMoved() ? 1 : 2;
|
||||
|
||||
// Kolla om man kan gå rakt frak
|
||||
for (int pawnDY = 1; pawnDY <= upTo; pawnDY++) {
|
||||
final Point pos = new Point(this.position.x, this.position.y + (this.isWhite() ? -pawnDY : pawnDY));
|
||||
boolean shouldBreak = addMovesIfCan(pos, movable, pieces, allowedToRecurse);
|
||||
if (shouldBreak) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Kolla ifall vi kan ta någon
|
||||
for (int pawnX : new int[] { -1, 1 }) {
|
||||
// Position vi kollar just nu, snett upp åt höger & vänster
|
||||
final Point pos = new Point(this.position.x + pawnX, this.position.y + (this.isWhite() ? -1 : 1));
|
||||
movable.addAll(addAttackMovesIfCan(pos, pieces));
|
||||
}
|
||||
return movable;
|
||||
}
|
||||
|
||||
// Känns som det här skulle kunnat vara i validMoves, men nu är det såhär
|
||||
/**
|
||||
* Ifall det är en pjäs som står här och den inte är samma färg som oss,
|
||||
* lägg till i listan
|
||||
*
|
||||
* @param pos
|
||||
* @param movable
|
||||
* @param pieces
|
||||
*/
|
||||
private List<Point> addAttackMovesIfCan(Point pos, Piece[][] pieces) {
|
||||
List<Point> movable = new ArrayList();
|
||||
// Se till att vi inte är utanför brädet
|
||||
if (pos.x >= pieces.length || pos.x < 0 || pos.y >= pieces[0].length || pos.y < 0) {
|
||||
return movable;
|
||||
}
|
||||
final Piece potentialEnemy = pieces[pos.x][pos.y];
|
||||
// Ifall det är tomt här, gör ingenting
|
||||
if (potentialEnemy != null && potentialEnemy.isWhite() != this.isWhite()) {
|
||||
if (!isInSchack(pieces, pos)) {
|
||||
movable.add(pos);
|
||||
}
|
||||
}
|
||||
return movable;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean addMovesIfCan(Point pos, List movable, Piece[][] pieces, boolean allowedToRecurse) {
|
||||
if (pos.x < 0 || pos.x > 7 || pos.y < 0 || pos.y > 7) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Piece pieceToCheck = pieces[pos.x][pos.y];
|
||||
if (pieceToCheck == null) {
|
||||
if (!isInSchack(pieces, pos)) {
|
||||
movable.add(pos);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void move(Piece[][] pieces, Point toMove) {
|
||||
super.move(pieces, toMove);
|
||||
|
||||
// Check if the pawn has moved to the end and should be transformed
|
||||
if (this.position.y == 0 && this.isWhite()
|
||||
|| this.position.y == 7 && !this.isWhite()) {
|
||||
transform(pieces);
|
||||
}
|
||||
}
|
||||
|
||||
private void transform(Piece[][] pieces) throws HeadlessException {
|
||||
String[] transformations = { "Queen", "Rook", "Bishop", "Horse" };
|
||||
int choosenTransformations = JOptionPane.showOptionDialog(null,
|
||||
"What do you want to the pawn to transform into?",
|
||||
"Pawn about to transform",
|
||||
JOptionPane.DEFAULT_OPTION,
|
||||
JOptionPane.INFORMATION_MESSAGE,
|
||||
null,
|
||||
transformations,
|
||||
transformations[0]);
|
||||
try {
|
||||
switch (choosenTransformations) {
|
||||
case 0:
|
||||
pieces[position.x][position.y] = new Queen(this.isWhite(), this.position);
|
||||
break;
|
||||
case 1:
|
||||
pieces[position.x][position.y] = new Rook(this.isWhite(), this.position);
|
||||
break;
|
||||
case 2:
|
||||
pieces[position.x][position.y] = new Bishop(this.isWhite(), this.position);
|
||||
break;
|
||||
default:
|
||||
pieces[position.x][position.y] = new Horse(this.isWhite(), this.position);
|
||||
break;
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
System.out.println(ioe);
|
||||
}
|
||||
}
|
||||
}
|
235
src/main/java/com/billenius/schack/Piece.java
Normal file
@ -0,0 +1,235 @@
|
||||
package com.billenius.schack;
|
||||
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Point;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
public abstract class Piece {
|
||||
|
||||
/**
|
||||
* Variabel som alltid bör vara samma värde som pjäsen är i brädes av
|
||||
* Piece[][]
|
||||
*/
|
||||
public Point position;
|
||||
/**
|
||||
* Sant ifall pjäsens färg är vit, falskt ifall den är svart
|
||||
*/
|
||||
private final boolean isWhite;
|
||||
/**
|
||||
* SPECIAL RULÖES APPLY TO THE KING, (ITS GOOD TO BE THE KING:)
|
||||
*/
|
||||
public boolean supremeRuler = false;
|
||||
/**
|
||||
* Bild av pjäsen som ritas ut på bärdet
|
||||
*/
|
||||
protected BufferedImage icon;
|
||||
|
||||
/**
|
||||
* Nödvändigt för rockad
|
||||
*/
|
||||
protected boolean moved = false;
|
||||
|
||||
public Piece(boolean white, Point startingPosition) throws IOException {
|
||||
this.isWhite = white;
|
||||
this.position = startingPosition;
|
||||
setPieceIcon();
|
||||
}
|
||||
|
||||
public Piece(boolean white) {
|
||||
this.isWhite = white;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ladda in pjäsbild från paketet img
|
||||
*
|
||||
* @param className
|
||||
* @throws IOException ifall det inte finns någon bild på pjäsen
|
||||
*/
|
||||
private void setPieceIcon() throws IOException {
|
||||
String className = this.getClass().getSimpleName();
|
||||
String colorName = this.isWhite() ? "White" : "Black";
|
||||
String fileName = colorName + className + ".png";
|
||||
InputStream is = getClass().getResourceAsStream("/com/billenius/img/" + fileName);
|
||||
icon = ImageIO.read(is);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ger tillbaks alla ställen pjäsen kan gå till
|
||||
*
|
||||
* @param pieces
|
||||
* @param allowedToRecurse
|
||||
* @return
|
||||
*/
|
||||
public abstract List<Point> validMoves(Piece[][] pieces, boolean allowedToRecurse);
|
||||
|
||||
/**
|
||||
* Ger tillbaks alla ställen pjäsen kan attackera
|
||||
*
|
||||
* @param pieces
|
||||
* @param shouldNotCareIfAttackSpaceIsEmptyOrNot För bönder ifall den ska
|
||||
* kolla ifall det är något i
|
||||
* möjliga attackrutor ifall
|
||||
* @return Alla lämpliga attackMoves
|
||||
*/
|
||||
public List<Point> validAttacks(Piece[][] pieces, boolean shouldNotCareIfAttackSpaceIsEmptyOrNot) {
|
||||
return validMoves(pieces, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ritar ut pjäsen baserat på den ihågkommna positionen
|
||||
*
|
||||
* @param g2
|
||||
*/
|
||||
public void draw(Graphics2D g2) {
|
||||
g2.drawImage(
|
||||
icon,
|
||||
position.x * Board.SIZE_OF_TILE,
|
||||
position.y * Board.SIZE_OF_TILE,
|
||||
null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Flyttar pjäsen till toMove och tar bort det som tidigare var där
|
||||
*
|
||||
* @param pieces
|
||||
* @param toMove
|
||||
*/
|
||||
public void move(Piece[][] pieces, Point toMove) {
|
||||
// Gör ingenting ifall vi är utanför brädet
|
||||
if (toMove.x >= pieces.length || toMove.y < 0 || position.x >= pieces[0].length || position.y < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
pieces[toMove.x][toMove.y] = this;
|
||||
pieces[position.x][position.y] = null;
|
||||
this.position = new Point(toMove);
|
||||
this.moved = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lägg till move ifall det går, alltså inte är schack där
|
||||
*
|
||||
* @param pos Drag att lägga till ifall det går
|
||||
* @param movable Lägger till drag i denna ArrayList
|
||||
* @param pieces Piece[][] över brädet
|
||||
* @param allowedToRecurse Behövs för att inte gå in i en evig loop där
|
||||
*
|
||||
* <pre>{@code addMovesIfCan -> isInSchack -> validMoves -> getCastlingIfPossible(King) -> isInSchack}</pre>
|
||||
*
|
||||
* @return true ifall man inte kan gå längre i denna riktning
|
||||
*/
|
||||
protected boolean addMovesIfCan(Point pos, List<Point> movable, Piece[][] pieces, boolean allowedToRecurse) {
|
||||
// Ifall vi är utanför brädet ge tillbaka false
|
||||
if (pos.x > 7 || pos.x < 0 || pos.y > 7 || pos.y < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Piece pieceToCheck = pieces[pos.x][pos.y];
|
||||
|
||||
// Detta är en tom plats
|
||||
if (pieceToCheck == null) {
|
||||
if (!allowedToRecurse || !isInSchack(pieces, pos)) {
|
||||
movable.add(pos);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ifall det är en pjäs i motståndarlaget här kan vi ta den men inte gå
|
||||
* längre Ifall det är samma färg som oss betyder det att vi inte kan
|
||||
* lägga till den
|
||||
*/
|
||||
if ((pieceToCheck.isWhite() != this.isWhite())
|
||||
&& ((allowedToRecurse && !isInSchack(pieces, pos)) || !allowedToRecurse)) {
|
||||
movable.add(pos);
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Kolla ifall det är schack vid den här positionen
|
||||
*
|
||||
* @param pieces Piece[][] över hela brädet
|
||||
* @param pos Kollar ifall det är schack om denna Piece flyttar hit
|
||||
* @return true ifall det är schack
|
||||
*/
|
||||
protected boolean isInSchack(Piece[][] pieces, Point pos) {
|
||||
// Kom ihåg vart vi var
|
||||
Point previousPosition = new Point(this.position);
|
||||
|
||||
// Kom ihåg motståndarpjäs
|
||||
Piece guyThatsAlreadyHere = pieces[pos.x][pos.y];
|
||||
|
||||
// Testa att flytta
|
||||
pieces[pos.x][pos.y] = this;
|
||||
pieces[previousPosition.x][previousPosition.y] = null;
|
||||
this.position = pos;
|
||||
|
||||
boolean inSchack = isInSchack(pieces);
|
||||
|
||||
// Flytta tillbaka
|
||||
pieces[previousPosition.x][previousPosition.y] = this;
|
||||
pieces[pos.x][pos.y] = guyThatsAlreadyHere;
|
||||
this.position = previousPosition;
|
||||
|
||||
return inSchack;
|
||||
}
|
||||
|
||||
/**
|
||||
* Kolla ifall det är schack
|
||||
*
|
||||
* @param pieces Piece[][] över hela brädet
|
||||
* @return true ifall det är schack
|
||||
*/
|
||||
protected boolean isInSchack(Piece[][] pieces) {
|
||||
List<Point> enemyAttacks = new ArrayList<>();
|
||||
|
||||
// Fråga alla pjäser vart de kan gå/ta
|
||||
for (Piece[] pieceArr : pieces) {
|
||||
for (Piece piece : pieceArr) {
|
||||
if (piece != null && piece.isWhite != this.isWhite()) {
|
||||
// Lägg till alla attacker för mostståndaren
|
||||
enemyAttacks.addAll(piece.validAttacks(pieces, false));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Kollar ifall kungen står i schack just nu
|
||||
for (Point enemyAttack : enemyAttacks) {
|
||||
Piece attackedPiece = pieces[enemyAttack.x][enemyAttack.y];
|
||||
if (attackedPiece != null && attackedPiece.supremeRuler) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.getClass().getSimpleName() + "{" + "position=" + position + ", isWhite=" + isWhite + '}';
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return true ifall pjäsen är vit
|
||||
*/
|
||||
public boolean isWhite() {
|
||||
return isWhite;
|
||||
}
|
||||
|
||||
/**
|
||||
* Kompabilitet med PieceKnownIfMoved
|
||||
*
|
||||
* @return false
|
||||
*/
|
||||
public boolean isMoved() {
|
||||
return moved;
|
||||
}
|
||||
|
||||
}
|
20
src/main/java/com/billenius/schack/Queen.java
Normal file
@ -0,0 +1,20 @@
|
||||
package com.billenius.schack;
|
||||
|
||||
import java.awt.Point;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
public class Queen extends LongWalkers {
|
||||
|
||||
public Queen(boolean isWhite, Point point) throws IOException {
|
||||
super(isWhite, point);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Point> validMoves(Piece[][] pieces, boolean allowedToRecurse) {
|
||||
return getMoves(
|
||||
new int[][] { { 1, 0 }, { -1, 0 }, { 0, 1 }, { -1, -1 }, { 0, -1 }, { 1, 1 }, { -1, 1 }, { 1, -1 } },
|
||||
pieces,
|
||||
allowedToRecurse);
|
||||
}
|
||||
}
|
21
src/main/java/com/billenius/schack/Rook.java
Normal file
@ -0,0 +1,21 @@
|
||||
package com.billenius.schack;
|
||||
|
||||
import java.awt.Point;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
public class Rook extends LongWalkers {
|
||||
|
||||
public Rook(boolean isWhite, Point startingPosition) throws IOException {
|
||||
super(isWhite, startingPosition);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Point> validMoves(Piece[][] pieces, boolean allowedToRecurse) {
|
||||
return getMoves(
|
||||
new int[][] { { 1, 0 }, { -1, 0 }, { 0, 1 }, { 0, -1 } },
|
||||
pieces,
|
||||
allowedToRecurse);
|
||||
}
|
||||
|
||||
}
|
104
src/main/java/com/billenius/schack/Schack.java
Normal file
@ -0,0 +1,104 @@
|
||||
package com.billenius.schack;
|
||||
|
||||
import java.awt.HeadlessException;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.io.IOException;
|
||||
import java.net.Inet4Address;
|
||||
import java.net.NetworkInterface;
|
||||
import java.net.UnknownHostException;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JMenu;
|
||||
import javax.swing.JMenuBar;
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.UIManager;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Love Billenius & Simon Hansson
|
||||
*/
|
||||
public class Schack {
|
||||
|
||||
final JFrame frame;
|
||||
|
||||
public Schack() throws IOException {
|
||||
// Set theme
|
||||
try {
|
||||
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
|
||||
} catch (Exception cantGetSystemTheme) {
|
||||
}
|
||||
|
||||
frame = new JFrame();
|
||||
frame.setTitle("Schack");
|
||||
frame.setAlwaysOnTop(false);
|
||||
frame.setResizable(false);
|
||||
|
||||
// Might throw an IOException if the icon of the Pieces isn't embedded correctly
|
||||
final Board board = new Board();
|
||||
frame.setContentPane(board);
|
||||
frame.getContentPane().addMouseListener(board);
|
||||
|
||||
// Create menu
|
||||
final JMenuBar menuBar = new JMenuBar();
|
||||
final JMenu gameMenu = new JMenu("Game");
|
||||
final JMenu connectMenu = new JMenu("Connect");
|
||||
final JMenuItem askForRemi = new JMenuItem("Ask for remi");
|
||||
final JMenuItem surrender = new JMenuItem("Surrender");
|
||||
final JMenuItem showIP = new JMenuItem("Show IP");
|
||||
final JMenuItem connectToOpponent = new JMenuItem("Connect to opponent");
|
||||
|
||||
askForRemi.addActionListener((ActionEvent ae) -> {
|
||||
String whosWantingRemi = board.isWhitesTurn() ? "Vit" : "Svart";
|
||||
int choice = JOptionPane.showConfirmDialog(board, whosWantingRemi + " erbjuder remi\nAccepterar du?");
|
||||
if (choice == JOptionPane.YES_OPTION) {
|
||||
choice = JOptionPane.showConfirmDialog(board, "Lika\nStarta om?");
|
||||
if (choice == JOptionPane.YES_OPTION) {
|
||||
try {
|
||||
board.restartGame();
|
||||
} catch (IOException ex) {
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
surrender.addActionListener((ActionEvent ae) -> {
|
||||
String whosGivingUp = board.isWhitesTurn() ? "Vit" : "Svart";
|
||||
int choice = JOptionPane.showConfirmDialog(board, whosGivingUp + " har gett upp\nStarta om?");
|
||||
if (choice == JOptionPane.YES_OPTION) {
|
||||
try {
|
||||
board.restartGame();
|
||||
} catch (IOException ex) {
|
||||
}
|
||||
}
|
||||
});
|
||||
showIP.addActionListener((ActionEvent ae) -> {
|
||||
try {
|
||||
|
||||
String ip = Inet4Address.getLocalHost().toString();
|
||||
JOptionPane.showMessageDialog(null, "IP: " + ip);
|
||||
|
||||
} catch (HeadlessException | UnknownHostException e) {
|
||||
}
|
||||
});
|
||||
connectToOpponent.addActionListener((ActionEvent ae) -> {
|
||||
String opponentIP = JOptionPane.showInputDialog(null, "What's your opponents IP?");
|
||||
System.out.println("opponents ip: " + opponentIP);
|
||||
|
||||
});
|
||||
|
||||
// Add the menu stuff
|
||||
frame.setJMenuBar(menuBar);
|
||||
menuBar.add(gameMenu);
|
||||
menuBar.add(connectMenu);
|
||||
gameMenu.add(askForRemi);
|
||||
gameMenu.add(surrender);
|
||||
connectMenu.add(showIP);
|
||||
connectMenu.add(connectToOpponent);
|
||||
frame.pack();
|
||||
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||
frame.setVisible(true);
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
new Schack();
|
||||
}
|
||||
}
|
9
src/main/java/com/billenius/schack/SchackState.java
Normal file
@ -0,0 +1,9 @@
|
||||
package com.billenius.schack;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author love
|
||||
*/
|
||||
public enum SchackState {
|
||||
SCHACK, SCHACKMATT, PATT, NORMAL, REMI
|
||||
}
|