Add comments, clean up code

main
Elnu 2 years ago
parent 91c04cbcf2
commit 309231e304

@ -1,33 +1,50 @@
import java.awt.*; import java.awt.Color;
import java.awt.Graphics;
public class Board { public class Board {
// Width and height of each board tile
static final int TILE_SIZE = 64; static final int TILE_SIZE = 64;
// Width and height of board in tiles
static final int BOARD_SIZE = 8; static final int BOARD_SIZE = 8;
// Width and height of window in pixels
static final int DIMENSION = TILE_SIZE * BOARD_SIZE; static final int DIMENSION = TILE_SIZE * BOARD_SIZE;
// Colors from Lost Century 24 // Colors from Lost Century 24
// https://lospec.com/palette-list/lost-century-24 // https://lospec.com/palette-list/lost-century-24
// new Color() takes in an integer representing the color
// Colors are represented in hexadecimal, so we can write the hex literal by prefixing the color code with 0x
static final Color BLACK = new Color(0x6c595c); static final Color BLACK = new Color(0x6c595c);
static final Color WHITE = new Color(0xab9b8e); static final Color WHITE = new Color(0xab9b8e);
final DrawingPanel panel; final DrawingPanel panel;
final Graphics graphics; final Graphics graphics;
// The board is a two-dimensional array of nullable pieces
Piece[][] board; Piece[][] board;
// The current board coordinate that's being dragged
BoardCoordinate dragging = null; BoardCoordinate dragging = null;
public Board() { public Board() {
// Initialize DrawingPanel
panel = new DrawingPanel(DIMENSION, DIMENSION); panel = new DrawingPanel(DIMENSION, DIMENSION);
graphics = panel.getGraphics();
// Connect up event handlers
panel.onMouseDown(this::handleMouseDown); panel.onMouseDown(this::handleMouseDown);
panel.onMouseDrag(this::draw); panel.onMouseDrag((x, y) -> {
// We want to re-render with new mouse position when dragging pieces
if (dragging != null) draw(x, y);
});
panel.onMouseUp(this::handleMouseUp); panel.onMouseUp(this::handleMouseUp);
graphics = panel.getGraphics();
// Initialize board
board = new Piece[BOARD_SIZE][BOARD_SIZE]; board = new Piece[BOARD_SIZE][BOARD_SIZE];
for (int y = 0; y < 2; y++) {
// Initialize pieces
for (int y = 0; y < 2; y++)
for (int x = 0; x < BOARD_SIZE; x++) { for (int x = 0; x < BOARD_SIZE; x++) {
set(x, y, new Piece(true)); set(x, y, new Piece(true));
set(x, y + 6, new Piece(false)); set(x, y + 6, new Piece(false));
} }
} }
}
public Piece get(int x, int y) { public Piece get(int x, int y) {
return board[y][x]; return board[y][x];
@ -54,30 +71,46 @@ public class Board {
move(from.x, from.y, to.x, to.y); move(from.x, from.y, to.x, to.y);
} }
// Mouse down event handler
// This sets the currently dragging piece
void handleMouseDown(int x, int y) { void handleMouseDown(int x, int y) {
// Get board coordinate of mouse click
BoardCoordinate coordinate = new ScreenCoordinate(x, y).toBoard(); BoardCoordinate coordinate = new ScreenCoordinate(x, y).toBoard();
// If there's no piece there, return
if (get(coordinate) == null) return; if (get(coordinate) == null) return;
// Set currently dragging piece to that coordinate
dragging = coordinate; dragging = coordinate;
// Redraw with dragging
draw(x, y); draw(x, y);
} }
void handleMouseUp(int x, int y) { void handleMouseUp(int x, int y) {
// Get board coordinate of mouse release
BoardCoordinate newCoordinate = new ScreenCoordinate(x, y).toBoard(); BoardCoordinate newCoordinate = new ScreenCoordinate(x, y).toBoard();
// Only do something if new coordinate is different from the originating coordinate
if (!dragging.equals(newCoordinate)) { if (!dragging.equals(newCoordinate)) {
// Get piece on target coordinate
Piece capturedPiece = get(newCoordinate); Piece capturedPiece = get(newCoordinate);
// Only move piece to square if there's nothing there, or they are of differing colors
if (capturedPiece == null || capturedPiece.black != get(dragging).black) { if (capturedPiece == null || capturedPiece.black != get(dragging).black) {
move(dragging, newCoordinate); move(dragging, newCoordinate);
} }
} }
// Clear dragging
dragging = null; dragging = null;
// Redraw without dragging
draw(); draw();
} }
public void draw() { public void draw() {
draw(0, 0); draw(null);
} }
public void draw(int mouseX, int mouseY) { public void draw(int mouseX, int mouseY) {
draw(new ScreenCoordinate(mouseX, mouseY));
}
public void draw(ScreenCoordinate mousePosition) {
// Draw board // Draw board
graphics.setColor(WHITE); graphics.setColor(WHITE);
graphics.fillRect(0, 0, DIMENSION, DIMENSION); graphics.fillRect(0, 0, DIMENSION, DIMENSION);
@ -85,21 +118,18 @@ public class Board {
for (int y = 0; y < BOARD_SIZE; y++) for (int y = 0; y < BOARD_SIZE; y++)
for (int x = y % 2; x < BOARD_SIZE; x += 2) for (int x = y % 2; x < BOARD_SIZE; x += 2)
graphics.fillRect(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE); graphics.fillRect(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE);
// Draw pieces
forEachPiece((coordinate, piece) -> { // Draw pieces
int x, y; forEachPiece((boardCoordinate, piece) -> {
if (coordinate.equals(dragging)) { // If piece is the one being dragged, render it at the mouse position
x = mouseX; // Otherwise, render it at the center of the board tile
y = mouseY; piece.draw(graphics, boardCoordinate.equals(dragging) ? mousePosition : boardCoordinate.toScreen());
} else {
x = coordinate.x * TILE_SIZE + TILE_SIZE / 2;
y = coordinate.y * TILE_SIZE + TILE_SIZE / 2;
}
piece.draw(graphics, x, y);
}); });
} }
// Functional interfaces for forEachPiece
// Provide ability to run code for each piece on board without having to duplicate nested for loop boilerplate
@FunctionalInterface @FunctionalInterface
interface PieceActionXY { interface PieceActionXY {
void forEachTile(int x, int y, Piece piece); void forEachTile(int x, int y, Piece piece);
@ -110,17 +140,26 @@ public class Board {
void forEachTile(BoardCoordinate coordinate, Piece piece); void forEachTile(BoardCoordinate coordinate, Piece piece);
} }
// Run code on each tile on board
// Usage:
// forEachPiece((x, y, piece) -> {
// // do something with piece
// });
public void forEachPiece(PieceActionXY tileAction) { public void forEachPiece(PieceActionXY tileAction) {
for (int y = 0; y < BOARD_SIZE; y++) for (int y = 0; y < BOARD_SIZE; y++)
for (int x = 0; x < BOARD_SIZE; x++) { for (int x = 0; x < BOARD_SIZE; x++) {
Piece piece = board[y][x]; Piece piece = get(x, y);
if (piece == null) continue; if (piece == null) continue;
tileAction.forEachTile(x, y, piece); tileAction.forEachTile(x, y, piece);
} }
} }
// Run code on each tile on board
// Usage:
// forEachPiece((coordinate, piece) -> {
// // do something with piece
// });
public void forEachPiece(PieceActionCoordinate tileAction) { public void forEachPiece(PieceActionCoordinate tileAction) {
forEachPiece((x, y, piece) -> tileAction.forEachTile(new BoardCoordinate(x, y), board[y][x])); forEachPiece((x, y, piece) -> tileAction.forEachTile(new BoardCoordinate(x, y), get(x, y)));
} }
} }

@ -1,12 +1,23 @@
// Board coordinate class.
// Provides tile coordinates for squares on the chess board.
public class BoardCoordinate extends Coordinate { public class BoardCoordinate extends Coordinate {
public BoardCoordinate(int x, int y) { public BoardCoordinate(int x, int y) {
super(x, y); super(x, y); // Execute superclass constructor
}
// TODO: reimplement as casting
// Convert to screen coordinate by getting center pixel of tile
public ScreenCoordinate toScreen() {
return new ScreenCoordinate(
x * Board.TILE_SIZE + Board.TILE_SIZE / 2,
y * Board.TILE_SIZE + Board.TILE_SIZE / 2
);
} }
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
if (obj == this) return true; if (obj == this) return true; // Equals if same object
if (!(obj instanceof BoardCoordinate other)) return false; if (!(obj instanceof BoardCoordinate other)) return false; // If other is not BoardCoordinate, not equals
return other.x == x && other.y == y; return other.x == x && other.y == y; // If is BoardCoordinate and x- and y-values match, equals
} }
} }

@ -1,5 +1,5 @@
import java.util.Objects; // Generic abstract Coordinate class for storing an (x, y) pair.
// BoardCoordinate and ScreenCoordinate inherit from this.
public abstract class Coordinate { public abstract class Coordinate {
public int x; public int x;
public int y; public int y;

@ -1,17 +1,28 @@
import java.awt.*; import java.awt.*;
public class Piece { public class Piece {
// Width and height of placeholder rectangle graphic
public static final int DIMENSION = 32; public static final int DIMENSION = 32;
public boolean black; public boolean black;
// If no parameter, default to white
public Piece() { } public Piece() { }
public Piece(boolean black) { public Piece(boolean black) {
this.black = black; this.black = black;
} }
// The Piece class doesn't store position,
// so when drawing we need to be provided this along with a graphics context when drawing
public void draw(Graphics graphics, int x, int y) { public void draw(Graphics graphics, int x, int y) {
graphics.setColor(black ? Color.BLACK : Color.WHITE); graphics.setColor(black ? Color.BLACK : Color.WHITE);
// Drawing is performed from the top-left corner.
// We need the drawn rectangle to be offset by half of the width and height
// so it is centered on the provided position.
graphics.fillRect(x - DIMENSION / 2, y - DIMENSION / 2, DIMENSION, DIMENSION); graphics.fillRect(x - DIMENSION / 2, y - DIMENSION / 2, DIMENSION, DIMENSION);
} }
public void draw(Graphics graphics, ScreenCoordinate coordinate) {
draw(graphics, coordinate.x, coordinate.y);
}
} }

@ -1,17 +1,21 @@
// Screen coordinate class.
// Holds pixel coordinates relative to window.
public class ScreenCoordinate extends Coordinate { public class ScreenCoordinate extends Coordinate {
public ScreenCoordinate(int x, int y) { public ScreenCoordinate(int x, int y) {
super(x, y); super(x, y); // Execute superclass constructor
} }
// TODO: reimplement as casting
public BoardCoordinate toBoard() { public BoardCoordinate toBoard() {
// We can convert to board coordinates by dividing by the tile size of each square on the board
return new BoardCoordinate(x / Board.TILE_SIZE, y / Board.TILE_SIZE); return new BoardCoordinate(x / Board.TILE_SIZE, y / Board.TILE_SIZE);
} }
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
if (obj == this) return true; if (obj == this) return true; // Equals if same object
if (obj instanceof BoardCoordinate) return obj == toBoard(); if (obj instanceof BoardCoordinate) return obj == toBoard(); // If other is BoardCoordinate, we can see if they match
if (!(obj instanceof ScreenCoordinate other)) return false; if (!(obj instanceof ScreenCoordinate other)) return false; // If not BoardCoordinate or ScreenCoordinate, not equals
return other.x == x && other.y == y; return other.x == x && other.y == y; // If is ScreenCoordinate and x- and y-values match, equals
} }
} }