Assignement on solving the NQueen using backtracking
In this assignment, you’ll explore how Constraint Satisfaction Problems (CSPs) can be applied to the classic N-Queens problem — a challenge of placing N queens on an N×N chessboard so that none attack each other.
You will implement and evaluate two fundamental approaches:
By the end, you’ll not only solidify your understanding of CSPs and heuristics, but also visualize how these algorithms behave in real time.
Can queens find harmony on the board? That’s your mission. 👑
Here is the Starter code for this project.
Before solving the N-Queens problem, we need a way to verify whether a given board configuration is valid — that is, no two queens are attacking each other.
In this question, your task is to implement the function is_valid(queens)
located in the cps.py
file.
The function should return True
if the current queen positions do not conflict (no queens share the same column, row, or diagonal), and False
otherwise.
You’ll be working with a dictionary where the keys are row indices and the values are column positions of queens. For example:
queens = {
0: 1,
1: 3,
2: 0,
3: 2
}
This represents 4 queens placed on a 4×4 board.
cps.py
is_valid(queens)
We’ve provided a test file with unit tests for this function.
To run only the tests related to is_valid
, use the following command:
pytest -m is_valid
✔️ Make sure your implementation passes all test cases before moving on.
One of the classical approaches to solving the N-Queens problem is using backtracking search. This algorithm attempts to place queens on the board row by row, choosing one column at a time, and backtracks whenever a placement leads to an invalid configuration.
The idea is simple:
This process continues recursively until all queens are successfully placed, or no solution is found.
Implement the function backtracking(board, row=0)
in the file csp.py
. This function should:
is_valid()
method from Question 1 to ensure validity.The board object passed into your function is an instance of the ChessBoard
class. You can use the following methods:
Method | Description |
---|---|
board.place_queen(row, col) | Place a queen at (row, col) |
board.remove_queen(row, col) | Remove a queen from (row, col) |
board.root.update() | Important: Refreshes the board view |
⚠️ Attention: You must call
board.root.update()
after placing or removing a queen to visualize the changes on the board.
To test your implementation on a board of size n
(e.g., 8), use the following command:
python run_solver.py 8 backtracking
This will visually show your backtracking algorithm solving the N-Queens problem on an 8×8 board. You can change the size to any value you like (e.g., 4, 10, 12).
To enhance the efficiency of solving the N-Queens problem, we now move to a constraint propagation technique called forward checking.
Instead of blindly placing queens and then checking validity, forward checking proactively eliminates choices by identifying which squares are no longer available after placing a queen.
To do this, we must compute — at any point in the algorithm — which squares are forbidden (i.e., they are attacked by at least one existing queen).
Implement the function get_forbidden_squares(queens, board_size)
in the file csp.py
.
def get_forbidden_squares(queens, board_size):
...
queens
: a dictionary of {row: col}
where each queen is currently placed.board_size
: the size of the board (N).(row, col)
tuples representing all squares that are under attack by any queen currently on the board.A square is considered forbidden if it shares:
We’ve included a dedicated test suite for this function. Once implemented, run the following command to test only this part:
python test_forbidden.py
Now that you’ve implemented get_forbidden_squares()
, you’re ready to build a smarter N-Queens solver using forward checking.
Unlike simple backtracking, this version will:
get_forbidden_squares()
to identify all attacked positions,This form of constraint propagation helps prune the search space early — making the algorithm significantly faster and more efficient.
Implement the function forward_search(board, row=0)
in the file csp.py
.
get_forbidden_squares()
to determine the current forbidden positions.As with backtracking, you can use:
Method | Description |
---|---|
board.place_queen(row, col) | Place a queen at (row, col) |
board.remove_queen(row, col) | Remove a queen from (row, col) |
board.clear_not_possible() | Clear red markers |
board.mark_not_possible(r,c) | Mark (r,c) as a forbidden (red) square |
board.root.update() | Refreshes the view (call after updates) |
⚠️ Important: Use
board.root.update()
to visualize each step andmark_not_possible()
to highlight forbidden squares on the board.
Run the following command to launch your visual solver with forward checking:
python run_solver.py 8 forward_search
You should see:
🎯 Try experimenting with larger board sizes (e.g., 12, 16) to see how forward checking improves performance.
Sudoku is another Constraint Satisfaction Problem (CSP) where we must assign numbers to a 9×9 grid while ensuring that:
In this question, you will complete a Sudoku solver using Forward Checking by implementing two key functions.
You are given a partially implemented Sudoku solver. The GUI, board setup, and visualization methods have been provided. However, you must complete the two most important CSP methods:
get_possible_values(board, row, col)
This function should return a set of valid numbers that can be placed at (row, col)
without violating Sudoku constraints.
Implementation Details:
soduko_solver.py
):def get_possible_values(board, row, col):
...
Example Usage:
valid_numbers = get_possible_values(board, 2, 4)
print(valid_numbers) # Output: {1, 3, 5, 6, 9} (depends on board state)
solve_with_forward_checking(board)
This function should implement Sudoku solving using Forward Checking:
get_possible_values()
to determine valid numbers for that position.soduko_solver.py
):def solve_with_forward_checking(board):
...
You do not need to worry about:
Your focus is only on implementing these two methods.
Once implemented, run the following command to test your solver:
python sudoku_solver.py
get_possible_values()
function.board[row]
[board[r][col] for r in range(9)]
start_row, start_col = 3 * (row // 3), 3 * (col // 3)
🚀 Challenge: Try solving a 16×16 Sudoku (instead of 9×9) by modifying the board size!
To wrap up the assignment, you’ll implement a local search strategy for solving the N-Queens problem using the powerful Min-Conflicts heuristic.
This approach is particularly effective for high-dimensional boards (N > 100), where traditional backtracking or forward checking would struggle.
Local search starts with a complete but possibly invalid assignment — placing one queen per row, even if there are conflicts. Then, it repeatedly improves the solution by:
This is known as the Min-Conflicts Algorithm.
It’s fast, efficient, and surprisingly effective — even for large boards like 1000×1000.
You will implement the following three functions in the file csp.py
.
count_conflicts(queens, row, col)
This function returns the number of queens that would be attacking a queen if it were placed at position (row, col)
.
Hints:
get_conflicted_rows(queens)
Returns a list of all row indices where the queen is currently in conflict with another queen.
This helps us identify which queen to move during each iteration of local search.
min_conflicts(board, max_steps=1000)
The main solver. It should:
max_steps
, do: board.place_queen(...)
and board.remove_queen(...)
.If a solution is found (no conflicts remain), return True
.
If max_steps
is reached and conflicts still exist, return False
.
Try running your local search algorithm on a large board to see how fast it performs:
python run_solver.py 100 min_conflicts
You should see a solution computed quickly — even for 100×100 boards!
Try increasing N to 200, 500, or even 1000 to explore the scalability of local search.
max_steps
.