Ändra från egotripp till egodipp
BIN
src/main/java/com/limone/img/BlackBishop.png
Normal file
After Width: | Height: | Size: 9.7 KiB |
BIN
src/main/java/com/limone/img/BlackHorse.png
Normal file
After Width: | Height: | Size: 9.8 KiB |
BIN
src/main/java/com/limone/img/BlackKing.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
src/main/java/com/limone/img/BlackPawn.png
Normal file
After Width: | Height: | Size: 6.2 KiB |
BIN
src/main/java/com/limone/img/BlackQueen.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
src/main/java/com/limone/img/BlackRook.png
Normal file
After Width: | Height: | Size: 4.5 KiB |
BIN
src/main/java/com/limone/img/WhiteBishop.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
src/main/java/com/limone/img/WhiteHorse.png
Normal file
After Width: | Height: | Size: 9.6 KiB |
BIN
src/main/java/com/limone/img/WhiteKing.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
src/main/java/com/limone/img/WhitePawn.png
Normal file
After Width: | Height: | Size: 5.9 KiB |
BIN
src/main/java/com/limone/img/WhiteQueen.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
src/main/java/com/limone/img/WhiteRook.png
Normal file
After Width: | Height: | Size: 4.0 KiB |
BIN
src/main/java/com/limone/img/splitscreen.png
Normal file
After Width: | Height: | Size: 132 KiB |
24
src/main/java/com/limone/schack/BasicMove.java
Normal file
@@ -0,0 +1,24 @@
|
||||
package com.limone.schack;
|
||||
|
||||
import java.awt.Point;
|
||||
import java.io.Serializable;
|
||||
|
||||
public class BasicMove implements Serializable {
|
||||
public Point from;
|
||||
public Point to;
|
||||
|
||||
public BasicMove(Point from, Point to) {
|
||||
this.from = from;
|
||||
this.to = to;
|
||||
}
|
||||
|
||||
public BasicMove(Move m) {
|
||||
this.from = m.from;
|
||||
this.to = m.to;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return (from.x + 1) + ":" + (from.y + 1)
|
||||
+ " " + '\u27F6' + " " + (to.x + 1) + ":" + (to.y + 1);
|
||||
}
|
||||
}
|
20
src/main/java/com/limone/schack/Move.java
Normal file
@@ -0,0 +1,20 @@
|
||||
package com.limone.schack;
|
||||
|
||||
import java.awt.Point;
|
||||
|
||||
import com.limone.schack.pieces.Piece;
|
||||
|
||||
public class Move extends BasicMove {
|
||||
public Piece movedPiece;
|
||||
|
||||
public Move(Piece piece, Point from, Point to) {
|
||||
super(from, to);
|
||||
this.movedPiece = piece;
|
||||
}
|
||||
|
||||
public Move(Piece piece, BasicMove basicMove) {
|
||||
super(basicMove.from, basicMove.to);
|
||||
this.movedPiece = piece;
|
||||
}
|
||||
|
||||
}
|
25
src/main/java/com/limone/schack/PieceRenderer.java
Normal file
@@ -0,0 +1,25 @@
|
||||
package com.limone.schack;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.image.BufferedImage;
|
||||
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JList;
|
||||
import javax.swing.ListCellRenderer;
|
||||
|
||||
public class PieceRenderer extends JLabel implements ListCellRenderer<Move> {
|
||||
|
||||
@Override
|
||||
public Component getListCellRendererComponent(JList<? extends Move> list, Move move, int index,
|
||||
boolean isSelected,
|
||||
boolean cellHasFocus) {
|
||||
BufferedImage image = move.movedPiece.getIcon();
|
||||
ImageIcon ii = new ImageIcon(image.getScaledInstance(40, 40, java.awt.Image.SCALE_SMOOTH));
|
||||
|
||||
setIcon(ii);
|
||||
setText(move.toString());
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
167
src/main/java/com/limone/schack/Schack.java
Normal file
@@ -0,0 +1,167 @@
|
||||
package com.limone.schack;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Font;
|
||||
import java.awt.HeadlessException;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.IOException;
|
||||
import java.net.Inet4Address;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.swing.DefaultListModel;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JList;
|
||||
import javax.swing.JMenu;
|
||||
import javax.swing.JMenuBar;
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JSplitPane;
|
||||
import javax.swing.UIManager;
|
||||
|
||||
import com.formdev.flatlaf.FlatLightLaf;
|
||||
import com.limone.schack.boards.Board;
|
||||
import com.limone.schack.boards.NetworkBoard;
|
||||
import com.limone.schack.boards.SameBoard;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Love Billenius & Simon Hansson
|
||||
*/
|
||||
public class Schack {
|
||||
|
||||
final JFrame frame;
|
||||
// Förlåt mig fader för jag kommer synda
|
||||
public final static Map<String, BufferedImage> pieceIcons = new HashMap<>();
|
||||
|
||||
|
||||
|
||||
public Schack() throws IOException {
|
||||
// Set theme
|
||||
try {
|
||||
if (UIManager.getSystemLookAndFeelClassName()
|
||||
.equals("javax.swing.plaf.metal.MetalLookAndFeel"))
|
||||
UIManager.setLookAndFeel(new FlatLightLaf());
|
||||
else
|
||||
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
|
||||
} catch (Exception cantGetSystemTheme) {
|
||||
}
|
||||
|
||||
String[] options = { "On the same screen", "Over the internet" };
|
||||
int choosenTransformations = JOptionPane.showOptionDialog(null,
|
||||
"How do you want to connect with your opponent",
|
||||
"Schack: Selection",
|
||||
JOptionPane.DEFAULT_OPTION,
|
||||
JOptionPane.INFORMATION_MESSAGE,
|
||||
null,
|
||||
options,
|
||||
options[0]);
|
||||
|
||||
DefaultListModel<Move> listModel = new DefaultListModel<>();
|
||||
final Board board;
|
||||
if (choosenTransformations == 0)
|
||||
board = new SameBoard(listModel);
|
||||
else
|
||||
board = new NetworkBoard(listModel);
|
||||
|
||||
frame = new JFrame();
|
||||
frame.setTitle("Schack");
|
||||
frame.setAlwaysOnTop(false);
|
||||
frame.setResizable(true);
|
||||
|
||||
// Might throw an IOException if the icon of the Pieces isn't embedded correctly
|
||||
// final Board board = new BlistModeloard(listModel);
|
||||
|
||||
// Logger
|
||||
final JList<Move> jlist = new JList<>(listModel);
|
||||
jlist.setVisible(true);
|
||||
jlist.setCellRenderer(new PieceRenderer());
|
||||
JScrollPane scrollPane = new JScrollPane(jlist);
|
||||
// scrollPane.setPreferredSize(new Dimension(120, 700));
|
||||
JPanel logPanel = new JPanel(new BorderLayout());
|
||||
logPanel.setPreferredSize(new Dimension(120, 800));
|
||||
|
||||
JLabel infoText = new JLabel("Moves");
|
||||
infoText.setFont(new Font("Cantarell", Font.PLAIN, 18));
|
||||
|
||||
infoText.setHorizontalAlignment(JLabel.CENTER);
|
||||
logPanel.add(infoText, BorderLayout.NORTH);
|
||||
logPanel.add(scrollPane, BorderLayout.CENTER);
|
||||
|
||||
JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
|
||||
splitPane.setDividerLocation(800);
|
||||
splitPane.setLeftComponent(board);
|
||||
splitPane.setRightComponent(logPanel);
|
||||
|
||||
frame.setContentPane(splitPane);
|
||||
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/limone/schack/SchackState.java
Normal file
@@ -0,0 +1,9 @@
|
||||
package com.limone.schack;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author love
|
||||
*/
|
||||
public enum SchackState {
|
||||
SCHACK, SCHACKMATT, PATT, NORMAL, REMI
|
||||
}
|
228
src/main/java/com/limone/schack/boards/Board.java
Normal file
@@ -0,0 +1,228 @@
|
||||
package com.limone.schack.boards;
|
||||
|
||||
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.DefaultListModel;
|
||||
import javax.swing.JPanel;
|
||||
|
||||
import com.limone.schack.Move;
|
||||
import com.limone.schack.SchackState;
|
||||
import com.limone.schack.pieces.Bishop;
|
||||
import com.limone.schack.pieces.Horse;
|
||||
import com.limone.schack.pieces.King;
|
||||
import com.limone.schack.pieces.Pawn;
|
||||
import com.limone.schack.pieces.Piece;
|
||||
import com.limone.schack.pieces.Queen;
|
||||
import com.limone.schack.pieces.Rook;
|
||||
|
||||
public abstract class Board extends JPanel implements MouseListener {
|
||||
|
||||
public static final int SIZE_OF_TILE = 100;
|
||||
protected Piece[][] pieces = new Piece[8][8];
|
||||
protected List<Point> validMovesToDraw = new ArrayList<>();
|
||||
private Point previouslyClickedPoint = new Point();
|
||||
private final Color moveableColor = new Color(255, 191, 0);
|
||||
short turnCount = 0;
|
||||
protected boolean whitesTurn = true;
|
||||
protected DefaultListModel<Move> moveList;
|
||||
|
||||
public Board(DefaultListModel<Move> listModel) throws IOException {
|
||||
this.pieces = getPieces();
|
||||
setPreferredSize(new Dimension(800, 800));
|
||||
this.moveList = listModel;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void makeMove(Move move);
|
||||
|
||||
@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;
|
||||
}
|
||||
|
||||
Move move = new Move(selectedPiece, selectedPiece.position, clickedCoordinate);
|
||||
makeMove(move);
|
||||
} 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];
|
||||
toDoIfNoPreviousPieceSelected(selectedPiece);
|
||||
} else
|
||||
validMovesToDraw = new ArrayList<>(); // Snabbare än .clear
|
||||
|
||||
getParent().repaint();
|
||||
}
|
||||
|
||||
protected abstract void toDoIfNoPreviousPieceSelected(Piece selectedPiece);
|
||||
|
||||
/**
|
||||
* Få status över brädet
|
||||
*
|
||||
* @return SCHACK, SCHACKMATT, PATT, NORMAL
|
||||
*/
|
||||
protected 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<Point> 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) {
|
||||
}
|
||||
}
|
168
src/main/java/com/limone/schack/boards/NetworkBoard.java
Normal file
@@ -0,0 +1,168 @@
|
||||
package com.limone.schack.boards;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Font;
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.net.Inet4Address;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.net.SocketException;
|
||||
|
||||
import javax.swing.DefaultListModel;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JPanel;
|
||||
|
||||
import com.limone.schack.BasicMove;
|
||||
import com.limone.schack.Move;
|
||||
import com.limone.schack.SchackState;
|
||||
import com.limone.schack.pieces.Piece;
|
||||
|
||||
public final class NetworkBoard extends Board implements Runnable {
|
||||
public final static int PORT = 1339;
|
||||
private final Socket socket;
|
||||
private ServerSocket serverSocket = null;
|
||||
private final ObjectInputStream inputStream;
|
||||
private final ObjectOutputStream outputStream;
|
||||
private final Thread inputListener;
|
||||
private Boolean myColor = null;
|
||||
|
||||
public NetworkBoard(DefaultListModel<Move> listModel) throws IOException {
|
||||
super(listModel);
|
||||
String[] options = { "Opponent connects to me", "I'am connecting to the opponent" };
|
||||
int choosenOption = JOptionPane.showOptionDialog(null,
|
||||
"Are you going to connect to the opponent or the reverse?",
|
||||
"Schack: Networking",
|
||||
JOptionPane.DEFAULT_OPTION,
|
||||
JOptionPane.INFORMATION_MESSAGE,
|
||||
null,
|
||||
options,
|
||||
options[0]);
|
||||
|
||||
// Nu ska vi bli en Server
|
||||
if (choosenOption == 0) {
|
||||
String ip = Inet4Address.getLocalHost().getHostAddress();
|
||||
|
||||
final JFrame frame = new JFrame("Schack: Networking");
|
||||
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||
JPanel panel = new JPanel(new BorderLayout());
|
||||
panel.setPreferredSize(new Dimension(600, 200));
|
||||
|
||||
JLabel loading = new JLabel(
|
||||
"<html>Waiting for opponent to connect...<br/>Listening on <i>" + ip + ":" + PORT + "</i></html>");
|
||||
loading.setFont(new Font("Cantarell", Font.PLAIN, 24));
|
||||
loading.setHorizontalAlignment(JLabel.CENTER);
|
||||
|
||||
panel.add(loading, BorderLayout.CENTER);
|
||||
frame.add(panel);
|
||||
frame.pack();
|
||||
frame.setVisible(true);
|
||||
serverSocket = new ServerSocket(PORT);
|
||||
this.socket = serverSocket.accept();
|
||||
// myColor = new Random().nextBoolean();
|
||||
myColor = true; // VIT
|
||||
frame.setVisible(false);
|
||||
|
||||
// Get input/output stream
|
||||
System.out.println("Getting inputstream");
|
||||
inputStream = new ObjectInputStream(socket.getInputStream());
|
||||
System.out.println("Getting outputstream");
|
||||
outputStream = new ObjectOutputStream(socket.getOutputStream());
|
||||
}
|
||||
// Nu ska vi bli en klient
|
||||
else {
|
||||
String ip = JOptionPane.showInputDialog(null,
|
||||
"What's the IP of your opponent?",
|
||||
"Schack: Networking",
|
||||
JOptionPane.QUESTION_MESSAGE);
|
||||
if (ip.equals(""))
|
||||
ip = "localhost";
|
||||
this.socket = new Socket(ip, 1339);
|
||||
myColor = false; // SVART
|
||||
|
||||
// Get input/output stream
|
||||
System.out.println("Getting outputstream");
|
||||
outputStream = new ObjectOutputStream(socket.getOutputStream());
|
||||
System.out.println("Getting inputstream");
|
||||
inputStream = new ObjectInputStream(socket.getInputStream());
|
||||
}
|
||||
inputListener = new Thread(this);
|
||||
inputListener.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void makeMove(Move move) {
|
||||
try {
|
||||
turnCount++;
|
||||
moveList.addElement(move);
|
||||
move.movedPiece.move(pieces, move.to);
|
||||
System.out.println("repainting");
|
||||
getParent().repaint();
|
||||
System.out.println("Sending move to opponent");
|
||||
outputStream.writeObject(new BasicMove(move));
|
||||
System.out.println("Move sent");
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void toDoIfNoPreviousPieceSelected(Piece selectedPiece) {
|
||||
if (selectedPiece != null && selectedPiece.isWhite() == myColor)
|
||||
validMovesToDraw.addAll(selectedPiece.validMoves(pieces, true));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
while (true) {
|
||||
BasicMove basicMove = (BasicMove) inputStream.readObject();
|
||||
Move move = new Move(pieces[basicMove.from.x][basicMove.from.y], basicMove);
|
||||
System.out.println("Got move");
|
||||
moveList.addElement(move);
|
||||
turnCount++;
|
||||
|
||||
System.out.println("Moving piece");
|
||||
move.movedPiece.move(pieces, move.to);
|
||||
System.out.println("Repainting");
|
||||
getParent().repaint();
|
||||
|
||||
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:
|
||||
}
|
||||
|
||||
}
|
||||
} catch (EOFException | SocketException e) {
|
||||
JOptionPane.showMessageDialog(this, "Lost connection to opponent");
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
JOptionPane.showMessageDialog(this, e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
57
src/main/java/com/limone/schack/boards/SameBoard.java
Normal file
@@ -0,0 +1,57 @@
|
||||
package com.limone.schack.boards;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import javax.swing.DefaultListModel;
|
||||
import javax.swing.JOptionPane;
|
||||
|
||||
import com.limone.schack.Move;
|
||||
import com.limone.schack.SchackState;
|
||||
import com.limone.schack.pieces.Piece;
|
||||
|
||||
public final class SameBoard extends Board {
|
||||
|
||||
public SameBoard(DefaultListModel<Move> listModel) throws IOException {
|
||||
super(listModel);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void makeMove(Move move) {
|
||||
moveList.addElement(move);
|
||||
move.movedPiece.move(pieces, move.to);
|
||||
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:
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void toDoIfNoPreviousPieceSelected(Piece selectedPiece) {
|
||||
if (selectedPiece != null && selectedPiece.isWhite() == whitesTurn)
|
||||
validMovesToDraw.addAll(selectedPiece.validMoves(pieces, true));
|
||||
else
|
||||
validMovesToDraw = new ArrayList<>(); // Snabbare än .clear
|
||||
|
||||
}
|
||||
|
||||
}
|
21
src/main/java/com/limone/schack/pieces/Bishop.java
Normal file
@@ -0,0 +1,21 @@
|
||||
package com.limone.schack.pieces;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
29
src/main/java/com/limone/schack/pieces/Horse.java
Normal file
@@ -0,0 +1,29 @@
|
||||
package com.limone.schack.pieces;
|
||||
|
||||
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/limone/schack/pieces/King.java
Normal file
@@ -0,0 +1,101 @@
|
||||
package com.limone.schack.pieces;
|
||||
|
||||
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/limone/schack/pieces/LongWalkers.java
Normal file
@@ -0,0 +1,49 @@
|
||||
package com.limone.schack.pieces;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
149
src/main/java/com/limone/schack/pieces/Pawn.java
Normal file
@@ -0,0 +1,149 @@
|
||||
package com.limone.schack.pieces;
|
||||
|
||||
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<Point> 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);
|
||||
}
|
||||
}
|
||||
}
|
233
src/main/java/com/limone/schack/pieces/Piece.java
Normal file
@@ -0,0 +1,233 @@
|
||||
package com.limone.schack.pieces;
|
||||
|
||||
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;
|
||||
|
||||
import com.limone.schack.boards.Board;
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* Nödvändigt för rockad
|
||||
*/
|
||||
protected boolean moved = false;
|
||||
protected BufferedImage pieceIcon;
|
||||
|
||||
public Piece(boolean white, Point startingPosition) throws IOException {
|
||||
this.isWhite = white;
|
||||
this.position = startingPosition;
|
||||
this.pieceIcon = getPieceIcon();
|
||||
}
|
||||
|
||||
public Piece(boolean white) {
|
||||
this.isWhite = white;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
private BufferedImage getPieceIcon() throws IOException {
|
||||
String colorName = isWhite() ? "White" : "Black";
|
||||
String path = "/com/limone/img/" + colorName + getClass().getSimpleName() + ".png";
|
||||
InputStream inputStream = getClass().getResourceAsStream(path);
|
||||
return ImageIO.read(inputStream);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ritar ut pjäsen baserat på den ihågkommna positionen
|
||||
*
|
||||
* @param g2
|
||||
*/
|
||||
public void draw(Graphics2D g2) {
|
||||
|
||||
g2.drawImage(
|
||||
getIcon(),
|
||||
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 + '}';
|
||||
}
|
||||
|
||||
public boolean equals(Piece otherPiece) {
|
||||
return getClass().getName().equals(otherPiece.getClass().getName())
|
||||
&& isWhite() == otherPiece.isWhite()
|
||||
&& supremeRuler == otherPiece.supremeRuler && moved == otherPiece.moved
|
||||
&& position.equals(otherPiece.position);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return true ifall pjäsen är vit
|
||||
*/
|
||||
public boolean isWhite() {
|
||||
return isWhite;
|
||||
}
|
||||
|
||||
/**
|
||||
* Kompabilitet med PieceKnownIfMoved
|
||||
*
|
||||
* @return false
|
||||
*/
|
||||
public boolean isMoved() {
|
||||
return moved;
|
||||
}
|
||||
|
||||
public BufferedImage getIcon() {
|
||||
return this.pieceIcon;
|
||||
}
|
||||
|
||||
}
|
20
src/main/java/com/limone/schack/pieces/Queen.java
Normal file
@@ -0,0 +1,20 @@
|
||||
package com.limone.schack.pieces;
|
||||
|
||||
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/limone/schack/pieces/Rook.java
Normal file
@@ -0,0 +1,21 @@
|
||||
package com.limone.schack.pieces;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
}
|