Search Algorithms - Local Search: Ntroduction To Rtificial Ntelligence Ssignment UE ATE Ednesday AY TH PM
Search Algorithms - Local Search: Ntroduction To Rtificial Ntelligence Ssignment UE ATE Ednesday AY TH PM
1 I NTRODUCTION
In this assignment you will create an agent to solve the n queens puzzle. The eight queens
puzzle is the problem of placing eight chess queens on an 8 × 8 chessboard so that no two
queens threaten each other; thus, a solution requires that no two queens share the same row,
column, or diagonal. For example one possible solution is:
The eight queens puzzle is an example of the more general n queens problem of placing n
non-attacking queens on an n × n chessboard, for which solutions exist for all natural num-
bers n with the exception of n = 2 and n = 3.
1
2 I MPLEMENTATION
T HE BOARD
We are going to think of the board as an n × n matrix with the top left position having coor-
dinates [1, 1] and the bottom right position having the coordinates [8, 8]. Notice that for our
given problem there should always be only a single queen in any given column in any valid
configuration. We therefore just need a list of length n to represent an n × n board with n
queens on it. For example the board shown above will have the following list representation
board = [4, 6, 8, 2, 7, 1, 3, 5]
so if I wanted the position of the queen in the 4 column I would just get the value board[3].
Notice the that function should be able to figure out the size of the board from the size of the
given list. So if it is given a larger list it will print a larger board. For example
2
TASK 2 - G ENERATE R ANDOM B OARD
You are to write a function called genRandomBoard that takes an integer n as input and gen-
erates a list that represents a board of size n × n with n queens placed randomly (one per
column) on the board.
>>> genRandomBoard(8)
[7, 8, 7, 6, 8, 7, 3, 5]
>>> genRandomBoard(10)
[4, 10, 3, 9, 4, 10, 1, 4, 8, 2]
Hint: To check if they diagonally threaten each other you just have to check whether the
absolute difference of the x coordinated of the position equal the absolute difference of the y
coordinates.
3
TASK 4 - C ALCULATING H EURISTIC C OST
This function determins a herristic cost estimate for a given board. We define this to be the
number of pairs of queens that are threatening each other. You can iterate over all the given
queen positions and see how many of the other queens are threatening it using the function
you wrote in Task 3. Once you add up all the threats divide it by 2 (we need pairs) to get the
answer.
>>> printBoard([1,1,1,1,1,1,1,1])
1 2 3 4 5 6 7 8
_ _ _ _ _ _ _ _
1 |W|W|W|W|W|W|W|W|
2 |_|_|_|_|_|_|_|_|
3 |_|_|_|_|_|_|_|_|
4 |_|_|_|_|_|_|_|_|
5 |_|_|_|_|_|_|_|_|
6 |_|_|_|_|_|_|_|_|
7 |_|_|_|_|_|_|_|_|
8 |_|_|_|_|_|_|_|_|
>>> hCostOfBoard([1,1,1,1,1,1,1,1])
28
>>> hCostOfBoard([4, 6, 8, 2, 7, 1, 3, 5])
0
Note the board in the second function call is the one given in the introduction.
4
obtained by moving a queen within its column. For example if we moved the queen in col-
umn 2 to row 1 the heuristic cost of the new configuration would be 12. Your task is to write a
function called printBoardWithHcost that prints a similar board given a list representing a
board configuration
>>> printBoardWithHcost([5,6,7,4,5,6,7,6])
__ __ __ __ __ __ __ __
|18|12|14|13|13|12|14|14|
|14|16|13|15|12|14|12|16|
|14|12|18|13|15|12|14|14|
|15|14|14| W|13|16|13|16|
| W|14|17|15| W|14|16|16|
|17| W|16|18|15| W|15| W|
|18|14| W|15|15|14| W|16|
|14|14|13|17|12|14|12|18|
Algorithm: Iterate through the board in a row-wise manner. So you would consider the posi-
tions in the following order [1,1], [1,2], [1,3],...[2,1],[2,2],...... Each time you
consider a position change the board so that the queen in the current column is in the current
row instead of the one given as input. For example given the input list [5,6,7,4,5,6,7,6]
if we are considering the position [1,2] we would make the element in 2nd position in the
given list equal to 1, so that we would get the list [5,1,7,4,5,6,7,6]. Calculate the heuristic
cost of the board (using hCostOfBoard function) and print that cost. If the queen is already
in the given row then you just print ’W’.
Now that we have decided on a heuristic it is time to solve the puzzle. Remember that in BFS,
DFS and A* we searched the whole search tree systematically. One reason for doing this was
that we need the path to the node as part of the solution. In our current problem we just need
a particular solution without caring how we get there. So our algorithm is going to start with
a random board find all the neighbours with heuristic value less than the current value and
move randomly to one of these neighbours. We keep doing this untill we reach the required
heuristic value or we get stuck. If we get stuck we start with another random board.
5
TASK 6 - N EIGHBORS WITH LOWEST HEURISTIC
To implement this function you have to write a function callled lowestCostNeighbours that
takes a board configuration as input and returns the current heuristic and a list of neigh-
bours with heuristics less than the current one. For example let us start with the board
[5,6,7,4,5,6,7,6]
The lowestCostNeighbours should return the list of lowest heuristic neighbours along with
the current heuristic.
As you can see from the figure all these represent the neighbors with the heuristic cost of 12.
TASK 7 - L OCALSEARCH
Now we come to our final function that combines everything. Write a function called localsearch
that takes a board as input and tries to find a solution. The algorithm implemented is as fol-
lows:
while true
6
1. Find the lowest cost neighbours
2. If the current heuristic value is 0 or there are no lower cost neighbors
return the current board
3. chose a random value from the neighbors
4. change the board according to the new choice
>>> localsearch([5,6,7,4,5,6,7,6])
current board:
__ __ __ __ __ __ __ __
|18|12|14|13|13|12|14|14|
|14|16|13|15|12|14|12|16|
|14|12|18|13|15|12|14|14|
|15|14|14| W|13|16|13|16|
| W|14|17|15| W|14|16|16|
|17| W|16|18|15| W|15| W|
|18|14| W|15|15|14| W|16|
|14|14|13|17|12|14|12|18|
possible neighbors:
[17, [[1, 2], [1, 6], [2, 5], [2, 7], [3, 2], [3, 6], [8, 5], [8, 7]]]
random neighbor chosen: [1, 2]
current board:
__ __ __ __ __ __ __ __
|15| W|11|10|09|09|09|11|
|11|16|10|11|07|09|07|12|
|10|12|14|10|09|08|09|10|
|11|14|10| W|09|12|08|12|
| W|14|12|11| W|11|11|12|
|12|17|11|13|09| W|10| W|
|13|14| W|11|10|10| W|13|
|10|14|09|12|07|10|07|14|
possible neighbors:
[12, [[2, 5], [2, 7], [8, 5], [8, 7]]]
random neighbor chosen: [8, 7]
current board:
__ __ __ __ __ __ __ __
|09| W|07|06|05|05|09|07|
7
|07|10|06|07|03|05|07|08|
|05|08|09|06|05|04|09|06|
|06|09|07| W|05|08|08|08|
| W|09|08|08| W|07|11|08|
|07|12|07|09|06| W|10| W|
|07|08| W|06|05|06|12|09|
|06|10|06|09|04|06| W|10|
possible neighbors:
[7, [[2, 5]]]
random neighbor chosen: [2, 5]
current board:
__ __ __ __ __ __ __ __
|05| W|04|04|05|03|05|03|
|05|06|04|05| W|03|04|04|
|02|04|05|04|05|02|04|02|
|03|05|05| W|05|04|05|04|
| W|05|04|04|07|03|06|04|
|05|08|04|05|06| W|06| W|
|04|04| W|03|05|03|07|05|
|03|05|03|06|04|03| W|05|
possible neighbors:
[3, [[3, 1], [3, 6], [3, 8]]]
random neighbor chosen: [3, 1]
current board:
__ __ __ __ __ __ __ __
|05| W|05|03|03|02|04|02|
|05|06|04|03| W|02|03|03|
| W|04|05|04|05|02|04|02|
|03|04|05| W|04|03|04|03|
|03|03|04|02|05|01|04|02|
|05|06|04|05|05| W|05| W|
|04|03| W|02|05|02|06|04|
|03|04|03|04|03|03| W|04|
possible neighbors:
[2, [[5, 6]]]
random neighbor chosen: [5, 6]
8
current board:
__ __ __ __ __ __ __ __
|03| W|04|03|02|02|03|02|
|04|03|04|03| W|02|02|03|
| W|02|03|05|04|02|03|03|
|02|02|04| W|04|03|04|02|
|03|02|04|03|04| W|03|03|
|03|03|02|04|04|02|04| W|
|03|01| W|03|03|02|04|05|
|02|02|03|03|02|03| W|03|
possible neighbors:
[1, []]
We have reached a dead end!
As you can see we have reached a dead end. This will occassionally occur. The solution is to
randomly start with a new board. Write a function called findLocalSolution as follows
def findLocalSolution():
con = 1
while con:
rval = localsearch(genRandomBoard(8))
if rval[0] == 0:
con = 0
return rval
When we run this we usually find a solution in a few tries. Here is a sample run:
current board:
__ __ __ __ __ __ __ __
|08|06|06|06|05|07|07|06|
|09|07|05|07|06|07|07|06|
|10|11|10|09| W| W|09| W|
|09|09| W| W|07|09|09|07|
| W|08|08|09|07|07|07|07|
|08|09|06|06|07|06|05|06|
|10|07|07|06|04|07|06|06|
|10| W|08|08|06|07| W|08|
possible neighbors:
[7, [[7, 5]]]
random neighbor chosen: [7, 5]
9
current board:
__ __ __ __ __ __ __ __
|05|03|02|04|05|05|03|04|
|06|04|02|04|06|04|04|04|
|07|07|06|06|07| W|05| W|
|06|07| W| W|07|06|06|06|
| W|05|05|07|07|05|04|05|
|05|05|03|05|07|05|02|03|
|07|05|05|05| W|06|04|05|
|07| W|05|07|06|06| W|06|
possible neighbors:
[4, [[1, 3], [2, 3], [6, 7]]]
random neighbor chosen: [6, 7]
current board:
__ __ __ __ __ __ __ __
|03|03|01|02|03|03|03|02|
|03|03|02|02|04|02|04|02|
|05|05|05|05|05| W|05| W|
|04|06| W| W|06|04|06|04|
| W|04|04|04|05|04|04|04|
|04|05|03|04|05|04| W|02|
|05|04|04|03| W|04|04|03|
|04| W|03|04|04|03|04|03|
possible neighbors:
[2, [[1, 3]]]
random neighbor chosen: [1, 3]
current board:
__ __ __ __ __ __ __ __
|03|03| W|03|03|02|03|02|
|01|03|02|03|02|01|03|01|
|05|03|05|04|05| W|04| W|
|02|04|02| W|04|03|04|02|
| W|02|04|03|04|03|04|03|
|02|04|03|04|03|03| W|02|
|04|03|04|03| W|02|03|02|
|03| W|03|04|03|02|02|02|
10
possible neighbors:
[1, []]
We have reached a dead end!
current board:
__ __ __ __ __ __ __ __
|08|08|08|09|07|04|06|06|
|07|11|08| W|08|06|06|09|
|06|09|09|07|09|05|07|08|
| W|12|09|13|09| W| W|09|
|09|10|08|08| W|07|08|08|
|08| W|08|10|09|07|06|09|
|07|09|09|10|06|04|07|06|
|08|12| W|10|09|06|07| W|
possible neighbors:
[8, [[1, 6], [7, 6]]]
random neighbor chosen: [1, 6]
current board:
__ __ __ __ __ __ __ __
|06|05|04|07|05| W|04|03|
|04|07|04| W|06|06|04|04|
|03|05|05|05|05|05|03|05|
| W|07|05|09|05|08| W|04|
|06|07|04|05| W|07|04|04|
|06| W|04|06|06|07|03|04|
|04|05|04|07|03|04|04|02|
|05|07| W|07|06|06|04| W|
possible neighbors:
[4, [[7, 8]]]
random neighbor chosen: [7, 8]
current board:
__ __ __ __ __ __ __ __
|03|04|03|05|04| W|02|03|
|02|04|04| W|05|04|02|04|
|01|03|03|04|04|03|01|05|
| W|05|04|06|05|06| W|04|
|04|05|03|03| W|06|02|04|
11
|04| W|03|04|05|04|02|04|
|03|04|04|06|03|03|02| W|
|02|04| W|04|04|03|02|04|
possible neighbors:
[2, [[3, 1], [3, 7]]]
random neighbor chosen: [3, 1]
current board:
__ __ __ __ __ __ __ __
|03|03|03|03|03| W|02|02|
|02|04|02| W|04|03|02|03|
| W|02|03|04|04|03|02|05|
|02|04|02|04|03|04| W|02|
|04|03|03|02| W|05|02|03|
|04| W|01|04|04|03|02|03|
|03|03|03|04|03|02|02| W|
|02|03| W|03|02|03|02|03|
possible neighbors:
[1, []]
We have reached a dead end!
current board:
__ __ __ __ __ __ __ __
| W|07|07|06|07| W|05|08|
|06|07|05|05| W|05|07|06|
|04|06|05|05|05|06|05|05|
|06|06|08|05|07|06|05| W|
|06|10|06| W|08|05| W|07|
|07|06| W|05|06|07|04|06|
|05|07|05|04|06|04|04|04|
|07| W|05|06|06|04|05|06|
possible neighbors:
[5, [[3, 1], [6, 7], [7, 4], [7, 6], [7, 7], [7, 8], [8, 6]]]
random neighbor chosen: [3, 1]
current board:
__ __ __ __ __ __ __ __
|05|05|06|04|05| W|03|06|
12
|06|06|04|04| W|05|06|05|
| W|06|04|05|05|07|05|05|
|06|06|07|03|06|06|04| W|
|06|09|06| W|06|05| W|06|
|07|05| W|05|05|06|03|05|
|05|06|04|03|06|04|02|03|
|07| W|04|05|05|05|04|04|
possible neighbors:
[4, [[7, 7]]]
random neighbor chosen: [7, 7]
current board:
__ __ __ __ __ __ __ __
|04|03|03|03|03| W|03|05|
|04|05|02|02| W|03|06|04|
| W|04|03|04|02|05|05|04|
|04|04|05|03|04|03|04| W|
|03|06|03| W|04|02|04|04|
|05|03| W|04|03|04|03|04|
|04|05|03|03|04|03| W|03|
|05| W|02|03|03|04|04|04|
possible neighbors:
[2, []]
We have reached a dead end!
current board:
__ __ __ __ __ __ __ __
|06|09|03|06|04|07|08|08|
|08|09|07|06|07|07|08| W|
|06|11|05| W|06|07|08|08|
| W|10| W|10| W|09|09|10|
|06|10|04|08|06|07|06|08|
|08| W|06|07|07|07|10|09|
|08|10|07|08|06| W| W|11|
|06|08|03|06|06|06|08|08|
possible neighbors:
[7, [[1, 3], [8, 3]]]
random neighbor chosen: [8, 3]
13
current board:
__ __ __ __ __ __ __ __
|03|05|03|03|01|03|04|04|
|04|05|07|03|03|04|04| W|
|03|06|05| W|03|04|04|05|
| W|05|07|06| W|05|05|05|
|03|05|04|04|03|05|02|04|
|05| W|06|04|04|04|06|05|
|05|07|07|06|03| W| W|07|
|04|05| W|04|04|04|04|05|
possible neighbors:
[3, [[1, 5]]]
random neighbor chosen: [1, 5]
current board:
__ __ __ __ __ __ __ __
|03|03|02|03| W|02|03|02|
|03|03|04|03|03|03|01| W|
|02|04|04| W|03|01|03|03|
| W|03|04|04|03|02|02|03|
|03|03|02|02|03|02|00|02|
|04| W|03|03|04|02|03|03|
|04|04|05|05|03| W| W|04|
|02|03| W|03|04|02|02|03|
possible neighbors:
[1, [[5, 7]]]
random neighbor chosen: [5, 7]
current board:
__ __ __ __ __ __ __ __
|01|02|02|02| W|02|03|01|
|02|01|03|03|02|03|01| W|
|01|03|02| W|03|01|03|02|
| W|02|03|02|02|03|02|03|
|03|03|02|02|02|03| W|02|
|03| W|02|02|03|02|03|02|
|02|02|03|03|02| W|01|02|
|01|02| W|03|03|01|02|01|
possible neighbors:
14
[0, []]
We have found a solution!
During this run we had to generate 4 random boards before we got a solution.
15