From 69c053ef59cee7335f371f929f4ac2d8889ad620 Mon Sep 17 00:00:00 2001 From: Vikas-hub-cyber <70075655+Vikas-hub-cyber@users.noreply.github.com> Date: Sun, 9 Oct 2022 22:20:57 +0530 Subject: [PATCH] Sliding Puzzle Game in CPP --- coding_freshmen/C++/Vikas-hub-cyber/Readme.md | 16 ++ .../C++/Vikas-hub-cyber/mylinkedlist.h | 42 +++ coding_freshmen/C++/Vikas-hub-cyber/myqueue.h | 111 ++++++++ .../C++/Vikas-hub-cyber/solution.cpp | 262 ++++++++++++++++++ 4 files changed, 431 insertions(+) create mode 100644 coding_freshmen/C++/Vikas-hub-cyber/Readme.md create mode 100644 coding_freshmen/C++/Vikas-hub-cyber/mylinkedlist.h create mode 100644 coding_freshmen/C++/Vikas-hub-cyber/myqueue.h create mode 100644 coding_freshmen/C++/Vikas-hub-cyber/solution.cpp diff --git a/coding_freshmen/C++/Vikas-hub-cyber/Readme.md b/coding_freshmen/C++/Vikas-hub-cyber/Readme.md new file mode 100644 index 0000000..eea9460 --- /dev/null +++ b/coding_freshmen/C++/Vikas-hub-cyber/Readme.md @@ -0,0 +1,16 @@ + + +# Sliding-Puzzle-Game solver +### Implementation of BFS Algorithms to solve N*M sliding puzzle Game. + +The project is based on the solution of [Sliding puzzle Game](https://en.wikipedia.org/wiki/Sliding_puzzle) in which Slide your tiles around the game board until you have arranged them in the correct order +

+ +

+
+ + - Concept of [Breadth-first search(BFS)](https://en.wikipedia.org/wiki/Breadth-first_search) to consider all cases + - Created own singly linked list + - linked list based queue for BFS . + - Convert grid into string of digits so that easy to process + - Convert string into grid finally, diff --git a/coding_freshmen/C++/Vikas-hub-cyber/mylinkedlist.h b/coding_freshmen/C++/Vikas-hub-cyber/mylinkedlist.h new file mode 100644 index 0000000..d88c7ea --- /dev/null +++ b/coding_freshmen/C++/Vikas-hub-cyber/mylinkedlist.h @@ -0,0 +1,42 @@ + +//** singly Lindked list operation operation *// + +#include + +//node of singly linked list +struct listNode +{ + struct listNode *next; //next node linked to current node + char *data; //string state contained by the list +}; + +struct listNode *head = NULL; + +//Returns 1 if value is found in the list, else 0 +//Time complexity : O(N) +int isPresent(char *value) +{ + struct listNode *dummy = head; + while (dummy) + { + //if data of dummy node and value is same + if (strcmp(value, dummy->data) == 0) + return 1; + + dummy = dummy->next; + } + return 0; +} + +//Inserts a new value in the list +//Time complexity : O(1) +void insert(char *value) +{ + struct listNode *newNode = (struct listNode *)malloc(sizeof(struct listNode)); + + newNode->data = (char *)malloc(sizeof(char) * 10); + strcpy(newNode->data, value); + newNode->next = head; + + head = newNode; +} diff --git a/coding_freshmen/C++/Vikas-hub-cyber/myqueue.h b/coding_freshmen/C++/Vikas-hub-cyber/myqueue.h new file mode 100644 index 0000000..88364ff --- /dev/null +++ b/coding_freshmen/C++/Vikas-hub-cyber/myqueue.h @@ -0,0 +1,111 @@ +/**** Queue using linked list***/ + +#include +#include + +// node of tree-linked list +struct Node +{ + Node *next; // pointer to next node of the list + Node *parent; // parent node of this node to be pushed to queue + char *val; // value contained by the node + int valMoved; // value moved to occupy the empty space +}; + +typedef struct Node queueNode; + +typedef struct +{ + queueNode *front; // front of the queue + queueNode *rear; // rear of the queue + int size; +} Queue; + +Queue *q; + +// returns 1 if queue is empty else 0 +int is_empty() +{ + return q->front == NULL; +} + +// pushes an elment at back of the queue +void enqueue(char *value, int valueMoved, queueNode *parentNode) +{ + q->size++; + queueNode *dummy = new queueNode(); + + dummy->val = (char *)malloc(sizeof(char) * 10); + strcpy(dummy->val, value); + + dummy->next = NULL; + dummy->parent = parentNode; + dummy->valMoved = valueMoved; + + if (is_empty()) + q->rear = q->front = dummy; + else + { + q->rear->next = dummy; + q->rear = q->rear->next; + } +} + +// removes the front element from the queue +void dequeue() +{ + // queue should not be empty + assert(!is_empty()); + q->size--; + + q->front = q->front->next; +} + +// returns the element at front of the queue +char *frontVal() +{ + // queue should not be empty + assert(!is_empty()); + + return q->front->val; +} + +// returns the node at front of the queue +queueNode *frontNode() +{ + // queue should not be empty + assert(!is_empty()); + + return q->front; +} + +// returns the size of the queue +int queueSize() +{ + return q->size; +} + +// function to initialize the queue +void initializeQueue() +{ + q = (Queue *)malloc(sizeof(Queue)); + q->front = NULL; + q->rear = NULL; + q->size = 0; +} + +// reverses a path of parent nodes +queueNode *reversePath(queueNode *head) +{ + queueNode *previousNode = NULL; + + while (head) + { + queueNode *Node = head->parent; + head->parent = previousNode; + previousNode = head; + head = Node; + } + + return previousNode; +} \ No newline at end of file diff --git a/coding_freshmen/C++/Vikas-hub-cyber/solution.cpp b/coding_freshmen/C++/Vikas-hub-cyber/solution.cpp new file mode 100644 index 0000000..af1aae3 --- /dev/null +++ b/coding_freshmen/C++/Vikas-hub-cyber/solution.cpp @@ -0,0 +1,262 @@ +#include +#include "assert.h" +#include "mylinkedlist.h" +#include "myqueue.h" +#include +#pragma GCC optimize("O3,unroll-loops") +#pragma GCC target("avx2,bmi,bmi2,lzcnt,popcnt") +using namespace std; +#define ln "\n" +#define ll long long +#define fast_cin() \ + ios_base::sync_with_stdio(false); \ + cin.tie(NULL); \ + cout.tie(NULL); + +// user inputs +ll sizeofRow, sizeofColumn; +ll input[6][6]; + +// input matrix in form of string +char *initialState; +myQueue *endNode; + +// Direction to move to block +ll X[4] = {0, 0, 1, -1}; +ll Y[4] = {1, -1, 0, 0}; + +void takeInput() +{ + cout << "\nEnter the desired number of rows: "; + cin >> sizeofRow; + cout << "\nEnter the desired number of columns: "; + cin >> sizeofColumn; + ll product = (sizeofRow * sizeofColumn * 1LL); + if (product > 9) + { + cout << "\nGrid size is too big to handle\n" + << ln; + exit(0); // To end the program + } + + // array to check if any number is visited greater than once + + ll no_of_Occurence[product]; + + // we intialised with 0 value + memset(no_of_Occurence, 0, sizeof(no_of_Occurence)); + + cout << "\nEnter the initial grid with" << sizeofRow << "sizeofRow and" << sizeofColumn << "sizeofColumn\n"; + cout << "Only distinct numbers between 1-" << product - 1 << " and a 0 to represent an empty space\n\n"; + + for (ll i = 0; i < sizeofRow; i++) + { + for (ll j = 0; j < sizeofColumn; j++) + { + cin >> input[i][j]; + + // if any invalid value is added to grid + if (input[i][j] >= product) + { + cout << "\n Sorry, Enter number is invalid \n" + << ln; + exit(0); + } + + // we increase the number of occurence + no_of_Occurence[input[i][j]]++; + } + } + + // if any character is repeated in the grid + for (ll i = 0; i < product; i++) + { + if (no_of_Occurence[i] != 1) + { + cout << "\nYou have entered INVALID grid \n"; + exit(0); + } + } +} + +//-------------------------Converts a matrix to string format------------------------ +void convertMatrixToString() +{ + initialState = (char *)malloc(sizeof(char) * (sizeofRow * sizeofColumn + 1)); + ll index = 0; + for (ll i = 0; i < sizeofRow; i++) + { + for (ll j = 0; j < sizeofColumn; j++) + { + initialState[index++] = (char)(input[i][j] + '0'); + } + } + initialState[index] = '\0'; +} + +//----------------------prints a matrix of sizeofRow rows and sizeofColumn columns from a string------------------ +void printMatrixFromString(char *string) +{ + cout<<"\n"; + for (ll i = 0; string[i] != '\0'; i++) + { + cout<< string[i]; + if (((i + 1) % sizeofColumn) == 0) + { + cout<<"\n"; + for (ll j = 0; j < sizeofColumn; j++) + cout<<"---"; + cout<<"\n"; + } + else + { + cout<<" | "; + } + } + cout<<"\n"; +} + +//------------------------Returns 1 if solution state is reached, else 0----------------------------------- +ll reachedAnswerState(char *toCheck) +{ + for (ll i = 0; i + 1 < sizeofRow * sizeofColumn; i++) + { + if ((toCheck[i] - '0') != (i + 1)) + return 0; + } + + return toCheck[sizeofRow * sizeofColumn - 1] == '0'; +} + +void swap(char *a, char *b) +{ + char temp = *a; + *a = *b; + *b = temp; +} + +//---------------------pushes all the reachable states from a given state---------------------------------- +//-----------------------------------Time Complexity : O((N*M)!)--------------------------------------------- +void pushReachableStates(myQueue *parent, char *initialState) +{ + // Finding the index at which empty space or 0 is present + ll indexOfZero = -1; + for (ll i = 0; i < sizeofRow * sizeofColumn; i++) + { + if (initialState[i] == '0') + { + indexOfZero = i; + break; + } + } + + // Computing the x and y coordinate of 0 in grid + ll xCoordinate = indexOfZero / sizeofColumn; + ll yCoordinate = indexOfZero % sizeofColumn; + + // moving in all four directions + for (ll i = 0; i < 4; i++) + { + ll newX = xCoordinate + X[i]; + ll newY = yCoordinate + Y[i]; + + // if new cell is inside the matrix + if (newX >= 0 && newX < sizeofRow && newY >= 0 && newY < sizeofColumn) + { + // moving the empty space + swap(&initialState[newX * sizeofColumn + newY], &initialState[indexOfZero]); + + // checking if we have reached this state initially or not + if (isPresent(initialState) == 0) + { + insert(initialState); + enqueue(initialState, initialState[indexOfZero] - '0', parent); + } + + // moving the empty space back to it's original position + swap(&initialState[newX * sizeofColumn + newY], &initialState[indexOfZero]); + } + } +} + +//---------------------Returns the number of minimum moves to solve the input grid--------------------------- +//-----------------------------------Time Complexity : O((N*M)!)--------------------------------------------- +ll minimumMoves() +{ + // initializing queue and adding the initialState + initializeQueue(); + + enqueue(initialState, -1, NULL); + insert(initialState); + + // denotes moves until we find solution state + ll movesTillNow = 0; + + // while there are more states to explore + while (is_empty() == false) + { + ll size = queueSize(); + + // exploring all the states within one move + while (size--) + { + char *currentState = (char *)malloc(sizeof(char) * 10); + myQueue *currentNode = frontNode(); + strcpy(currentState, frontVal()); + + dequeue(); + + if (reachedAnswerState(currentState)) + { + endNode = currentNode; + return movesTillNow; + } + + pushReachableStates(currentNode, currentState); + } + + // incrementing number of moves to reach the solution state + movesTillNow++; + } + + // there is no solution for the input grid + return -1; +} + +int main() +{ + takeInput(); + convertMatrixToString(); + + ll result = minimumMoves(); + + // if there is no possible solution + if (result == -1) + { + cout << "\nNot Possible"; + } + else + { + // shortest number of moves + cout << "\nShortest number of moves = " << result << ln; + + // reversing the path of parents to print from front + myQueue *startNode = reversePath(endNode); + + // until the end of the path + while (startNode != NULL) + { + printMatrixFromString(startNode->val); + ll toMove = startNode->valMoved; + startNode = startNode->parent; + + if (startNode) + { + cout << "Press any key to continue\n"; + + cout << "\nMoving " << startNode->valMoved << " to reach next state:\n"; + } + } + } + return 0; +} \ No newline at end of file