From 2c6b64fa7da13af0e6b7403d8af5efb12c0f7709 Mon Sep 17 00:00:00 2001 From: Persson-dev Date: Mon, 31 Mar 2025 22:28:08 +0200 Subject: [PATCH] pretty cool --- .gitignore | 4 +- app/src/main/java/chess/App.java | 6 +- app/src/main/java/chess/model/ChessBoard.java | 59 ++++++++- app/src/main/java/chess/model/Direction.java | 26 ++-- app/src/main/java/chess/model/Game.java | 31 +++++ .../model/visitor/PermissiveRuleChecker.java | 8 +- .../chess/model/visitor/PiecePathChecker.java | 15 ++- .../java/chess/simplerender/PieceIcon.java | 62 +++++++++ .../main/java/chess/simplerender/Window.java | 123 ++++++++++++++++++ app/src/main/java/common/Signal0.java | 26 ++++ app/src/main/java/common/Signal1.java | 27 ++++ .../main/resources/pieces2D/black-bishop.png | Bin 0 -> 1271 bytes .../main/resources/pieces2D/black-king.png | Bin 0 -> 3416 bytes .../main/resources/pieces2D/black-knight.png | Bin 0 -> 2341 bytes .../main/resources/pieces2D/black-pawn.png | Bin 0 -> 626 bytes .../main/resources/pieces2D/black-queen.png | Bin 0 -> 2488 bytes .../main/resources/pieces2D/black-rook.png | Bin 0 -> 589 bytes .../main/resources/pieces2D/white-bishop.png | Bin 0 -> 2727 bytes .../main/resources/pieces2D/white-king.png | Bin 0 -> 3187 bytes .../main/resources/pieces2D/white-knight.png | Bin 0 -> 2841 bytes .../main/resources/pieces2D/white-pawn.png | Bin 0 -> 1904 bytes .../main/resources/pieces2D/white-queen.png | Bin 0 -> 4333 bytes .../main/resources/pieces2D/white-rook.png | Bin 0 -> 1321 bytes 23 files changed, 363 insertions(+), 24 deletions(-) create mode 100644 app/src/main/java/chess/model/Game.java create mode 100644 app/src/main/java/chess/simplerender/PieceIcon.java create mode 100644 app/src/main/java/chess/simplerender/Window.java create mode 100644 app/src/main/java/common/Signal0.java create mode 100644 app/src/main/java/common/Signal1.java create mode 100644 app/src/main/resources/pieces2D/black-bishop.png create mode 100644 app/src/main/resources/pieces2D/black-king.png create mode 100644 app/src/main/resources/pieces2D/black-knight.png create mode 100644 app/src/main/resources/pieces2D/black-pawn.png create mode 100644 app/src/main/resources/pieces2D/black-queen.png create mode 100644 app/src/main/resources/pieces2D/black-rook.png create mode 100644 app/src/main/resources/pieces2D/white-bishop.png create mode 100644 app/src/main/resources/pieces2D/white-king.png create mode 100644 app/src/main/resources/pieces2D/white-knight.png create mode 100644 app/src/main/resources/pieces2D/white-pawn.png create mode 100644 app/src/main/resources/pieces2D/white-queen.png create mode 100644 app/src/main/resources/pieces2D/white-rook.png diff --git a/.gitignore b/.gitignore index 609e392..0056fd7 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,6 @@ # Ignore Gradle build output directory build -app/bin \ No newline at end of file +app/bin + +.vscode \ No newline at end of file diff --git a/app/src/main/java/chess/App.java b/app/src/main/java/chess/App.java index 716a717..5010ca6 100644 --- a/app/src/main/java/chess/App.java +++ b/app/src/main/java/chess/App.java @@ -3,7 +3,9 @@ */ package chess; -import chess.render.*; +import chess.model.ChessBoard; +import chess.model.Game; +import chess.simplerender.Window; public class App { public String getGreeting() { @@ -11,6 +13,6 @@ public class App { } public static void main(String[] args) { - new Window().run(); + new Window(new Game(new ChessBoard())); } } diff --git a/app/src/main/java/chess/model/ChessBoard.java b/app/src/main/java/chess/model/ChessBoard.java index 7bc1ae2..d0fd9f8 100644 --- a/app/src/main/java/chess/model/ChessBoard.java +++ b/app/src/main/java/chess/model/ChessBoard.java @@ -1,5 +1,11 @@ package chess.model; +import chess.model.pieces.Bishop; +import chess.model.pieces.King; +import chess.model.pieces.Knight; +import chess.model.pieces.Pawn; +import chess.model.pieces.Queen; +import chess.model.pieces.Rook; import chess.model.visitor.KingIdentifier; import chess.model.visitor.PiecePathChecker; @@ -30,6 +36,7 @@ public class ChessBoard { this.cells[i][j] = new Cell(); } } + initPieces(); } public void applyMove(Move move) { @@ -41,6 +48,7 @@ public class ChessBoard { Piece movingPiece = pieceAt(move.getStart()); pieceComes(movingPiece, move.getFinish()); pieceLeaves(move.getStart()); + movingPiece.move(); } public void undoMove(Move move) { @@ -52,7 +60,8 @@ public class ChessBoard { } public Piece pieceAt(Coordinate coordinate) { - assert (coordinate.isValid()); + if (!coordinate.isValid()) + return null; return cellAt(coordinate).getPiece(); } @@ -103,10 +112,56 @@ public class ChessBoard { continue; PiecePathChecker checker = new PiecePathChecker(this, new Move(attackCoords, kingPos)); - if (checker.isValidForPiece(attackPiece)) + if (checker.isValid()) return true; } } return false; } + + public boolean[][] getAllowedMoves(Coordinate pieceCoords) { + Piece piece = pieceAt(pieceCoords); + if (piece == null) + return null; + + boolean[][] result = new boolean[Coordinate.VALUE_MAX][Coordinate.VALUE_MAX]; + for (int i = 0; i < Coordinate.VALUE_MAX; i++) { + for (int j = 0; j < Coordinate.VALUE_MAX; j++) { + PiecePathChecker piecePathChecker = new PiecePathChecker(this, new Move(pieceCoords, new Coordinate(i, j))); + result[i][j] = piecePathChecker.isValid(); + } + } + return result; + } + + public void initPieces() { + for (int i = 0; i < 8; i++) { + pieceComes(new Pawn(Color.Black), new Coordinate(i, 0)); + pieceComes(new Pawn(Color.White), new Coordinate(i, Coordinate.VALUE_MAX - 1)); + } + + pieceComes(new Rook(Color.Black), new Coordinate(0, 1)); + pieceComes(new Rook(Color.Black), new Coordinate(Coordinate.VALUE_MAX - 1, 1)); + + pieceComes(new Rook(Color.White), new Coordinate(0, Coordinate.VALUE_MAX - 2)); + pieceComes(new Rook(Color.White), new Coordinate(Coordinate.VALUE_MAX - 1, Coordinate.VALUE_MAX - 2)); + + pieceComes(new Knight(Color.Black), new Coordinate(1, 1)); + pieceComes(new Knight(Color.Black), new Coordinate(Coordinate.VALUE_MAX - 2, 1)); + + pieceComes(new Knight(Color.White), new Coordinate(1, Coordinate.VALUE_MAX - 2)); + pieceComes(new Knight(Color.White), new Coordinate(Coordinate.VALUE_MAX - 2, Coordinate.VALUE_MAX - 2)); + + pieceComes(new Bishop(Color.Black), new Coordinate(2, 1)); + pieceComes(new Bishop(Color.Black), new Coordinate(Coordinate.VALUE_MAX - 3, 1)); + + pieceComes(new Bishop(Color.White), new Coordinate(2, Coordinate.VALUE_MAX - 2)); + pieceComes(new Bishop(Color.White), new Coordinate(Coordinate.VALUE_MAX - 3, Coordinate.VALUE_MAX - 2)); + + pieceComes(new Queen(Color.Black), new Coordinate(4, 1)); + pieceComes(new King(Color.Black), new Coordinate(3, 1)); + + pieceComes(new Queen(Color.White), new Coordinate(4, Coordinate.VALUE_MAX - 2)); + pieceComes(new King(Color.White), new Coordinate(3, Coordinate.VALUE_MAX - 2)); + } } diff --git a/app/src/main/java/chess/model/Direction.java b/app/src/main/java/chess/model/Direction.java index a8ab8e6..4c673b7 100644 --- a/app/src/main/java/chess/model/Direction.java +++ b/app/src/main/java/chess/model/Direction.java @@ -3,8 +3,8 @@ package chess.model; public enum Direction { Unset(65), - Front(8), Back(-8), Left(-1), Right(1), - FrontLeft(7), FrontRight(9), BackLeft(-9), BackRight(-7); + Front(-8), Back(8), Left(-1), Right(1), + FrontLeft(-9), FrontRight(-7), BackLeft(7), BackRight(9); private final int indexOffset; @@ -16,15 +16,23 @@ public enum Direction { return indexOffset; } + public static Direction fromInt(int direction) { + for (Direction dir : Direction.values()) { + if (dir.getIndexOffset() == direction) + return dir; + } + return null; + } + public static Direction findDirection(Move move) { assert move.isValid() : "Move is invalid!"; int diffX = move.getFinish().getX() - move.getStart().getX(); int diffY = move.getFinish().getY() - move.getStart().getY(); if (diffX == 0 && diffY < 0) - return Direction.Back; - if (diffX == 0 && diffY > 0) return Direction.Front; + if (diffX == 0 && diffY > 0) + return Direction.Back; if (diffX < 0 && diffY == 0) return Direction.Left; @@ -32,14 +40,14 @@ public enum Direction { return Direction.Right; if (diffX < 0 && -diffX == diffY) - return Direction.FrontLeft; + return Direction.BackLeft; if (diffX > 0 && diffX == diffY) - return Direction.FrontRight; + return Direction.BackRight; if (diffY < 0 && diffX == diffY) - return Direction.BackLeft; - if (diffY > 0 && diffX == -diffY) - return Direction.BackRight; + return Direction.FrontLeft; + if (diffX > 0 && diffX == -diffY) + return Direction.FrontRight; return Direction.Unset; } diff --git a/app/src/main/java/chess/model/Game.java b/app/src/main/java/chess/model/Game.java new file mode 100644 index 0000000..67f1f2c --- /dev/null +++ b/app/src/main/java/chess/model/Game.java @@ -0,0 +1,31 @@ +package chess.model; + +import chess.model.visitor.PiecePathChecker; +import common.Signal0; +import common.Signal1; + +public class Game { + private final ChessBoard board; + + public final Signal0 OnRenderUpdate = new Signal0(); + public final Signal1 OnMoveRefused = new Signal1<>(); + + public Game(ChessBoard board) { + this.board = board; + } + + public ChessBoard getBoard() { + return board; + } + + public void tryMove(Move move) { + boolean valid = new PiecePathChecker(board, move).isValid(); + if (!valid) { + this.OnMoveRefused.emit(move); + return; + } + this.board.applyMove(move); + this.OnRenderUpdate.emit(); + } + +} diff --git a/app/src/main/java/chess/model/visitor/PermissiveRuleChecker.java b/app/src/main/java/chess/model/visitor/PermissiveRuleChecker.java index 637f8bb..8af813e 100644 --- a/app/src/main/java/chess/model/visitor/PermissiveRuleChecker.java +++ b/app/src/main/java/chess/model/visitor/PermissiveRuleChecker.java @@ -75,19 +75,19 @@ public class PermissiveRuleChecker implements PieceVisitor { int distance = this.move.traversedCells(); // Revoke moving backwards - if (directionIndexOffset * pawn.multiplier() < 0) + if (directionIndexOffset * pawn.multiplier() > 0) return false; // Allowing straight moves - if (Math.abs(directionIndexOffset) == Direction.Front.getIndexOffset()) { + if (Math.abs(directionIndexOffset) == Math.abs(Direction.Front.getIndexOffset())) { if (pawn.hasMoved()) return distance == 1; return distance == 1 || distance == 2; } // Allowing small diagonal moves - if (Math.abs(directionIndexOffset) == Direction.FrontLeft.getIndexOffset() - || Math.abs(directionIndexOffset) == Direction.FrontRight.getIndexOffset()) { + if (directionIndexOffset == Direction.FrontLeft.getIndexOffset() + || directionIndexOffset == Direction.FrontRight.getIndexOffset()) { return distance == 1; } diff --git a/app/src/main/java/chess/model/visitor/PiecePathChecker.java b/app/src/main/java/chess/model/visitor/PiecePathChecker.java index cf285d1..02f5036 100644 --- a/app/src/main/java/chess/model/visitor/PiecePathChecker.java +++ b/app/src/main/java/chess/model/visitor/PiecePathChecker.java @@ -24,7 +24,12 @@ public class PiecePathChecker implements PieceVisitor { this.board = board; } - public boolean isValidForPiece(Piece piece) { + public boolean isValid() { + if (this.move.getStart().equals(this.move.getFinish())) + return false; + Piece piece = this.board.pieceAt(move.getStart()); + if (piece == null) + return false; return visit(piece); } @@ -62,18 +67,16 @@ public class PiecePathChecker implements PieceVisitor { if (!new PermissiveRuleChecker(this.move).isValidFor(pawn)) return false; - Direction moveDirection = Direction.findDirection(this.move); - // ... - // moveDirection = Directions(int(findDirection(move)) * pawn.multiplier()) + Direction moveDirection = Direction.fromInt(Direction.findDirection(move).getIndexOffset() * pawn.multiplier()); if (moveDirection == Direction.Front) - return testPath(pawn.getColor()); + return testPath(pawn.getColor()) && this.board.pieceAt(this.move.getFinish()) == null; assert moveDirection == Direction.FrontLeft || moveDirection == Direction.FrontRight; Piece destPiece = this.board.pieceAt(this.move.getFinish()); if (destPiece == null) - return true; + return false; return destPiece.getColor() != pawn.getColor(); } diff --git a/app/src/main/java/chess/simplerender/PieceIcon.java b/app/src/main/java/chess/simplerender/PieceIcon.java new file mode 100644 index 0000000..f47f509 --- /dev/null +++ b/app/src/main/java/chess/simplerender/PieceIcon.java @@ -0,0 +1,62 @@ +package chess.simplerender; + +import java.awt.Image; + +import javax.swing.Icon; +import javax.swing.ImageIcon; + +import chess.model.Color; +import chess.model.Piece; +import chess.model.PieceVisitor; +import chess.model.pieces.Bishop; +import chess.model.pieces.King; +import chess.model.pieces.Knight; +import chess.model.pieces.Pawn; +import chess.model.pieces.Queen; +import chess.model.pieces.Rook; + +public class PieceIcon implements PieceVisitor { + + private static final String basePath = "app/src/main/resources/pieces2D/"; + + public Icon getIcon(Piece piece) { + if (piece == null) + return null; + return new ImageIcon(new ImageIcon(basePath + colorToString(piece.getColor()) + "-" + visit(piece) + ".png").getImage().getScaledInstance(100,100, Image.SCALE_SMOOTH)); + } + + private String colorToString(Color color) { + return color == Color.Black ? "black" : "white"; + } + + @Override + public String visitPiece(Bishop bishop) { + return "bishop"; + } + + @Override + public String visitPiece(King king) { + return "king"; + } + + @Override + public String visitPiece(Knight knight) { + return "knight"; + } + + @Override + public String visitPiece(Pawn pawn) { + return "pawn"; + } + + @Override + public String visitPiece(Queen queen) { + return "queen"; + } + + @Override + public String visitPiece(Rook rook) { + return "rook"; + } + +} diff --git a/app/src/main/java/chess/simplerender/Window.java b/app/src/main/java/chess/simplerender/Window.java new file mode 100644 index 0000000..80baf2d --- /dev/null +++ b/app/src/main/java/chess/simplerender/Window.java @@ -0,0 +1,123 @@ +package chess.simplerender; + +import java.awt.Color; +import java.awt.GridLayout; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JPanel; + +import chess.model.ChessBoard; +import chess.model.Coordinate; +import chess.model.Game; +import chess.model.Move; + +public class Window extends JFrame { + + private final JLabel cells[][]; + private final Game game; + private final ChessBoard board; + + private Coordinate lastClick = null; + + public Window(Game game) { + this.cells = new JLabel[8][8]; + this.game = game; + this.board = game.getBoard(); + initSlots(); + build(); + setSize(800, 800); + setVisible(true); + setDefaultCloseOperation(EXIT_ON_CLOSE); + } + + private void initSlots() { + this.game.OnRenderUpdate.connect(this::updateBoard); + this.game.OnMoveRefused.connect(this::drawInvalid); + } + + private Color getCellColor(int x, int y) { + return ((x + y) % 2 == 1) ? Color.BLACK : Color.WHITE; + } + + private void build() { + JPanel content = new JPanel(new GridLayout(8, 8)); + setContentPane(content); + for (int y = 0; y < 8; y++) { + for (int x = 0; x < 8; x++) { + JLabel label = new JLabel(); + label.setOpaque(true); + label.setBackground(getCellColor(x, y)); + this.cells[x][y] = label; + + final int xx = x; + final int yy = y; + + label.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + onCellClicked(xx, yy); + } + }); + content.add(label); + } + } + updateBoard(); + } + + private void updateBoard() { + PieceIcon pieceIcon = new PieceIcon(); + for (int y = 0; y < 8; y++) { + for (int x = 0; x < 8; x++) { + JLabel cell = this.cells[x][y]; + cell.setIcon(pieceIcon.getIcon(this.board.pieceAt(new Coordinate(x, y)))); + } + } + } + + private void previewMoves(int x, int y) { + boolean[][] allowedMoves = this.board.getAllowedMoves(new Coordinate(x, y)); + if (allowedMoves == null) + return; + for (int i = 0; i < 8; i++) { + for (int j = 0; j < 8; j++) { + JLabel cell = this.cells[i][j]; + if (allowedMoves[i][j]) + cell.setBackground(Color.CYAN); + } + } + } + + private void drawInvalid(Move move) { + JLabel from = this.cells[move.getStart().getX()][move.getStart().getY()]; + JLabel to = this.cells[move.getFinish().getX()][move.getFinish().getY()]; + from.setBackground(Color.RED); + to.setBackground(Color.RED); + } + + private void clearMoves() { + for (int y = 0; y < 8; y++) { + for (int x = 0; x < 8; x++) { + JLabel cell = this.cells[x][y]; + cell.setBackground(getCellColor(x, y)); + } + } + } + + private void onCellClicked(int x, int y) { + clearMoves(); + if (this.lastClick == null) { + if (this.board.isCellEmpty(new Coordinate(x, y))) + return; + this.lastClick = new Coordinate(x, y); + previewMoves(x, y); + return; + } + if (!this.lastClick.equals(new Coordinate(x, y))) + this.game.tryMove(new Move(lastClick, new Coordinate(x, y))); + this.lastClick = null; + } + +} diff --git a/app/src/main/java/common/Signal0.java b/app/src/main/java/common/Signal0.java new file mode 100644 index 0000000..ab3af2c --- /dev/null +++ b/app/src/main/java/common/Signal0.java @@ -0,0 +1,26 @@ +package common; + +import java.util.ArrayList; +import java.util.List; + +public class Signal0 { + private final List handlers; + + public Signal0() { + this.handlers = new ArrayList<>(); + } + + public void connect(Runnable handler) { + this.handlers.add(handler); + } + + public void disconnect(Runnable handler) { + this.handlers.remove(handler); + } + + public void emit() { + for (Runnable handler : this.handlers) { + handler.run(); + } + } +} diff --git a/app/src/main/java/common/Signal1.java b/app/src/main/java/common/Signal1.java new file mode 100644 index 0000000..d491fba --- /dev/null +++ b/app/src/main/java/common/Signal1.java @@ -0,0 +1,27 @@ +package common; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Consumer; + +public class Signal1 { + private final List> handlers; + + public Signal1() { + this.handlers = new ArrayList<>(); + } + + public void connect(Consumer handler) { + this.handlers.add(handler); + } + + public void disconnect(Consumer handler) { + this.handlers.remove(handler); + } + + public void emit(T arg) { + for (Consumer handler : this.handlers) { + handler.accept(arg); + } + } +} diff --git a/app/src/main/resources/pieces2D/black-bishop.png b/app/src/main/resources/pieces2D/black-bishop.png new file mode 100644 index 0000000000000000000000000000000000000000..0dd4f27ca2eea4b2ad2f64be437716926449400b GIT binary patch literal 1271 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 yP(+nXSm%*_4{+g4f`VwFbejwR``u(0Inzo-U3d z6?5Ls==MGAAmDQTLIb}P!$pP(|GXbuW@ut-Fkv`2-R0Q6pDe$HKJK0xprbM`?OEA( znOOl5zN{e*AoNGh;Z0rKbLLrPe>X;*V?FYA`Q--;a~mdq{_rV7)xv>C{N&+R*E|gx zmf7x#vbV99#Tq3_s@ieAZ|m4jz@K2 zn*|o|ANelE*YR@qxgERm?LwGX4_uw)6|-JMpqP2(k!UXF07fq+Fu@wYm?X#1@Mg2` z#ZDE5hYl493=bQs9U4jw*eWETiI!G}x zY~%G%W;ifkX61SOwfdML& zdjJ0Y8#itU2?N=i;n?#PiN>gwtyCMMUeUGw$zB@hUysi}p9 zg|A+{8XX-iFE3Y9Q}grl8y+5>ot@p?-QC&QX>4p{v)OOnys4?FDJ?B6C@4ryP9~8^ z9UUDpF)^1fU*_lM_w@86lgTU=3ynr+Wn~o?7q_;y_Vo0OjEv~$=tM?F78Mn>x3|yD z&Aop8`o)VE>FMcVVPQ^APF7Y{G#V`=Bt$|&!pzLf#l=NlULFdC!hFP~xl^wXv$wv= z-3*?C11Jo_`N`dp|9>!-<5>UzPqef!b%-qHkX`-cut?CC)*p1U!gE=4lTV`|B_6SC z?m$gccidPsHx<*cvv3Y#Aj+y={7{Uq&~tX@xfxr}keqhb{6kHRj7Y7HUA*FgZ15QI z_?Wvt5i?pi-mzoo>qGE0M-mi^W>@Kk)5W1a^Q%*r`k@BSFeZS;2-|YyARMsj;^nyr z-$O+LeddEovpkeaF&X#7mS>#Rbx78>09uW6IO#v7QG!yoGC%~nS)se@C6RB@T^_SZ zalQL4XOnI`NZwIh6fS}~PurqptJh6WTo(*f#Gx39R^ zWMl)BXIemrpD}=tHZ#{11uXrLxIKtwiCD*M5bxE36IJ9u36P>h)FPjU&`7zCkJKGJ z2aGntB-6~rs!Hu3iX3&IC7}=Tkt*>XY!YVc>A|`8@X=&Q&2rGnCO`)~xq(aG@)k6_ z3}wUzq%#Q(qNy9U5zJNXv~?(Aj1S`JQYs^(myH0mVxV8>X$1nBYp1Wm-g!5s zwS%n#hm5zdhXa5+ts@KuC@*IS9EOJ0Om_Of!s`Gd^*-UB#~uToQx=`+WT1 zln7n`pY&8MIkom^!lf}N;K4yI=Y-acP%**Bh!7v&TRnjvu9qLxRRM>^d&RHm#0hk2 zyjb%K?Rq)0sh~Lt)=I%Wh^AMsHa?f@Z4jjoouE~;0zApC!bzai#y!O0kRI$y2T5f+ z^zg-!i-!QV6Hh1pHp46Dp|=O*cHF3nhzIq}wOV4jMNFDoE}sgfsq0Ueg|9R~2|lI> zh6v^sdOQ$<7O*aPQh6Oo**b0x5jRg?R)uG28M5^rhIwtll=X%~L;RfqHZ!{-V5vf| zG)xN)D&tii4mam1r~RF+q!R>`Rl*+gG>#t!8gO70_J^r3{7~n=FkD&TX#HVKF4@N* z1wnM+1+vo9(5hW@7KJ+3H;4!951j_PwQUoR_0Lvgq6!58kw{}#%G>Nmo;HF87-JRT zc&}5H@euo}CR&^h@*53+WWm4MEy44b^L&dy`xi$@hq7jL2t>ugWEZfU^Q7jLTm=pjSe7S& zTul^*Q-qjd7s@d50jbB8SLc#on10_rylVP1cIJ4j)OP!TaA&x7Ny6T^^O&xdQWQ}C zNf$TPey$pYvAr|=GO1k;3&~af9=v$-hF3|nP}|Yn;U-y3g1yzr?>Rq~vcR5KI#=>+ zcUi^|yyX(JLeKxm85ffvk?y~V4?U~^3#Z60+RyINo`>W_9-UR{=!lxgPLKe@O(wdN zNN#WIKkK8=zVDDcm^o)wWZtGLKAKEDySj>CX+u%nH1>1v+>FVgvxDhG>J+KovTTtQ zBiOO_4B=6rW<)~2YP%PP{hXr!&t#ZrmzP&S&X?h*TW z=~?FK@u)hZmQ>da(Hz~C%!z3clQG$nw(I@Oy5j9xBR30%RO=JNZJr8kr)VYnymVfa{caO?hj(ZV*8Mt%7}TziaTw7s92&3JP+IwrD=q*#L>s;aj8#NQ-(<)cj+ z27?m3qWV5hU$Q}uwm+UGo&sOrQ^_~rb0Y?9HEs|4vwm*0879+*CR=+>D^fmG~hNQ*-6sgbV=IfJa8ejpUwoO5VbeRDq8r|VMVx8{#fqZQM*40i~q)zf4}7vwUBg=(^eL{ zIexb3r~h=CsO*5b2QNFgHTt`}0?X834n=KF_-8nr5cH^f(9{4U9$vb#=XDBLFQae8 zo-QJOjcTllZICV%e+r|J2PVW4_Obrsf3%;hU3M%yE4T`LY^$cpTcSHVjQJ!Y#Ff8q z8f@?e_PUe5M(bVu^)4}+JfzGUh-@ut-Z3Wc*tZ~P@t-#$B8s#GPzts1YDfSmL*a^q aEL*|;K(;Pzvi8pJcghlLZBb|D5&vJaz~#^Y literal 0 HcmV?d00001 diff --git a/app/src/main/resources/pieces2D/black-rook.png b/app/src/main/resources/pieces2D/black-rook.png new file mode 100644 index 0000000000000000000000000000000000000000..79a3f57744a186791fbb8f24a1df33e1666d19a3 GIT binary patch literal 589 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H3?#oinD`S&F%}28J2BoosZ$T+a29w(76TPu z2Vq7hjoB4ILHhuo5LX}#1poj42a?yWT}w?(y?giW_U+p{Iy%msJ9p;Hney^-V`Jk# zfBvMWrwa-Se*E}x)v8syckjM_{rZ+ITizav6$k1REeY}qW?%#wgAU$SuZjUWrp?pE zF{EP7+grE&S_}jl68WSaE4tnPuV{MAxyOlBf12)W&C4%UV$J@?ejNN zEg+}CfJge{5{~xycTa9y{Af+ifn8@bR41L>=y~KP^E76snB>y=OH&vguxBi8+qEOV z+tb~_TxR*N9g&7FIcBWO-g)}%u29XFoCd5648Pf9M49Sh@3(EcVf|p&67iP#MhEsU z@Hd-aS9@dC{+lPeS-O7RUcAO(!OHa#&(a!K?Ms_y$W`(+RQRsWj+3(752Hil%`ZnS zXFi*IIrfIijMNM@#p!R o*^GNQA3gr^CUY6oL93YmF@!qYYCMwSpa~N4boFyt=akR{0M35`00000 literal 0 HcmV?d00001 diff --git a/app/src/main/resources/pieces2D/white-bishop.png b/app/src/main/resources/pieces2D/white-bishop.png new file mode 100644 index 0000000000000000000000000000000000000000..550c0d1d2e228746f9eb776c7b124dd66c046c66 GIT binary patch literal 2727 zcmZ`*X*ARg7ynNaB8+VF7|UbHZZrnN4ACG)8Os=DkTQd@hOs4LDq=#GWT)|xj5bB2 zEN#PBvXp&S_N7RKl6Rg@?|DAF_ndow=id9f=broF-g6oDwpKy{FaZDngsgEE1TND5 z(L)Eh*4Kb_f(r+!SUeU0o~9lC?ZLzKUqOjSa1J^o-EDU{o3@E--4sTEw}#*(Zpu*6FvtA$Yk;)AlS zrcIE5lvEHH1sWCUBFJAAQPTload$*FiG&QbDK!Vtlh_hgU$$wc2Hw>^KEFppG^2lx zX|3!gs$V0JaAqvk?<4PLNy>F{=PKpO-$TuRbbdt)Y{`8YH!xZbGx?TwWg?HX-!z#Q zwb2EF{!eoD%|&H?PbNHM0x#a`zzR`{17ofHydpucDZ}MLVfBczjas{xal5jMwuzF5 z31}JnCV82o?8UW}`EbYJ{LY-6%(!#feso-`kJ^_jpfovnB zW}ioThx&l3zTMow8&+ZSs|p_o+S>gt70duBh58JYH&=E7Ib@h)3fg0AzWN@;p1()C zn#dpAxhS$aE9KM|m@awuw>K$B@~Ryh#dNOY{Z!$7Bclk17Nak(Oy3xB?{K?Jk#S5R znNfRcPe3~gg^x)F2$Hd?lfjr8=PJ5s<<{%;zHXB_BiZ6coB471&v>y3a{ece5p$TS zRLr6($1loiA{%M_SAZFxsp5yl;PC1!zqkz6_uRtu!;$xm8!^#o_g>%?i_YCE7o*eS1oj824 zkXSOQT+F0KJ(A~)Fh^ZI^L*bhdWq=WM*`6$=O4tW37LclVSoB&^OW;M7iN3iNhET1 zXbSJoxi8;7BTaj<+(vV8zZ9WCdUDf8=fn(j zPJb=*{%it8yV0^Dc{Upb-t{aQsk4gwfFM25!&U;TcxoXPg1KagmsF2flEUOu;IU zjv*@0R7sJMnlg`E#ayTojpMyUEN7#@#-QqTGTkn+dXG10zp(O>4)ZK2cmM_Ns<2Vo zTc-krNRwNxW5?A`XzN)y&6PDV!(mfJlbezHP;J2kaj<%%Rr9%IiOaH2A z6|oM=%Al#|z>=fS=BJi8*`5}%$%Gv`M|JqfaW0)1WPhvLfxI(FQkn&C{0<6r@eXcz zp#4<+W0}(*ygEX)X9f+|6>svNx|n=@`ixJGQ|ag5;G-d@5?&Hu`bB%M_N)$liAA%G zU7TK=d}ivma|hX<^=zE9j|2N|$d234AAdXLqv^u*CTvsh`V5edG7*BCr9XDK@!L#4ai ziwZ9IpjcJ(DjA zWi2_%Fqea=golDY22l5y*h|HG*HPdJ-Hxk^FW>c>-hA4#jhmv5l!pnWGcC;|X*v@^&Xky;u*Sz8&9bHs zZZE0%Un%)C&*h#MTd55vgw{2Mcti{0%DXwnrJE;3Hdj#l*J~XVj5zktWsksa;7Eq~ z9G+Qk_VATrAKOW(v~IcOr+?1kfXvf~Eh(x7DORJ%r7JeE!LtiGIbYMTmQ~=jMI4q2 zt54B?+%CLt>o6U{T_)*NV1fA;PVJ0kho-6EIPYa2kDnrT8z|f;x`pnp1XFE;=jo zZ|}*1K6|``Q{gSP?qrko75)^Z#DHgQ-U93_dz%pFo%FPH9EPWJ4jEX}drA}TQy^ui z*NMYXO?1^gjO%AItW?lIih>008Ad#py&wrK*n{`59uz>Cz#BRBm#spZ903l+q;>%pvNYBQg^BWy#9F@CHsiUwM?FQhGX zM=Pq%_&MvyGYp21KRR?e%jm{IM=pfLQPYKwUOpV}#vM(Iq9_JB!S|@9cdjUQ*#lT8 z?|49v0G%~7ZID4*prK)ZrN8~QQ@%4VGfUp^z>-L6G(~s$Jzy4T7 zqoJkIJ&b-|?=?P1F;;9QRHqW)ZNY~mqb@I$i9ya*{B+eb$~_>EXCs{FnQ4h?%Y_GpMJt*9vR;BC_$M}F&U56VoV(3WM{8sz&f;0n z3|`X3*h%rr?xY1x`Ghn5d}rJBmRO9j&ewv>M%Rmy32tS!d&3```yHhDj}1q(T(obi z7I%1GO{|1!kEXi|!Vzv#={TOWgTn)z;l?#n>#uZDN6#PUS4g!8lEY15s5{GR` zg^jcR#$EyQBFAGh+~*i;d@c|8%d2lbNpBVM+jgbbDYimLSvtuv`P*4aTL!n>{w0>m z`(Uxk%>0Fp2nhF4Qw}@n9Omf}=7piqytn`$5juu&gaI6hBI=+q`e+PNPZNQ}AP@IBz=&x_34*-yIS&zNWpXH)HaD){A5HEekO9cRq&PwR-06?@70I=!_06+@? z0KTx|b~~N32EDh1sSyD1;+}-cS;ia&zZQ8mY3iS#Gmw202LP}-m>KCi#C=*Xz7@qY zd1>gXBnFt7DhY(!KG?iVVuTcWl6obQ)stOB9PS+TnKo58aJWRDYA7ra@OL%Cms6r<{SaH$ApkS^6*A1C^aLk4RYVZ>|ab zBo`0~vhnaz7i3OW$97Y?|o}9`@1A#TVISkoo$(dg(?kBX7T&8J=h; zmm4Z-${xBC2H8L+9sTnv)?k7RSn_=4eQuZIx{Q$`V#^X^R8+o%uzK(^$ze$lRV zr!P1Rj*#|$TY)=mm|79D6e|eM<9`zdtz6P_4EE1&XG5vI@%^lMN>cWv$2MU|s-N2Ezt5>Fm zyYL}e=f0ED{wA|D9r=?WW#q1AT-bv|tnMo1(MACp<;TiDAbw%Ls#~#iN@A2QH(;LZ z!#=!}qwEF)Lk4VZbTc4?+SnQd?@MOqzDNK~Yk`<;DO5Yq$wSJ^(jCi{&QLWI#m2nQ z*5~{k&s*uK_s3p$8}O@0Fhvx<%?R00Pqc>MKoMC+2SRvFfni*2RAb|Bp+6esOWiu7 zdQP=@j@!5bC~iC7P5RtOXLLQh^XTT1*@(sX$`mGd__5^ZgJkf=yYY_OAAa{$dHGYQ z2$@qm`D{r_1#LmBX_bh0rd}!m;$r%=;5)1&_l@uw7yr?}qS~+Xh7ic2C55 z)olethDs2qLBrNrsyOK1F}odCIEl0VjdrHbS@wLwTERlni~5<8<5Eev&S1<2WSzIHBm#TTL8vT5E zkc)bf88`i2J_z_~C2(m3En;#yk0G^tvJO-(kG+o!Razt^36zeWq)n# zDb`o<`{%03>xA1&aN@Dk)rRedEBBx&Xn|htO^Z>r$#3!Qt+yoSN{WKFAnyf_QV!yi zE+576Fto*FIVnn9i8E`V@S!4zrA}R*R!Q9|vT^hbaX%i4;c>bVODeA6B5$juj%%%U zZP2YTRu!*7Zp-1X-(qma*H;!O(FgGavt&33BAHs!r3RYjx+I$ zrScNlGrPO)6xWPVm#2kC^USi7iiD(8*nm{L`NsiwQ^8Qwu)?Xukxbd6rrLoSEgY-1 zvrVN({juVtOG7ScEvW0bIVd)Bl9I-D2^wc$k>0u-R48urZ&b;!r;FqHpaI17$xHKu46M7M@=?sJZ?{`K9$n zB;Jm1DtrR^M9f%IGaU9;TyCyoQ%7GWE2CgFTgG{<#S1>WR7Y#CZ;*H3(%KyQNubtZ zqTz|tWOk^k_7inItNX58jmBO1Dv$@!?X9lQ-ZdPRL{$BHMoxx-SQDPcial1EzzI<^ zkc`eXDV;)P^o*bcEB2LoftEQ{{s@(&lccc>DPpXe_1&(0n`1Fe*1koN3(2A;t3Rdx4!UwHgJe z4NgBMzzN4bVG|sg)Bj6nPCEz=0KCB~8QT zd%S?E@nQut&SWLP++yO39DCD4WslUDWA$-iLjSz3iAmfg5)d!fjh#eX{(RC!{0mv5 zBQ`~mty7Sp_%s;$-CC-h>^A3MeQvi(b?}k$C@r{>Vml+aPc_FAhwk4F9-X~(+Vm`3 zUUTLSmA4kxEw>9|Z=^u4Eo7&UH5nIv9r`PspL-FNeF5=BOG-{^%KjI_M$0}oQ&9R& zrrh>L>e{hnPZQJUiMK`)?l9f{O!2$GbPUhtNVEj&?A7A3OzKE%uczlaA9&+Yw6x|S zq+w{C8CtO*$*yNns?UW&Vyqcx_#ct$Yr)&jH1iwHFA~Y8V&ktboc3GqhiT12@2Mer zHBPi}J7lq3*3TTBZ(-VW#?^}wF_#ay%|VXUj8E|+&)h~EF$qgAFlg`Vv~v_(_VlP? z%ob0j+o09)W|U;lu=#c0jCj$HAGi;%hn|k}3@fg7c;FCf+m7 z@}TJF)Kc-{b*Tf)8s%1VSbV8>l0l36H_11^thA5ax}-szLICOsvt$6^DxP5!DQy|)GN5XX??a$oV9 zpDl?+c11reWzjqY_Rg&*2U+WRLG@Ux=e7@1+XB6~?RMD}z48E^t`vvWFs zh^vehDmYkFG&|Ur_Uvfy!MqTNzF>i0UdO8xxkU{7(bLYw(Y{yBX;SU#L%n?->A8l$5m;lr$AoG#r$*q3YUD6-_xM6{wO@ z<5B+b{|G`tktn~L|6edjRE$0o2>dg_KGZKN)+@pn5E~n-h`JFJ>EjjVs~8&L|7b%8 Qd`1G88Cx6G8h9rE3mXdC&;S4c literal 0 HcmV?d00001 diff --git a/app/src/main/resources/pieces2D/white-knight.png b/app/src/main/resources/pieces2D/white-knight.png new file mode 100644 index 0000000000000000000000000000000000000000..15724748fe1303e1537469e2395fb276a5ca3942 GIT binary patch literal 2841 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 ZaqiMsyl2i9l9x&XP&Z8V%5_}s{|Aa}Et>!U literal 0 HcmV?d00001 diff --git a/app/src/main/resources/pieces2D/white-pawn.png b/app/src/main/resources/pieces2D/white-pawn.png new file mode 100644 index 0000000000000000000000000000000000000000..b2ddcf006465ebd0b84c7de395d71269c5d35b59 GIT binary patch literal 1904 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 SI~ysWA_h-aKbLh*2~7YmdL}*q literal 0 HcmV?d00001