// Alexander Huddleston 223000555 // CSCE420 // Due: October 2, 2017 (changed to 4) // hw1pr3.cpp // Purpose: A breadth-first search program solving a 15-puzzle problem. #include #include #include using namespace std; // I could move this into a separate header file, due to time // constrains I am keeping it in main for now. class GameBoard { private: // A string representing the state of the board. string state = ""; // Which index the blank tile is at. int blank = 0; // List of game moves so far. vector moves; public: // Should only be used at the beginning to set initial state. void setBoardState(string s) { state = s; blank = s.find('a'); } // Return the current board state. string getBoardState() { return state; } // Return the vector of move strings. vector getMoves() { return moves; } // Change board state, make move. Not necessarily in that order. void swap(char c) { char temp = 'p'; switch(c) { case 'l': temp = state[blank - 1]; state[blank - 1] = 'a'; state[blank] = temp; blank = --blank; break; case 'r': temp = state[blank + 1]; state[blank + 1] = 'a'; state[blank] = temp; blank = ++blank; break; case 'u': temp = state[blank - 4]; state[blank - 4] = 'a'; state[blank] = temp; blank = blank - 4; break; case 'd': temp = state[blank + 4]; state[blank + 4] = 'a'; state[blank] = temp; blank = blank + 4; break; default: break; } // Debugging //print_move(c, state); moves.push_back(c + state); } // Check if a move is legal. bool isLegal(char c) { if(c == 'l') { return ((blank % 4) > 0); } if(c == 'r') { return ((blank % 4) < 3); } if(c == 'u') { return (blank > 3); } if(c == 'd') { return (blank < 12); } } // Check if we have solved the puzzle bool isSolved(string s) { if(moves.size() > 0) { return !(moves[moves.size() - 1].substr(1).compare(s)); } else { return !(state.compare(s)); } } // Useful if we want the previous board state back. void resetLastMove() { if(moves.size() > 0) { moves.pop_back(); moves.pop_back(); } else { cerr << "Nothing to reset." << endl; } } } gb; // Global GameBoard queue. queue gbq; string get_input_game_board() { string input = ""; getline(cin, input); string output = ""; string token = ""; for(char c : input) { if(c == ',') { output += (char)(stoi(token) + 97); token = ""; continue; } else { token += c; } } output += (char)(stoi(token) + 97); return output; } void print_move(char m, string gb) { string move = ""; switch(m) { case 'l': move = "Left"; break; case 'r': move = "Right"; break; case 'u': move = "Up"; break; case 'd': move = "Down"; break; default: move = "Start"; break; } for(int x = 0; x < 16; ++x) { if(x == 0) { cout << "\t" << move << "\t"; } else if(x % 4 == 0) { cout << "\n\t\t"; } if(((int)gb[x]) - 97 < 10) { cout << ((int)gb[x] - 97) << " "; } else { cout << ((int)gb[x] - 97) << " "; } } if(m == 's') { cout << "\nSwap the blank\n"; } else { cout << "\n\n"; } } GameBoard solve_game(GameBoard gb, string solved) { gbq.pop(); if(gb.isSolved(solved)) { return gb; } if(gb.isLegal('l')) { gb.swap('l'); gbq.push(gb); if(gb.isSolved(solved)) { return gb; } else { gb.swap('r'); gb.resetLastMove(); } } if(gb.isLegal('r')) { gb.swap('r'); gbq.push(gb); if(gb.isSolved(solved)) { return gb; } else { gb.swap('l'); gb.resetLastMove(); } } if(gb.isLegal('u')) { gb.swap('u'); gbq.push(gb); if(gb.isSolved(solved)) { return gb; } else { gb.swap('d'); gb.resetLastMove(); } } if(gb.isLegal('d')) { gb.swap('d'); gbq.push(gb); if(gb.isSolved(solved)) { return gb; } else { gb.swap('u'); gb.resetLastMove(); } } return solve_game(gbq.front(), solved); } int main() { // Initializing with simple test case just in case something goes wrong. string solved = "bcdefghijklmnopa"; string init = "bcdefghijkalnopm"; // Getting input. cout << "Enter 15-puzzle starting state by rows (0 for blank):" << endl; init = get_input_game_board(); cout << "Enter ending state by rows (0 for blank):" << endl; solved = get_input_game_board(); // Push starting board into queue, start recursion. gb.setBoardState(init); gbq.push(gb); gb = solve_game(gbq.front(), solved); // Print the solution. cout << "Solution:" << endl; print_move('s', init); if(gb.getMoves().size() > 0) { for(string m : gb.getMoves()) { char c = m[0]; string state = m.substr(1); print_move(c, state); } } // I added various pieces of code to help the program // if the user decides to put in an already solved puzzle. if(gb.getMoves().size() > 0) { cout << "Done!\tGenerated " << gb.getMoves().size() << " states." << endl; } else { cout << "You gave me a solved puzzle." << endl; } return 0; }