C#
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Object-Oriented C#
-
Section 4: Working with Data
-
Section 5: Error Handling
-
Section 6: Delegates and Events
-
Section 7: Async Programming
-
Section 8: More Language Features
-
Section 9: File I/O and Serialization
-
Section 10: Networking in .NET
-
Section 11: The .NET Ecosystem
-
Section 12: Memory and Performance
-
Section 13: Concurrency Beyond Async
-
Section 14: Reflection and Attributes
-
Section 15: Testing and Best Practices
-
Section 16: Design Patterns in C#
-
Section 17: Standard Library Deep Dive
-
Section 18: Data Structures and Algorithms in C#
-
Section 19: GUI and Desktop Development Overview
-
Section 20: Practical Projects
-
Section 21: More Practice Exercises
-
Section 22: More Standard Library and Text Processing
-
Section 23: More Design Patterns
-
Section 24: More Projects
-
Section 25: Interview Practice
-
Section 26: C# Keywords Reference (Modifiers)
-
Section 27: C# Keywords Reference (Statements)
-
Section 28: C# Keywords Reference (Operators)
-
Section 29: BCL: System.Collections.Generic
-
Section 30: BCL: System.Linq
-
Section 31: BCL: System.Threading
-
Section 32: BCL: System.IO
-
Section 33: BCL: System.Text and System.Text.Json
-
Section 34: BCL: System.Net.Http
-
Section 35: C# Language Specification Topics
-
Section 36: More Practice Exercises
-
Section 37: More Async Patterns
-
Section 38: More BCL: System.Reflection and System.Diagnostics
-
Section 39: Nullable Reference Types In Depth
-
Section 40: C# Records and Pattern Matching In Depth
-
Section 41: Dependency Injection Deep Dive
-
Section 42: More Interview and Whiteboard Practice
154: Building a Simple Chess Move Validator
Think of a chess move validator like a strict bouncer at a high-end club. The bouncer doesn't care who you are; they only care if you meet the specific criteria on their clipboard. "Are you on the list? Are you wearing the right shoes? Is your ID valid?" If any one of those is a "no," you aren't getting in. The bouncer doesn't try to guess where you wanted to go; they just compare your current state against a set of rigid rules and give a binary yes or no.
In C#, our validator works exactly the same way. We aren't simulating the whole game or handling the UI here. We are building a "bouncer" method that takes a starting position and an ending position, looks at the piece involved, and returns a bool. If the move violates the rules of that piece, the bouncer kicks the move out.
Defining the Coordinate System
Before we can validate a move, we need a way to talk about where things are. I find that using a record is the cleanest way to handle this in modern C#. It's lightweight and gives us value-based equality out of the box, which is perfect for a 2D grid.
public record Position(int Row, int Col);
Now, we can represent a move as a pair of these positions. If we're moving from Row 0, Col 0 to Row 0, Col 5, we know we've moved horizontally. This simple structure prevents us from passing around loose integers and getting our X and Y coordinates swapped—a mistake I've made more times than I'd like to admit.
Enforcing the Rook's Straight-Line Rule
Let's build the logic for the Rook. A Rook is simple: it can move any number of squares, but it must stay in the same row or the same column. It can't do both, and it certainly can't move diagonally.
I like to write these as "Guard Clauses." Instead of one giant if statement, we check for the valid conditions. For a Rook, the rule is: (start.Row == end.Row) OR (start.Col == end.Col). If neither of those is true, the move is illegal.
public bool IsRookMoveValid(Position start, Position end)
{
// A piece can't move to the spot it's already standing on
if (start == end) return false;
// The Rook must move either vertically or horizontally
bool isHorizontal = start.Row == end.Row;
bool isVertical = start.Col == end.Col;
return isHorizontal || isVertical;
}
The Bishop's Diagonal Logic
The Bishop is a bit trickier. It doesn't care about rows or columns individually; it cares about the relationship between them. For a move to be diagonal, the distance moved vertically must be exactly equal to the distance moved horizontally.
This is where Math.Abs becomes your best friend. We don't care if the Bishop is moving up-left or down-right; we only care about the absolute difference between the coordinates.
public bool IsBishopMoveValid(Position start, Position end)
{
if (start == end) return false;
int rowDiff = Math.Abs(start.Row - end.Row);
int colDiff = Math.Abs(start.Col - end.Col);
// In a perfect diagonal, the change in Row equals the change in Col
return rowDiff == colDiff;
}
Notice how we're keeping these methods pure. They don't change the state of the board; they just answer a question. This makes them incredibly easy to unit test. You can feed in a hundred different start and end positions and verify the output without ever having to actually "set up" a game board.
📋 Practical Task
Exercise: Implementing the Knight's "L-Shape" Constraint
The Knight is the most unique piece in chess because it doesn't move in a straight line. Its movement is always an "L" shape: it moves two squares in one cardinal direction and then one square perpendicularly. In mathematical terms, if the change in rows is 2, the change in columns must be 1 (or vice versa).
Your Task: Create a method called IsKnightMoveValid that takes two Position records (start and end). The method should return true only if the move follows the Knight's L-shape rule. Otherwise, it should return false.
Requirements:
- Use
Math.Absto calculate the differences between rows and columns. - Ensure the move isn't to the same square.
- Verify that one axis changed by 2 and the other axis changed by 1.
There are no comments for now.