Skip to content

Instantly share code, notes, and snippets.

@shiracamus
Last active September 22, 2021 22:46
Show Gist options
  • Save shiracamus/17feaddaf5fdbbf9d74f044c6300d9e8 to your computer and use it in GitHub Desktop.
Save shiracamus/17feaddaf5fdbbf9d74f044c6300d9e8 to your computer and use it in GitHub Desktop.
/* Model */
enum Face { NONE, BLACK, WHITE, INVALID };
class Piece {
final Face face, reverse;
Piece(Face face, Face reverse) {
this.face = face;
this.reverse = reverse;
}
}
final Piece NONE = new Piece(Face.NONE, Face.NONE),
BLACK = new Piece(Face.BLACK, Face.WHITE),
WHITE = new Piece(Face.WHITE, Face.BLACK),
INVALID = new Piece(Face.INVALID, Face.INVALID);
class Board {
static final int SIZE = 8;
private final Piece[][] cell = new Piece[SIZE][SIZE];
Board() {
for (int y = 0; y < SIZE; y++)
for (int x = 0; x < SIZE; x++)
cell[y][x] = NONE;
int center = SIZE / 2 - 1;
cell[center + 0][center + 0] = WHITE;
cell[center + 0][center + 1] = BLACK;
cell[center + 1][center + 0] = BLACK;
cell[center + 1][center + 1] = WHITE;
}
Piece pieceAt(int x, int y) {
return isValid(x, y) ? cell[y][x] : INVALID;
}
private boolean isValid(int x, int y) {
return 0 <= x && x < SIZE && 0 <= y && y < SIZE;
}
boolean canPut() {
return canPut(BLACK) || canPut(WHITE);
}
private boolean canPut(Piece piece) {
for (int y = 0; y < SIZE; y++)
for (int x = 0; x < SIZE; x++)
if (canPut(piece, x, y)) return true;
return false;
}
private boolean canPut(Piece piece, int x, int y) {
if (pieceAt(x, y) != NONE) return false;
for (int dy = -1; dy <= 1; dy++)
for (int dx = -1; dx <= 1; dx++)
if (canReverse(piece, x, y, dx, dy)) return true;
return false;
}
private boolean canReverse(Piece piece, int x, int y, int dx, int dy) {
if (dx == 0 && dy == 0) return false;
if (pieceAt(x + dx, y + dy).face != piece.reverse) return false;
do {
x += dx;
y += dy;
} while (pieceAt(x, y).face == piece.reverse);
return pieceAt(x, y) == piece;
}
boolean put(Piece piece, int x, int y) {
if (!canPut(piece, x, y)) return false;
cell[y][x] = piece;
for (int dy = -1; dy <= 1; dy++)
for (int dx = -1; dx <= 1; dx++)
if (dx != 0 || dy != 0) reverse(piece, x, y, dx, dy);
return true;
}
private void reverse(Piece piece, int x, int y, int dx, int dy) {
if (!canReverse(piece, x, y, dx, dy)) return;
while (pieceAt(x + dx, y + dy).face == piece.reverse) {
y += dy;
x += dx;
cell[y][x] = piece;
}
}
int count(Piece piece) {
int num = 0;
for (int y = 0; y < SIZE; y++)
for (int x = 0; x < SIZE; x++)
if (cell[y][x] == piece) num++;
return num;
}
}
abstract class Player {
final String name;
final Piece piece;
String message = "";
protected boolean thinking = false;
Player(String name, Piece piece) {
this.name = name + "(" + piece.face + ")";
this.piece = piece;
}
boolean play(Board board) { // return true when turn player
if (thinking) return false;
thinking = true;
return think(board);
}
abstract boolean play(Board board, int x, int y);
abstract protected boolean think(Board board);
protected boolean put(Board board, int x, int y) {
if (thinking && board.put(piece, x, y)) {
thinking = false;
message = "";
return true;
}
return false;
}
}
class Human extends Player {
Human(String name, Piece piece) {
super(name, piece);
}
boolean play(Board board, int x, int y) { // mouse clicked
if (put(board, x, y)) return true;
message = "Invalid place!";
return false;
}
protected boolean think(Board board) {
return false; // wait to click mouse
}
}
class Beginner extends Player {
Beginner(String name, Piece piece) {
super(name, piece);
}
boolean play(Board board, int x, int y) { // mouse clicked
return false; // ignore mouse clicked
}
protected boolean think(Board board) {
while (!super.put(board, int(random(Board.SIZE)), int(random(Board.SIZE))));
return true;
}
}
/* View */
static final int CELL_SIZE = 100;
static final int CELL_OFFSET = CELL_SIZE / 2;
static final int PIECE_OFFSET = CELL_OFFSET + CELL_SIZE / 2;
static final int PIECE_SIZE = (int)(CELL_SIZE * 0.8);
static final int WINDOW_SIZE = CELL_SIZE * Board.SIZE + CELL_OFFSET * 2;
static final int MESSAGE_X = WINDOW_SIZE / 2;
static final int MESSAGE_Y = CELL_SIZE / 3;
static final int SCORE_X = WINDOW_SIZE / 2;
static final int SCORE_Y = WINDOW_SIZE - CELL_SIZE / 6;
void draw() {
clearWindow();
drawBoard();
drawScore();
if (board.canPut())
drawPlayer();
else
drawJudgement();
}
void clearWindow() {
fill(0);
rect(0, 0, WINDOW_SIZE, WINDOW_SIZE);
}
void drawBoard() {
for (int y = 0; y < Board.SIZE; y++)
for (int x = 0; x < Board.SIZE; x++)
drawCell(x, y);
}
void drawCell(int x, int y) {
stroke(0);
strokeWeight(2);
fill(0, 150, 0); // board green
rect(CELL_OFFSET + x * CELL_SIZE, CELL_OFFSET + y * CELL_SIZE,
CELL_SIZE, CELL_SIZE);
noStroke();
drawPiece(x, y, board.pieceAt(x, y));
}
void drawPiece(int x, int y, Piece piece) {
if (piece != BLACK && piece != WHITE) return;
fill(piece == BLACK ? 0 : 255);
ellipse(PIECE_OFFSET + x * CELL_SIZE, PIECE_OFFSET + y * CELL_SIZE,
PIECE_SIZE, PIECE_SIZE);
}
void drawScore() {
fill(255);
text("BLACK: " + board.count(BLACK) + " vs WHITE: " + board.count(WHITE),
SCORE_X, SCORE_Y);
}
void drawPlayer() {
fill(255);
text("TURN: " + player.name + " " + player.message,
MESSAGE_X, MESSAGE_Y);
}
void drawJudgement() {
fill(255, 255, 0); // yellow
int piece1 = board.count(player1.piece);
int piece2 = board.count(player2.piece);
text(piece1 > piece2 ? player1.name + " won!" :
piece1 < piece2 ? player2.name + " won!" :
"draw!",
MESSAGE_X, MESSAGE_Y);
}
/* Controller */
void settings() {
size(WINDOW_SIZE, WINDOW_SIZE);
}
void setup() {
background(0);
colorMode(RGB, 256);
textSize(30);
textAlign(CENTER);
noLoop();
redraw();
thread("play");
}
void play() {
if (player.play(board)) {
turn();
}
}
void mousePressed() {
if (!board.canPut()) return;
int y = (mouseY - CELL_OFFSET) / CELL_SIZE;
int x = (mouseX - CELL_OFFSET) / CELL_SIZE;
if (player.play(board, x, y))
turn();
else
redraw();
}
void turn() {
player.message = "";
player = player == player1 ? player2 : player1;
if (!board.canPut(player.piece)) {
Player pass = player;
player = player == player1 ? player2 : player1;
if (!board.canPut(player.piece)) {
redraw();
return; // game is over
}
player.message = "(" + pass.name + " was passed)";
}
redraw();
thread("play");
}
Board board = new Board();
Player player1 = new Human("You", BLACK);
Player player2 = new Beginner("Computer", WHITE);
Player player = player1;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment