You are on page 1of 11

IT375 - Artificial Intelligence 20IT116

Practical – 2

1. Analyze and Implement 8-puzzle Problem.

Analysis:
Given a 3×3 board with 8 tiles (every tile has one number from 1 to 8) and one empty space. The
objective is to place the numbers on tiles to match the final configuration using the empty space.
We can slide four adjacent (left, right, above, and below) tiles into the empty space.

When is the Problem unsolvable?


It is not possible to solve an instance of 8 puzzle if number of inversions is odd in the input state.

Here, a pair of tiles form an inversion if the values on tiles are in reverse order of their
appearance in goal state.

Approaches to solve the problem:

2 brute force approaches to this problem are discussed here.

i. BFS:

This approach will find the goal state after sliding the empty space maximum 4 times in
whichever direction possible.
The steps to solve the problem using BFS:

1. First traverse the initial matrix to find the empty space.


2. Then push the matrix into a queue to explore all the possibilities from that state.
3. Try to move the empty space in all the directions and push the changed matrix into the
queue to explore it further.
4. Then check if the current matrix being explored is equal to the goal state, if it is return
true else explore it further.
5. Also keep track of the already explored states to not explore any redundant states and
avoid infinite loops.
6. If none of the states matched the goal state then a solution is not possible from the current
state, so return false.

Implementation using BFS:

#include<bits/stdc++.h>
using namespace std;
int main(){

1
IT375 - Artificial Intelligence 20IT116

#ifndef ONLINE_JUDGE
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
#endif
vector<vector<char>> initState = {
{'1', '2', '3'},
{'4', '6', ' '},
{'5', '8', '7'}
};
vector<vector<char>> goalState = {
{'1', '2', '3'},
{'5', '6', '7'},
{'4', '8', ' '}
};
queue<vector<vector<char>>> states;
states.push(initState);
set<vector<vector<char>>> visited;
while(!states.empty()){
vector<vector<char>> curr = states.front();
states.pop();
visited.insert(curr);
bool flag = true;
for(int i = 0; i < 3; i++){
for(int j = 0; j < 3; j++){
if(curr[i][j] != goalState[i][j]){
flag = false;
break;
}
}
}
if(flag) cout << "Found!\n"; break;
int x, y;
for(int i = 0; i < 3; i++){
for(int j = 0; j < 3; j++){
if(curr[i][j] == ' '){
x = i; y = j;
break;
}
}
}
if(x - 1 >= 0){
swap(curr[x - 1][y], curr[x][y]);
if(visited.find(curr) == visited.end()){
states.push(curr);

2
IT375 - Artificial Intelligence 20IT116

}
swap(curr[x - 1][y], curr[x][y]);
}
if(x + 1 < 3){
swap(curr[x + 1][y], curr[x][y]);
if(visited.find(curr) == visited.end()){
states.push(curr);
}
swap(curr[x + 1][y], curr[x][y]);
}
if(y - 1 >= 0){
swap(curr[x][y - 1], curr[x][y]);
if(visited.find(curr) == visited.end()){
states.push(curr);
}
swap(curr[x][y - 1], curr[x][y]);
}
if(y + 1 < 3){
swap(curr[x][y + 1], curr[x][y]);
if(visited.find(curr) == visited.end()){
states.push(curr);
}
swap(curr[x][y + 1], curr[x][y]);
}
}
cout << "Not Found!\n";
}

ii. DFS:

Steps to solve the problem using DFS:

1. First find out the empty space in the given initial matrix.
2. Then try to slide that space in any of the directions
3. After a slide is performed, start exploring that state till it’s depth(Here till it’s depth
means either we have reached the goal state or an already explored state)
4. Keep exploring the states till we either reach the goal state or run out of states to explore.’
5. Like BFS, here also we need to keep track of all the states that were explored.

Implementation using DFS:

#include <bits/stdc++.h>
using namespace std;

3
IT375 - Artificial Intelligence 20IT116

bool DFS(vector<vector<char>>& initState, vector<vector<char>>& goalState,


set<vector<vector<char>>>& visited){
for(auto j:initState){
for(auto i:j){
cout << i << " ";
}
cout << "\n";
}
cout << "\n";
visited.insert(initState);
bool flag = true;
for(int i = 0; i < 3; i++){
for(int j = 0; j < 3; j++){
if(initState[i][j] != goalState[i][j]){
flag = false;
break;
}
}
}
if(flag) return true;
int x, y;
for(int i = 0; i < 3; i++){
for(int j = 0; j < 3; j++){
if(initState[i][j] == ' '){
x = i; y = j;
break;
}
}
}
if(x - 1 >= 0){
swap(initState[x - 1][y], initState[x][y]);
if(visited.find(initState) == visited.end()){
if(DFS(initState, goalState, visited)) return true;
}
swap(initState[x - 1][y], initState[x][y]);
}
if(x + 1 < 3){
swap(initState[x + 1][y], initState[x][y]);
if(visited.find(initState) == visited.end()){
if(DFS(initState, goalState, visited)) return true;
}
swap(initState[x + 1][y], initState[x][y]);
}
if(y - 1 >= 0){

4
IT375 - Artificial Intelligence 20IT116

swap(initState[x][y - 1], initState[x][y]);


if(visited.find(initState) == visited.end()){
if(DFS(initState, goalState, visited)) return true;
}
swap(initState[x][y - 1], initState[x][y]);
}
if(y + 1 < 3){
swap(initState[x][y + 1], initState[x][y]);
if(visited.find(initState) == visited.end()){
if(DFS(initState, goalState, visited)) return true;
}
swap(initState[x][y + 1], initState[x][y]);
}
return false;
}
int main(){
#ifndef ONLINE_JUDGE
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
#endif
vector<vector<char>> initState = {
{'1', '2', '3'},
{'4', '6', ' '},
{'5', '8', '7'}
};
vector<vector<char>> goalState = {
{'1', '2', '3'},
{'5', '6', '7'},
{'4', '8', ' '}
};
set<vector<vector<char>>> visited;
if(DFS(initState, goalState, visited)) cout << "Possible!\n";
else cout << "Not Possible!\n";
}

5
IT375 - Artificial Intelligence 20IT116

2. Analyze and Implement water jug problem.

Analysis:
You are given two jugs, one of m litre and another of n litre capacity. Both the jugs are initially
empty. The jugs do not have any intermediate markings and labelling for measuring smaller
quantities. You can be asked to measure d litres of water, such that d is less than n.

First, fill the n litre jug and empty all its contents in the “m” litre jug. As soon as the n litre jug
becomes vacant, refill it. As soon as the “m” litre jug becomes full, empty it. Repeat the first
three steps until either the n litre jug or the m litre jug, has exactly d litres of water in it.

The solution written using Breadth-First Search is considered to be one of the most optimum
solutions.

For this Problem, a DFS solution is impossible becuause: -


DFS is also known as Depth-First Search sometimes turns out to be an incomplete algorithm and
may end up abruptly, giving a Non-Optimal Solution. The solution generated by the depth-first
search may be incomplete as this algorithm goes on to the deepest possible point in the first path.
In case, that first path leads to infinity, the algorithm will turn into an infinite loop and will never
give any correct solution.

BFS solution of the Problem:

1. Define a state space that contains all possible configurations of the water jugs and
even some of the unreachable ones.
2. Specify one or multiple states within that space that describe all the possible
situations from which we can initiate the problem-solving process. These states are
referred to as the initial states.
3. Specify one or more states which are regarded as the acceptable solutions to the
problem. These states are known as goal states.
4. Specify a set of rules also known as predictions that describe the actions (operators)
allowed and a well-defined control strategy for aligning the order of application of
these predictions.

Implementation:

#include <bits/stdc++.h>
using namespace std;
typedef pair<int, int> pii;
void printpath(map<pii, pii> mp, pii u)
{

6
IT375 - Artificial Intelligence 20IT116

if (u.first == 0 && u.second == 0) {


cout << 0 << " " << 0 << endl;
return;
}
printpath(mp, mp[u]);
cout << u.first << " " << u.second << endl;
}
void BFS(int a, int b, int target)
{
map<pii, int> m;
bool isSolvable = false;
map<pii, pii> mp;

queue<pii> q;

q.push({0, 0});
while (!q.empty()) {
auto u = q.front();
q.pop();
if(m[u] == 1)
continue;
if((u.first > a || u.second > b || u.first < 0 || u.second < 0))
continue;
m[{u.first, u.second}] = 1;
if(u.first == target || u.second == target){
isSolvable = true;
printpath(mp, u);
if(u.first == target){
if(u.second != 0)
cout << u.first << " " << 0 << endl;
}
else{
if(u.first != 0)
cout << 0 << " " << u.second << endl;
}
return;
}
if(m[{u.first, b}] != 1){
q.push({u.first, b});
mp[{u.first, b}] = u;
}
if(m[{a, u.second}] != 1){
q.push({a, u.second});
mp[{a, u.second}] = u;

7
IT375 - Artificial Intelligence 20IT116

}
int d = b - u.second;
if(u.first >= d){
int c = u.first - d;
if(m[{c, b}] != 1){
q.push({c, b});
mp[{c, b}] = u;
}
}
else{
int c = u.first + u.second;
if(m[{0, c}] != 1){
q.push({0, c});
mp[{0, c}] = u;
}
}
d = a - u.first;
if(u.second >= d){
int c = u.second - d;
if(m[{a, c}] != 1){
q.push({a, c});
mp[{a, c}] = u;
}
}
else{
int c = u.first + u.second;
if(m[{c, 0}] != 1){
q.push({c, 0});
mp[{c, 0}] = u;
}
}
if(m[{u.first, 0}] != 1){
q.push({u.first, 0});
mp[{u.first, 0}] = u;
}
if(m[{0, u.second}] != 1){
q.push({0, u.second});
mp[{0, u.second}] = u;
}
}
if(!isSolvable)
cout << "No solution";
}

8
IT375 - Artificial Intelligence 20IT116

int main()
{
#ifndef ONLINE_JUDGE
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
#endif
int jug1, jug2, target;
cin >> jug1;
cin >> jug2;
cin >> target;
cout << "Path from initial state to solution state ::\n";
BFS(jug1, jug2, target);
return 0;
}

9
IT375 - Artificial Intelligence 20IT116

3. Analyze and Implement N-Queens Problem

Analysis:

Given an N x N chessboard and N queens. We need to determine all the possible states of the
chessboard which has N queens and no queens are attacking each other.

Backtracking/DFS Approach:

1. Put the queens column by column, to place a queen on a cell first check if that cell is
being attacked by another queen. If not, place the queen on that cell and then explore all
the possibilities.
2. After all the possibilities with the queen on that cell is explored, remove the queen from
that cell and try putting it on another cell of the same column and then repeat the same
process.
3. After the whole traversal is over, we will have our all possible states.

Implementation:

#include<bits/stdc++.h>
using namespace std;
class Solution {
public:
bool safe(int row, int col, vector<string> board, int n){
int duprow = row;
int dupcol = col;
while(row >= 0 && col >= 0){
if(board[row][col] == 'Q') return false;
row--;
col--;
}
row = duprow;
col = dupcol;
while(col >= 0){
if(board[row][col] == 'Q') return false;
col--;
}
col = dupcol;
while(row < n && col >= 0){
if(board[row][col] == 'Q') return false;
row++;
col--;
}

10
IT375 - Artificial Intelligence 20IT116

return true;
}
void solve(int col,vector<string> board, vector<vector<string>>& ans, int n){
if(col == n){
ans.push_back(board);
return;
}
for(int row = 0; row < n; row++){
if(safe(row, col, board, n)){
board[row][col] = 'Q';
solve(col + 1, board, ans, n);
board[row][col] = '.';
}
}
}
vector<vector<string>> solveNQueens(int n) {
vector<vector<string>> ans;
vector<string> board(n);
string s(n, '.');
for(int i = 0; i < n; i++){
board[i] = s;
}
solve(0, board, ans, n);
return ans;
}
};
int main(){
#ifndef ONLINE_JUDGE
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
#endif
int n;
cin >> n;
Solution obj;
vector<vector<string>> ans = obj.solveNQueens(n);
for(auto& j:ans){
for(auto i:j){
cout << i << "\n";
}
cout << "\n";
}
}

11

You might also like