C++
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Object-Oriented C++
-
Section 4: Memory Management
-
Section 5: Templates and Generic Programming
-
Section 6: The Standard Template Library
-
Section 7: Modern C++ Features
-
Section 8: Error Handling
-
Section 9: Multithreading
-
Section 10: Operator Overloading and Type Conversion
-
Section 11: Advanced Topics
-
Section 12: Tooling and Build Systems
-
Section 13: Design Patterns in C++
-
Section 14: Interfacing with C and Systems Programming
-
Section 15: Networking and IPC Basics
-
Section 16: Graphics and Game Programming Basics
-
Section 17: The Boost Libraries
-
Section 18: Data Structures and Algorithms in C++
-
Section 19: Practical Projects
-
Section 20: More Concurrency Patterns
-
Section 21: More OOP and Design Practice
-
Section 22: File I/O and Streams
-
Section 23: More Standard Library
-
Section 24: Practice Exercises
-
Section 25: Interview and Algorithm Practice
-
Section 26: Compiler and Language Internals
-
Section 27: GUI and Application Frameworks Overview
-
Section 28: Testing and Quality Practices
-
Section 29: Numerics Library
-
Section 30: Concepts Library (C++20)
-
Section 31: Ranges Library (C++20) In Depth
-
Section 32: More Utility Library
183: Building a Simple Chess Move Validator
Alright, let's get our hands dirty. We've talked about data structures for a board, but now we need the actual logic. I want to build a validator for a Rook. The Rook is a great place to start because its movement is simple—straight lines—but it introduces a problem that trips up a lot of developers: path obstruction.
The "Too Simple" Version
My first instinct is usually to just check if the move is horizontal or vertical. If the start and end coordinates share an axis, it's a Rook move, right? Let's look at this snippet I just threw together:
bool isValidRookMove(int startX, int startY, int endX, int endY) {
// A Rook moves in a straight line: either X stays same or Y stays same
return (startX == endX || startY == endY);
}
At first glance, this works. If I move from (0,0) to (0,5), it returns true. But wait. I'm thinking about the actual game of chess. If there's a Pawn sitting at (0,3), the Rook can't just teleport to (0,5). It's blocked. My code currently treats the board like a vacuum. I need to actually look at the squares between the start and the end.
Walking the Path
To fix this, I need to "walk" from the start position toward the end position and check if any square is occupied. I'll use a 2D array of chars to represent the board, where ' ' is empty and any other character is a piece. Here's how I'll try to implement the path-checking logic:
bool isPathClear(char board[8][8], int startX, int startY, int endX, int endY) {
int dx = (endX > startX) ? 1 : (endX < startX ? -1 : 0);
int dy = (endY > startY) ? 1 : (endY < startY ? -1 : 0);
int currX = startX + dx;
int currY = startY + dy;
while (currX != endX || currY != endY) {
if (board[currX][currY] != ' ') {
return false; // Found a piece! Path is blocked.
}
currX += dx;
currY += dy;
}
return true;
}
I used a little trick here with dx and dy. By calculating the direction (1, -1, or 0), I can use one while loop regardless of whether the Rook is moving up, down, left, or right. It's much cleaner than writing four separate if blocks for every direction.
The "Friendly Fire" Problem
Now, if I plug isPathClear into my move validator, I hit another snag. What happens when the Rook reaches the destination square? My while loop stops before it checks board[endX][endY]. This is actually good, because the destination square can have a piece on it—that's called capturing.
But I realized I forgot one critical rule: you can't capture your own piece. If I'm moving a White Rook and there's a White Knight at the destination, that move is illegal. I need to pass the piece's color into the function to handle this. Let's refine the final logic:
bool isValidRookMove(char board[8][8], int startX, int startY, int endX, int endY, char pieceColor) {
// 1. Basic movement rule
if (startX != endX && startY != endY) return false;
// 2. Check for obstructions
if (!isPathClear(board, startX, startY, endX, endY)) return false;
// 3. Check destination: Is it a teammate?
char destPiece = board[endX][endY];
if (destPiece != ' ' && isSameColor(destPiece, pieceColor)) {
return false; // Can't capture your own piece
}
return true;
}
I've separated the "path" logic from the "destination" logic. The path must be empty, but the destination can be either empty or occupied by an enemy. This structure makes the code much easier to debug because I can test isPathClear independently of the capture rules. It's a small distinction, but in a complex game, these little architectural choices keep you from losing your mind when you eventually have to implement the Knight or the Queen.
📋 Practical Task
Implementing the Bishop's Diagonal Path Validator
Now it's your turn. You've seen how the Rook moves in straight lines. The Bishop is similar, but it moves diagonally. This means both the X and Y coordinates must change by the same absolute amount (e.g., moving from (2,2) to (5,5) is a change of 3 in both directions).
Your Task: Create a function isValidBishopMove that mirrors the logic we used for the Rook. It must:
- Verify the move is a perfect diagonal (the absolute difference between startX/endX must equal the absolute difference between startY/endY).
- Use a path-checking loop to ensure no pieces are blocking the diagonal path.
- Ensure the destination square does not contain a piece of the same color.
Implement this using a char board[8][8] and a pieceColor char (e.g., 'W' for white, 'B' for black). Test it with a scenario where a Bishop is blocked by a pawn on its diagonal path to ensure your loop is working correctly.
There are no comments for now.