1
- #include < bits/stdc++.h>
2
- using namespace std ;
1
+ #include < iostream> // for IO operations
2
+ #include < vector> // for std::vector
3
+ #include < set> // for std::set
4
+ #include < limits> // for std::numeric_limits
5
+
3
6
/* *
4
7
* @file
5
- * @brief Implementation of Iterative deepening Search algorithm
8
+ * @brief Implementation of the Iterative Deepening Search algorithm for the 8-tile puzzle.
6
9
* @author [Sushant Kogurwar](https://github.com/sushskvnitn)
7
10
*/
8
- #define N 3 // Define the size of the tile puzzle (3x3)
11
+
12
+ #define N 3 // /< Define the size of the tile puzzle (3x3)
9
13
10
14
/* *
11
15
* @class Node
12
16
* @brief Represents a state in the 8-tile puzzle.
13
17
*/
14
18
class Node {
15
19
private:
16
- vector<vector<int >> state; // /< Current state of the puzzle
17
- pair<int , int > blankIndex; // /< Index of the blank tile (0)
18
- Node *parent; // /< Parent node for tracing back the solution
19
- int depth; // /< Depth of the current node in the search tree
20
+ std:: vector<std:: vector<int >> state; // /< Current state of the puzzle
21
+ std:: pair<int , int > blankIndex; // /< Index of the blank tile (0)
22
+ Node *parent; // /< Parent node for tracing back the solution
23
+ int depth; // /< Depth of the current node in the search tree
20
24
21
25
/* *
22
26
* @brief Finds the index of the blank tile in the current state.
23
27
* @return Pair of indices (row, column) of the blank tile.
24
28
*/
25
- pair<int , int > findBlankIndex () {
29
+ std:: pair<int , int > findBlankIndex () {
26
30
for (int i = 0 ; i < N; i++) {
27
31
for (int j = 0 ; j < N; j++) {
28
32
if (state[i][j] == 0 ) {
@@ -40,53 +44,31 @@ class Node {
40
44
* @param parent Pointer to the parent node.
41
45
* @param depth Depth of the node.
42
46
*/
43
- Node (const vector<vector<int >> &state, Node *parent, int depth)
47
+ Node (const std:: vector<std:: vector<int >> &state, Node *parent, int depth)
44
48
: state(state), parent(parent), depth(depth) {
45
49
blankIndex = findBlankIndex ();
46
50
}
47
51
48
- vector<vector<int >> getState () const { return state; }
49
- pair<int , int > getBlankIndex () const { return blankIndex; }
52
+ std:: vector<std:: vector<int >> getState () const { return state; }
53
+ std:: pair<int , int > getBlankIndex () const { return blankIndex; }
50
54
int getDepth () const { return depth; }
51
55
};
52
56
53
57
/* *
54
58
* @class Solve8TilePuzzle
55
59
* @brief A class to solve the 8-tile puzzle using Iterative Deepening Search (IDS).
56
- *
57
- * @details
58
- * This class implements a solution for the 8-tile puzzle, where the goal is to
59
- * rearrange the tiles from a given initial state to a specified goal state.
60
- * The algorithm uses Iterative Deepening Search, which combines the benefits of
61
- * depth-first search (space efficiency) and breadth-first search (completeness).
62
- *
63
- * The initial state of the puzzle is provided by the user, and the algorithm
64
- * checks if the puzzle is solvable based on the number of inversions in the array.
65
- * If the puzzle is solvable, it attempts to find the solution using a depth-limited
66
- * search approach, increasing the depth limit iteratively until a solution is found
67
- * or it is confirmed that no solution exists.
68
- *
69
- * The implementation ensures that:
70
- * - The space complexity is efficient, as it avoids storing large states in memory.
71
- * - The time complexity is less than O(n^2) due to the iterative deepening approach.
72
- * - The original array remains unmodified throughout the process.
73
- *
74
- * If the puzzle is not solvable, the algorithm returns a message indicating this.
75
- *
76
- * @note The blank tile is represented by 0 in the puzzle.
77
60
*/
78
-
79
61
class Solve8TilePuzzle {
80
62
public:
81
- vector<vector<int >> initialState, goalState; // /< Initial and goal states
82
- set<vector<vector<int >>> visitedList; // /< Set to track visited states
63
+ std:: vector<std:: vector<int >> initialState, goalState; // /< Initial and goal states
64
+ std:: set<std:: vector<std:: vector<int >>> visitedList; // /< Set to track visited states
83
65
84
66
/* *
85
67
* @brief Constructor for Solve8TilePuzzle class.
86
68
* @param initialState Initial state of the puzzle.
87
69
* @param goalState Goal state of the puzzle.
88
70
*/
89
- Solve8TilePuzzle (const vector<vector<int >> &initialState, const vector<vector<int >> &goalState)
71
+ Solve8TilePuzzle (const std:: vector<std:: vector<int >> &initialState, const std:: vector<std:: vector<int >> &goalState)
90
72
: initialState(initialState), goalState(goalState) {}
91
73
92
74
bool boundsOK (int i, int j) const {
@@ -108,20 +90,21 @@ class Solve8TilePuzzle {
108
90
return true ;
109
91
}
110
92
111
- const vector<vector<int >> dirs = {{0 , 1 }, {1 , 0 }, {0 , -1 }, {-1 , 0 }};
93
+ const std:: vector<std:: vector<int >> dirs = {{0 , 1 }, {1 , 0 }, {0 , -1 }, {-1 , 0 }};
112
94
for (const auto &dir : dirs) {
113
95
int newI = currNode->getBlankIndex ().first + dir[0 ];
114
96
int newJ = currNode->getBlankIndex ().second + dir[1 ];
115
97
116
98
if (!boundsOK (newI, newJ)) continue ;
117
99
118
- vector<vector<int >> newState = currNode->getState ();
119
- swap (newState[currNode->getBlankIndex ().first ][currNode->getBlankIndex ().second ], newState[newI][newJ]);
100
+ std:: vector<std:: vector<int >> newState = currNode->getState ();
101
+ std:: swap (newState[currNode->getBlankIndex ().first ][currNode->getBlankIndex ().second ], newState[newI][newJ]);
120
102
Node *newNode = new Node (newState, currNode, currNode->getDepth () + 1 );
121
103
122
104
if (visitedList.find (newNode->getState ()) == visitedList.end ()) {
123
105
if (dls (newNode, depthLimit)) return true ;
124
106
}
107
+ delete newNode; // Prevent memory leak
125
108
}
126
109
return false ;
127
110
}
@@ -130,10 +113,14 @@ class Solve8TilePuzzle {
130
113
* @brief Initiates the iterative deepening search to solve the puzzle.
131
114
*/
132
115
void iterativeDeepeningSearch () {
133
- for (int depth = 0 ; depth < INT_MAX ; depth++) {
116
+ for (int depth = 0 ; depth < std::numeric_limits< int >:: max () ; depth++) {
134
117
visitedList.clear ();
135
118
Node *root = new Node (initialState, nullptr , 0 );
136
- if (dls (root, depth)) return ;
119
+ if (dls (root, depth)) {
120
+ delete root; // Clean up
121
+ return ;
122
+ }
123
+ delete root; // Clean up
137
124
}
138
125
}
139
126
@@ -142,7 +129,7 @@ class Solve8TilePuzzle {
142
129
* @param node The node at which the solution is found.
143
130
*/
144
131
void printSolution (Node *node) {
145
- cout << " Solution found at depth " << node->getDepth () << endl;
132
+ std:: cout << " Solution found at depth " << node->getDepth () << std:: endl;
146
133
// Trace back to print the solution path if necessary
147
134
}
148
135
@@ -168,30 +155,48 @@ class Solve8TilePuzzle {
168
155
* @brief Takes user input for the initial state of the puzzle.
169
156
* @param initialState Reference to the 2D vector where the input will be stored.
170
157
*/
171
- void takeUserInput (vector<vector<int >> &initialState) {
172
- cout << " Enter the initial state of the 8-tile puzzle (0 for blank tile):\n " ;
158
+ void takeUserInput (std:: vector<std:: vector<int >> &initialState) {
159
+ std:: cout << " Enter the initial state of the 8-tile puzzle (0 for blank tile):\n " ;
173
160
for (int i = 0 ; i < N; i++) {
174
161
for (int j = 0 ; j < N; j++) {
175
- cin >> initialState[i][j];
162
+ std:: cin >> initialState[i][j];
176
163
}
177
164
}
178
165
}
179
166
180
167
/* *
181
- * @brief Main function to run the 8-tile puzzle solver.
168
+ * @brief Test function to run the 8-tile puzzle solver with predefined cases .
182
169
*/
183
- int main () {
184
- vector<vector<int >> initialState (N, vector<int >(N, 0 ));
185
- vector<vector<int >> goalState = {{1 , 2 , 3 }, {4 , 5 , 6 }, {7 , 8 , 0 }};
186
-
187
- takeUserInput (initialState);
170
+ void testSolve8TilePuzzle () {
171
+ // Test Case 1: Solvable case
172
+ std::vector<std::vector<int >> initialState1 = {{1 , 2 , 3 }, {4 , 5 , 6 }, {7 , 8 , 0 }};
173
+ std::vector<std::vector<int >> goalState = {{1 , 2 , 3 }, {4 , 5 , 6 }, {7 , 8 , 0 }};
174
+
175
+ Solve8TilePuzzle puzzle1 (initialState1, goalState);
176
+ if (puzzle1.isSolvable ()) {
177
+ std::cout << " Test Case 1: " ;
178
+ puzzle1.iterativeDeepeningSearch ();
179
+ } else {
180
+ std::cout << " Test Case 1: Not Solvable" << std::endl;
181
+ }
188
182
189
- Solve8TilePuzzle solvePuzzle (initialState, goalState);
190
- if (solvePuzzle.isSolvable ()) {
191
- solvePuzzle.iterativeDeepeningSearch ();
183
+ // Test Case 2: Unsolvable case
184
+ std::vector<std::vector<int >> initialState2 = {{1 , 2 , 3 }, {4 , 5 , 6 }, {0 , 7 , 8 }};
185
+
186
+ Solve8TilePuzzle puzzle2 (initialState2, goalState);
187
+ if (puzzle2.isSolvable ()) {
188
+ std::cout << " Test Case 2: " ;
189
+ puzzle2.iterativeDeepeningSearch ();
192
190
} else {
193
- cout << " \n Not Solvable" << endl;
191
+ std:: cout << " Test Case 2: Not Solvable" << std:: endl;
194
192
}
193
+ }
195
194
195
+ /* *
196
+ * @brief Main function to run the test function.
197
+ * @returns 0 on exit
198
+ */
199
+ int main () {
200
+ testSolve8TilePuzzle ();
196
201
return 0 ;
197
202
}
0 commit comments