Exercism - Queen Attack
This post shows you how to get Queen Attack exercise of Exercism.
Preparation
Before we click on our next exercise, let’s see what concepts of DART we need to consider

So we need to use the following concepts.
Classes and Constructors
Classes define blueprints for creating objects. Constructors initialize objects with data and can include validation.
class Queen {
final int row;
final int column;
Queen(this.row, this.column);
}
void main() {
// Create a queen at position (3, 2)
Queen queen = Queen(3, 2);
print(queen.row); // 3
print(queen.column); // 2
}
Final Fields
Final fields can only be assigned once (typically in the constructor) and cannot be changed afterward. They’re perfect for immutable data like chess piece positions.
class Queen {
final int row; // Cannot be changed after initialization
final int column; // Cannot be changed after initialization
Queen(this.row, this.column);
}
void main() {
Queen queen = Queen(3, 2);
// queen.row = 5; // Error: Cannot assign to final variable
// queen.column = 4; // Error: Cannot assign to final variable
}
Assert Statements
Assert statements validate conditions during development. If the condition is false, an AssertionError is thrown. They’re useful for input validation in constructors.
class Queen {
final int row;
final int column;
Queen(this.row, this.column)
: assert(row >= 0, 'row not positive'),
assert(row < 8, 'row not on board'),
assert(column >= 0, 'column not positive'),
assert(column < 8, 'column not on board');
}
void main() {
// Valid queen
Queen q1 = Queen(3, 2); // OK
// Invalid queen (will throw AssertionError in debug mode)
// Queen q2 = Queen(-1, 2); // AssertionError: row not positive
// Queen q3 = Queen(3, 8); // AssertionError: column not on board
}
Boolean Methods
Methods can return boolean values to indicate whether a condition is true or false. They’re perfect for checking relationships between objects.
class Queen {
final int row;
final int column;
Queen(this.row, this.column);
bool canAttack(Queen other) {
// Check if queens can attack each other
return row == other.row || column == other.column;
}
}
void main() {
Queen q1 = Queen(3, 2);
Queen q2 = Queen(3, 5); // Same row
Queen q3 = Queen(1, 2); // Same column
print(q1.canAttack(q2)); // true (same row)
print(q1.canAttack(q3)); // true (same column)
}
Helper Methods (Private Methods)
Helper methods (often private methods starting with _) encapsulate reusable logic, making code more organized and maintainable.
class Queen {
final int row;
final int column;
Queen(this.row, this.column);
// Public method
bool canAttack(Queen other) {
return _onSameRow(other) || _onSameColumn(other);
}
// Private helper method
bool _onSameRow(Queen other) {
return row == other.row;
}
// Private helper method
bool _onSameColumn(Queen other) {
return column == other.column;
}
}
Logical OR Operator
The logical OR operator (||) returns true if at least one of the conditions is true. It’s used to check multiple attack conditions.
void main() {
bool sameRow = true;
bool sameColumn = false;
bool sameDiagonal = false;
// OR operator: true if any condition is true
bool canAttack = sameRow || sameColumn || sameDiagonal;
print(canAttack); // true (because sameRow is true)
// All false
bool canAttack2 = false || false || false;
print(canAttack2); // false
}
Comparison Operators
Comparison operators (==) compare values and return boolean results. They’re essential for checking if queens share rows, columns, or diagonals.
void main() {
int row1 = 3, row2 = 3;
int col1 = 2, col2 = 5;
// Check if same row
bool sameRow = row1 == row2;
print(sameRow); // true
// Check if same column
bool sameColumn = col1 == col2;
print(sameColumn); // false
// Use in methods
bool checkRow(int r1, int r2) => r1 == r2;
print(checkRow(3, 3)); // true
}
Absolute Value
The abs() method returns the absolute value of a number (removes the negative sign). It’s essential for calculating diagonal distances regardless of direction.
void main() {
int diff1 = 5 - 2;
int diff2 = 2 - 5;
// Without abs: different signs
print(diff1); // 3
print(diff2); // -3
// With abs: same value
print(diff1.abs()); // 3
print(diff2.abs()); // 3
// Use for diagonal check
int rowDiff = (3 - 1).abs(); // 2
int colDiff = (5 - 3).abs(); // 2
bool sameDiagonal = rowDiff == colDiff;
print(sameDiagonal); // true
}
Mathematical Operations
Mathematical operations like subtraction are used to calculate differences between positions. These differences help determine if pieces are on the same diagonal.
void main() {
int row1 = 3, row2 = 1;
int col1 = 2, col2 = 4;
// Calculate differences
int rowDiff = row1 - row2; // 3 - 1 = 2
int colDiff = col1 - col2; // 2 - 4 = -2
// Use absolute value for distance
int rowDistance = (row1 - row2).abs(); // 2
int colDistance = (col1 - col2).abs(); // 2
// Check if on same diagonal
bool sameDiagonal = rowDistance == colDistance;
print(sameDiagonal); // true
}
Chess Board Coordinates
Chess boards are typically represented as 8x8 grids with rows and columns indexed from 0 to 7. Understanding zero-based indexing is essential.
void main() {
// Chess board: 8 rows (0-7), 8 columns (0-7)
// Position c5 in chess notation:
// - Column c = 2 (a=0, b=1, c=2, ...)
// - Row 5 = 3 (rows are 1-indexed in chess, so 5 = index 3)
int row = 3; // Row 3 (0-indexed)
int column = 2; // Column 2 (c)
// Validate position
bool valid = row >= 0 && row < 8 && column >= 0 && column < 8;
print(valid); // true
}
Introduction
Given the position of two queens on a chess board, indicate whether or not they are positioned so that they can attack each other.
In the game of chess, a queen can attack pieces which are on the same row, column, or diagonal.
A chessboard can be represented by an 8 by 8 array.
So if you are told the white queen is at c5 (zero-indexed at column 2, row 3) and the black queen at f2 (zero-indexed at column 5, row 6), then you know that the set-up is like so:
A chess board with two queens. Arrows emanating from the queen at c5 indicate possible directions of capture along file, rank and diagonal.
You are also able to answer whether the queens can attack each other. In this case, that answer would be yes, they can, because both pieces share a diagonal.
Credit
The chessboard image was made by habere-et-dispertire using LaTeX and the chessboard package by Ulrike Fischer.
How can queens attack each other?
Queens can attack each other if they are on:
-
Same row: Both queens have the same row coordinate
- Example: Queen at (3, 2) and Queen at (3, 5) → same row 3
-
Same column: Both queens have the same column coordinate
- Example: Queen at (3, 2) and Queen at (1, 2) → same column 2
-
Same diagonal: The absolute difference in rows equals the absolute difference in columns
- Example: Queen at (3, 2) and Queen at (5, 4) → row diff = 2, col diff = 2 → same diagonal
- Example: Queen at (3, 2) and Queen at (1, 4) → row diff = 2, col diff = 2 → same diagonal
The key insight for diagonal detection is that if two points are on the same diagonal, the horizontal distance equals the vertical distance (in absolute terms).
For example, with queens at c5 (row 3, column 2) and f2 (row 6, column 5):
- Row difference: |3 - 6| = 3
- Column difference: |2 - 5| = 3
- Since 3 == 3, they’re on the same diagonal → Can attack!
Solution
class Queen {
final int row;
final int column;
Queen(this.row, this.column)
: assert(row >= 0, 'row not positive'),
assert(row < 8, 'row not on board'),
assert(column >= 0, 'column not positive'),
assert(column < 8, 'column not on board');
bool canAttack(Queen other) {
return _onSameRow(other) ||
_onSameColumn(other) ||
_onSameDiagonal(other);
}
bool _onSameRow(Queen other) => row == other.row;
bool _onSameColumn(Queen other) => column == other.column;
bool _onSameDiagonal(Queen other) {
final rowDiff = (row - other.row).abs();
final colDiff = (column - other.column).abs();
return rowDiff == colDiff;
}
}
Let’s break down the solution:
-
class Queen- Represents a queen on a chess board:- Stores the queen’s position as row and column coordinates
-
final int row- Row coordinate (0-7):- Final means it cannot be changed after initialization
- Represents the row position on an 8x8 board
-
final int column- Column coordinate (0-7):- Final means it cannot be changed after initialization
- Represents the column position on an 8x8 board
-
Queen(this.row, this.column)- Constructor:- Takes row and column as parameters
- Initializes the final fields
-
Assert statements - Input validation:
assert(row >= 0, 'row not positive'): Ensures row is non-negativeassert(row < 8, 'row not on board'): Ensures row is within board bounds (0-7)assert(column >= 0, 'column not positive'): Ensures column is non-negativeassert(column < 8, 'column not on board'): Ensures column is within board bounds (0-7)- These assertions throw
AssertionErrorin debug mode if conditions fail
-
bool canAttack(Queen other)- Main method:- Returns
trueif this queen can attack the other queen - Uses logical OR (
||) to check three conditions:- Same row, OR
- Same column, OR
- Same diagonal
- Returns
trueif any condition is true
- Returns
-
bool _onSameRow(Queen other)- Helper method for row check:row == other.row: Compares this queen’s row with the other queen’s row- Returns
trueif they’re equal (same row) - Private method (starts with
_)
-
bool _onSameColumn(Queen other)- Helper method for column check:column == other.column: Compares this queen’s column with the other queen’s column- Returns
trueif they’re equal (same column) - Private method (starts with
_)
-
bool _onSameDiagonal(Queen other)- Helper method for diagonal check:final rowDiff = (row - other.row).abs(): Calculates absolute row difference- Example: (3, 2) and (5, 4) → |3 - 5| = 2
final colDiff = (column - other.column).abs(): Calculates absolute column difference- Example: (3, 2) and (5, 4) → |2 - 4| = 2
return rowDiff == colDiff: Returnstrueif differences are equal- If row difference equals column difference, they’re on the same diagonal
- Private method (starts with
_)
The solution efficiently checks if two queens can attack each other by verifying three conditions: same row, same column, or same diagonal. The diagonal check uses the mathematical property that points on the same diagonal have equal absolute differences in both coordinates.
A video tutorial for this exercise is coming soon! In the meantime, check out my YouTube channel for more Dart and Flutter tutorials. 😉
Visit My YouTube Channel