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 {
// Width and height of each board tile
static final int TILE_SIZE = 64;
// Width and height of board in tiles
static final int BOARD_SIZE = 8;
// Width and height of window in pixels
static final int DIMENSION = TILE_SIZE * BOARD_SIZE;
// Colors from 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 WHITE = new Color(0xab9b8e);
final DrawingPanel panel;
final Graphics graphics;
// The board is a two-dimensional array of nullable pieces
Piece[][] board;
// The current board coordinate that's being dragged
BoardCoordinate dragging = null;
public Board() {
// Initialize DrawingPanel
panel = new DrawingPanel(DIMENSION, DIMENSION);
graphics = panel.getGraphics();
// Connect up event handlers
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);
graphics = panel.getGraphics();
// Initialize board
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++) {
set(x, y, new Piece(true));
set(x, y + 6, new Piece(false));
}
}
}
public Piece get(int x, int y) {
return board[y][x];
@ -54,30 +71,46 @@ public class Board {
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) {
// Get board coordinate of mouse click
BoardCoordinate coordinate = new ScreenCoordinate(x, y).toBoard();
// If there's no piece there, return
if (get(coordinate) == null) return;
// Set currently dragging piece to that coordinate
dragging = coordinate;
// Redraw with dragging
draw(x, y);
}
void handleMouseUp(int x, int y) {
// Get board coordinate of mouse release
BoardCoordinate newCoordinate = new ScreenCoordinate(x, y).toBoard();
// Only do something if new coordinate is different from the originating coordinate
if (!dragging.equals(newCoordinate)) {
// Get piece on target coordinate
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) {
move(dragging, newCoordinate);
}
}
// Clear dragging
dragging = null;
// Redraw without dragging
draw();
}
public void draw() {
draw(0, 0);
draw(null);
}
public void draw(int mouseX, int mouseY) {
draw(new ScreenCoordinate(mouseX, mouseY));
}
public void draw(ScreenCoordinate mousePosition) {
// Draw board
graphics.setColor(WHITE);
graphics.fillRect(0, 0, DIMENSION, DIMENSION);
@ -85,21 +118,18 @@ public class Board {
for (int y = 0; y < BOARD_SIZE; y++)
for (int x = y % 2; x < BOARD_SIZE; x += 2)
graphics.fillRect(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE);
// Draw pieces
forEachPiece((coordinate, piece) -> {
int x, y;
if (coordinate.equals(dragging)) {
x = mouseX;
y = mouseY;
} else {
x = coordinate.x * TILE_SIZE + TILE_SIZE / 2;
y = coordinate.y * TILE_SIZE + TILE_SIZE / 2;
}
piece.draw(graphics, x, y);
// Draw pieces
forEachPiece((boardCoordinate, piece) -> {
// If piece is the one being dragged, render it at the mouse position
// Otherwise, render it at the center of the board tile
piece.draw(graphics, boardCoordinate.equals(dragging) ? mousePosition : boardCoordinate.toScreen());
});
}
// Functional interfaces for forEachPiece
// Provide ability to run code for each piece on board without having to duplicate nested for loop boilerplate
@FunctionalInterface
interface PieceActionXY {
void forEachTile(int x, int y, Piece piece);
@ -110,17 +140,26 @@ public class Board {
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) {
for (int y = 0; y < BOARD_SIZE; y++)
for (int x = 0; x < BOARD_SIZE; x++) {
Piece piece = board[y][x];
Piece piece = get(x, y);
if (piece == null) continue;
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) {
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 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
public boolean equals(Object obj) {
if (obj == this) return true;
if (!(obj instanceof BoardCoordinate other)) return false;
return other.x == x && other.y == y;
if (obj == this) return true; // Equals if same object
if (!(obj instanceof BoardCoordinate other)) return false; // If other is not BoardCoordinate, not equals
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 int x;
public int y;

@ -1,17 +1,28 @@
import java.awt.*;
public class Piece {
// Width and height of placeholder rectangle graphic
public static final int DIMENSION = 32;
public boolean black;
// If no parameter, default to white
public Piece() { }
public Piece(boolean 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) {
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);
}
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 ScreenCoordinate(int x, int y) {
super(x, y);
super(x, y); // Execute superclass constructor
}
// TODO: reimplement as casting
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);
}
@Override
public boolean equals(Object obj) {
if (obj == this) return true;
if (obj instanceof BoardCoordinate) return obj == toBoard();
if (!(obj instanceof ScreenCoordinate other)) return false;
return other.x == x && other.y == y;
if (obj == this) return true; // Equals if same object
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 not BoardCoordinate or ScreenCoordinate, not equals
return other.x == x && other.y == y; // If is ScreenCoordinate and x- and y-values match, equals
}
}