Java
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Object-Oriented Java
-
Section 4: Collections Framework
-
Section 5: Exception Handling
-
Section 6: Generics
-
Section 7: Functional Java
-
Section 8: Concurrency
-
Section 9: I/O and NIO
-
Section 10: JVM Internals
-
Section 11: Modern Java Features
-
Section 12: Build Tools and Project Structure
-
Section 13: Testing
-
Section 14: Databases and Persistence
-
Section 15: Networking
-
Section 16: Design and Best Practices
-
Section 17: Reflection and Annotations
-
Section 18: Logging and Diagnostics
-
Section 19: Date, Time, and Internationalization
-
Section 20: Java Platform Module System
-
Section 21: Security in Java
-
Section 22: Advanced Collections and Data Structures
-
Section 23: More Concurrency Patterns
-
Section 24: Compression, Files, and System Integration
-
Section 25: GUI Programming
-
Section 26: Practical Projects
-
Section 27: Data Structures and Algorithms
-
Section 28: Interview and Algorithm Practice
-
Section 29: JSON and Data Interchange
-
Section 30: More Concurrency Utilities
-
Section 31: More Collections and Streams Practice
-
Section 32: More File and System Programming
-
Section 33: Standard Library Deep Dive
-
Section 34: More Practice and Drills
-
Section 35: More Testing and Quality
-
Section 36: More Design Patterns and Architecture
-
Section 37: Career and Ecosystem
-
Section 38: More OOP and Architecture Practice
-
Section 39: More Enterprise Concepts
-
Section 40: Advanced JavaFX
-
Section 41: More Interview Practice
231: Building a Basic Chess Game Engine
When I first started building game engines, I fell into a trap that I see almost every junior developer hit when they tackle chess: the "Stringly-Typed" board. You'll be tempted to represent your board as a String[][] or an int[][], where "WP" stands for White Pawn and "BK" stands for Black King. It feels fast. You can print it to the console easily, and it seems intuitive.
Here is why that's a disaster. The moment you need to implement a move, you end up with a massive, nested switch statement or a chain of if-else blocks that looks like this:
if (board[row][col].equals("WP")) { // 50 lines of pawn movement logic } else if (board[row][col].equals("WR")) { // 50 lines of rook movement logic } // ... and so on for every pieceThis is brittle. One typo—like typing "Wp" instead of "WP"—and your game engine doesn't crash; it just silently fails to move the piece, leaving you hunting through logs for an hour. It's a maintenance nightmare because adding a new rule (like castling) requires hunting through a monolithic block of logic.
Forget Strings, Use Polymorphism
The correct way to handle this in Java is to let the pieces tell the board how they move, not the other way around. We want a polymorphic structure. I always start by defining an abstract
Piececlass. This class doesn't know how to move—that's for the subclasses—but it defines the contract that every piece must follow.public abstract class Piece { protected Color color; public Piece(Color color) { this.color = color; } public Color getColor() { return color; } // Every piece must implement its own rule set public abstract boolean isValidMove(Board board, Position start, Position end); }By doing this, the
Boardclass doesn't need to know if it's dealing with a Bishop or a Knight. It just callspiece.isValidMove(...). I love this approach because it encapsulates the complexity. If the Knight's movement logic is buggy, I know exactly which file to open:Knight.java.The Board as a Manager, Not a Rulebook
Another common mistake is putting the movement validation logic inside the
Boardclass. The board should be a coordinator. It should manage the 2D array ofPieceobjects and handle the physical swapping of positions, but it shouldn't be the one deciding if a diagonal move is legal for a Bishop.Think of the
Boardas the physical wooden board and thePieceas the intelligence. Here is a streamlined way to handle the move request:public class Board { private Piece[][] grid = new Piece[8][8]; public boolean movePiece(Position start, Position end) { Piece piece = grid[start.getRow()][start.getCol()]; if (piece == null) { return false; // No piece to move } if (piece.isValidMove(this, start, end)) { grid[end.getRow()][end.getCol()] = piece; grid[start.getRow()][start.getCol()] = null; return true; } return false; // Illegal move } }Notice how
movePieceis clean? It asks the piece if the move is valid, and if the piece says "yes," the board updates the state. This separation of concerns is what differentiates a "script" from an "engine."Handling the "Jump" Logic
Now, you might be wondering: "Wait, if the piece handles the logic, how does it know if another piece is blocking the path?" This is why we pass the
Boardinstance into theisValidMovemethod.For a Rook, the
isValidMoveimplementation will loop through the coordinates between the start and end points. If it hits any non-nullPiecein theboard.gridbefore reaching the destination, it returnsfalse. The Knight, of course, ignores this because it can jump. By passing the board reference, the piece has a "window" into the world around it without owning the world itself.
📋 Practical Task
Implementing the Knight's L-Shape Movement Logic
You have been provided with the Piece abstract class and the Board class. Your task is to create the Knight class that extends Piece.
Implement the isValidMove(Board board, Position start, Position end) method specifically for the Knight. Remember:
- The Knight moves in an "L" shape: two squares in one cardinal direction and then one square perpendicularly.
- Unlike the Rook or Bishop, the Knight can jump over other pieces; you do not need to check for blocking pieces between the start and end positions.
- The move is invalid if the destination square is occupied by a piece of the same color.
- The move is invalid if the destination is outside the 8x8 board boundaries.
Requirements:
1. Create the Knight class.
2. Use absolute difference calculations (Math.abs) to verify the 2-and-1 movement pattern.
3. Ensure you check the piece color at the destination square using the Board reference.
There are no comments for now.