Add comments, clean up code
This commit is contained in:
parent
91c04cbcf2
commit
309231e304
5 changed files with 98 additions and 33 deletions
|
@ -1,32 +1,49 @@
|
||||||
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);
|
||||||
panel.onMouseDown(this::handleMouseDown);
|
|
||||||
panel.onMouseDrag(this::draw);
|
|
||||||
panel.onMouseUp(this::handleMouseUp);
|
|
||||||
graphics = panel.getGraphics();
|
graphics = panel.getGraphics();
|
||||||
|
|
||||||
|
// Connect up event handlers
|
||||||
|
panel.onMouseDown(this::handleMouseDown);
|
||||||
|
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);
|
||||||
|
|
||||||
|
// 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) {
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
Reference in a new issue