SweatyImposterChess Game

Chess Game

Design a chess game: model the board, pieces, legal-move generation, turn order, and game-end detection (checkmate, stalemate, draws). Focus on a piece hierarchy that's easy to extend.

Clarifying questions

  • Standard chess only, or do we want to support variants (Chess960, custom pieces)?
  • Two human players, or do we need to plug in an engine?
  • Do we need full rule fidelity (en passant, castling, threefold repetition, fifty-move)?
  • Are we serializing games for replay (PGN/FEN)?
  • Time controls — out of scope or required?

Core requirements

  • 8x8 board with placement and lookup by coordinate.
  • Six piece types per color with correct move generation.
  • Alternating turns with legal-move validation including self-check prevention.
  • Special moves: castling, en passant, promotion.
  • Detect check, checkmate, stalemate, and draw conditions.
  • Maintain full move history for replay and undo.

Canonical class breakdown

GameOwns Board, two Players, move history, and game state; the entry point for makeMove.
Board8x8 grid of Squares; provides piece lookup, move application, and snapshotting for undo.
SquareA coordinate that may hold a Piece; thin wrapper that simplifies move generation.
Piece (abstract) — King, Queen, Rook, Bishop, Knight, PawnEach subclass generates its candidate moves from a position; legality is filtered by Board.
MoveValue object capturing from, to, captured piece, promotion, and special flags (castle, en passant).
MoveValidatorFilters candidate moves: removes self-check, applies turn order, validates special-move preconditions.
GameStateEvaluatorInspects Board after each move to flag check, checkmate, stalemate, and draw rules.
PlayerColor identity plus references to captured pieces; abstract for human vs engine.

Java sketchjava

// Java skeleton

enum Color { WHITE, BLACK }
enum PieceType { KING, QUEEN, ROOK, BISHOP, KNIGHT, PAWN }
enum GameStatus { ACTIVE, CHECK, CHECKMATE, STALEMATE, DRAW }

class Square {
    private final int row;
    private final int col;
    private Piece piece;
}

abstract class Piece {
    protected final Color color;
    protected boolean hasMoved;
    public abstract PieceType type();
    public abstract List<Move> candidateMoves(Board board, Square from);
}

class King extends Piece { /* + castling rights */ }
class Queen extends Piece { ... }
class Rook extends Piece { ... }
class Bishop extends Piece { ... }
class Knight extends Piece { ... }
class Pawn extends Piece { /* + en passant flag */ }

class Move {
    private final Square from;
    private final Square to;
    private final Piece captured;
    private final PieceType promotion;
    private final boolean isCastle;
    private final boolean isEnPassant;
}

class Board {
    private final Square[][] grid; // 8x8
    public Piece at(int r, int c) { ... }
    public void apply(Move m) { ... }
    public void undo(Move m) { ... }
    public boolean isAttacked(Square sq, Color byColor) { ... }
}

class MoveValidator {
    public boolean isLegal(Board board, Move m, Color toMove) {
        // filter candidate moves, reject self-check, validate special-move preconditions
    }
}

class GameStateEvaluator {
    public GameStatus evaluate(Board board, List<Move> history, Color toMove) {
        // check, checkmate, stalemate, threefold, fifty-move
    }
}

abstract class Player {
    protected final Color color;
    protected final List<Piece> captured;
    public abstract Move chooseMove(Board board);
}

class HumanPlayer extends Player { ... }
class EnginePlayer extends Player { ... }

class Game {
    private final Board board;
    private final Player white;
    private final Player black;
    private final List<Move> history;
    private final MoveValidator validator;
    private final GameStateEvaluator evaluator;
    private Color toMove;
    public GameStatus makeMove(Move m) { ... }
    public void undoLast() { ... }
}

Key decisions to defend

  • Each Piece subclass generates candidate moves; Board owns legality (it sees the whole position). Don't put 'is in check' logic on King.
  • Move is a value object — applying it returns a new state or pushes to history for undo, never mutates in place silently.
  • Castling and en passant are flags on Move, not separate operations, so the engine handles them uniformly.
  • GameStateEvaluator is separate from Board because draw rules (threefold, fifty-move) need history, not just position.
  • Use polymorphism over an isLegalMove switch on PieceType — variant chess is the canonical extension story.

Likely follow-ups

  • · Add an engine player — what's the interface?
  • · Support Chess960 — what changes in setup and castling?
  • · Implement undo/redo efficiently for a long game.

Dive deeper

Chess is the canonical test of polymorphism vs enum-and-switch. Strong candidates put move generation on Piece subclasses and legality (which requires global board awareness) on Board or a validator. Weak answers either bury everything in giant switches on piece type or, conversely, push global concerns like check detection into King. The interviewer is also probing whether you separate position state from history — draw detection forces the distinction.

All OOD prompts