// Removes the string from the front of the queue and sets it to s void deQ(Queue *q, char **s) { if (isEmptyQ(q)) { DIE("Queue is empty"); } if (!isEmptyS(&(q->stack2))) { popS(&(q->stack2), s); } else { while (!isEmptyS(&(q->stack1))) { popS(&(q->stack1), s); pushS(&(q->stack2), *s); } popS(&(q->stack2), s); } }
char* popQ( StrQueue* queue ) { if( isEmptyQ(queue) == 0 ){ char* temp; queue->front = (queue->front + 1) % Q_ARR_MAX; temp = queue->queue[ queue->front ]; queue->queue[ queue->front ] = 0; return temp; }else{ printf("queue is empty"); return NULL; } }
int dequeue(QUEUE *Q,int *data) { int i; if(isEmptyQ(*Q)) return 0; else { *data=Q->q[Q->front]; i=Q->front; while(i!=Q->rear) { Q->q[i]=Q->q[i+1]; i++; } //(Q->front)--; if(Q->front==Q->rear) --(Q->front); --(Q->rear); return 1; } }
/* Pops off string pointer in FIFO order by taking from Stack 2 if it has values and otherwise pouring all the values from Stack 1 into Stack 2 before popping off the top of Stack 2, which will be the first element pushed onto Stack 1. Returns TRUE if successful and puts popped value into *pos. */ bool dequeue (Stack *stk1, Stack *stk2, char **pos) { if (!isEmptyQ(stk1, stk2)) // The queue is NOT empty { if (!isEmptyS(stk2)) // stk2 has vals, pop off top one { popS(stk2, pos); return true; } else // No vals in stk2 { while (!isEmptyS(stk1)) // pour all of stk1 into stk2 { popS(stk1, pos); pushS(stk2, *pos); } popS(stk2, pos); // Now pop off top of stk2 return true; } } else return false; // Queue was empty }
int main(int argc, char *argv[]) { bool rFlag = false; // Flag to tell if -r is specified int height = 3; // HEIGHT of the Rubik's square int width = 3; // WIDTH of the Rubik's square int maxlength; // MAXLENGTH of a series of moves char *initial = NULL; // The INITIAL string char *goal = NULL; // The GOAL string /* INPUT ERROR CHECKING */ // Check for correct number of args if (argc < 4 || argc > 7) { DIE("RubikSq: RubikSq [-r] [HEIGHT WIDTH] MAXLENGTH INITIAL GOAL"); } if (argc == 5 || argc == 7) { // Check to make sure the first arg is "-r" if (strcmp(argv[1], "-r") != 0) { DIE("RubikSq: Invalid [-r] Flag"); } rFlag = true; } if (argc == 6 || argc == 7) { char *check = argv[argc-5]; // Used to check for non-numeric chars in the args for (int i = 0; i < strlen(check); i++) { if (!isdigit(check[i])) { DIE("RubikSq: Invalid HEIGHT"); } } char *end = NULL; // End pointer for strtol height = strtol(argv[argc-5], &end, 10); if (*end != '\0') { DIE("RubikSq: Invalid HEIGHT"); } char *check2 = argv[argc-4]; // Used to check for non-numeric chars in the args for (int i = 0; i < strlen(check2); i++) { if (!isdigit(check2[i])) { DIE("RubikSq: Invalid WIDTH"); } } char *end2 = NULL; // End pointer for strtol width = strtol(argv[argc-4], &end2, 10); if (*end2 != '\0') { DIE("RubikSq: Invalid WIDTH"); } } char *check3 = argv[argc-3]; // Used to check for non-numeric chars in the args for (int i = 0; i < strlen(check3); i++) { if (!isdigit(check3[i])) { DIE("RubikSq: Invalid MAXLENGTH"); } } char *end3 = NULL; // End pointer for strtol maxlength = strtol(argv[argc-3], &end3, 10); if (*end3 != '\0') { DIE("RubikSq: Invalid MAXLENGTH"); } // Check for non-alpha chars in the args initial = argv[argc-2]; for (int i = 0; i < strlen(initial); i++) { if (!isalpha(initial[i])) { DIE("RubikSq: Invalid INITIAL"); } } // Check for non-alpha chars in the args goal = argv[argc-1]; for (int i = 0; i < strlen(goal); i++) { if (!isalpha(goal[i])) { DIE("RubikSq: Invalid GOAL"); } } if (maxlength < 0) { DIE("RubikSq: MAXLENGTH < 0"); } if (height < 2 || height > 5 || width < 2 || width > 5) { DIE("RubikSq: HEIGHT/WIDTH must be between 2 and 5, inclusive"); } if (strlen(initial) != strlen(goal)){ DIE("RubikSq: Length of INITIAL does not equal length of GOAL"); } if ((height*width) != strlen(initial)) { DIE("RubikSq: HEIGHT*WIDTH does not match length of INITIAL/GOAL"); } // If GOAL and INITIAL are the same, print and exit if (strcmp(initial, goal) == 0) { printf("%s\n", initial); exit(0); } // Make an alphabetized copy of INITIAL char *initialSort = malloc(strlen(initial)+1); // An alphabetized version of INITIAL strcpy(initialSort, initial); sortAlphabetical(initialSort); // Make an alphabetized copy of GOAL char *goalSort = malloc(strlen(goal)+1); // An alphabetized version of GOAL strcpy(goalSort, goal); sortAlphabetical(goalSort); if (strcmp(initialSort, goalSort) != 0) { DIE("RubikSq: INITIAL and GOAL do not contain the same letters"); } // Make sure all letters are between A and L, inclusive if (initialSort[0] < 'A' || initialSort[strlen(initialSort)-1] > 'L' || goalSort[0] < 'A' || goalSort[strlen(goalSort)-1] > 'L') { DIE("RubikSq: INITIAL/GOAL contain invalid letters"); } /* ALGORITHM */ Trie dict; // The dictionary trie for storing past positions createT(&dict); addT(&dict, goal, NULL, 0, 0); Queue moves; // The queue of positions to analyze createQ(&moves); enQ(&moves, goal); // Main loop while (!isEmptyQ(&moves)) { char *pos = NULL; // The current position P deQ(&moves, &pos); int len = getLengthT(&dict, pos, 0); // The length of P in the dictionary if (len < maxlength) { int total; // The total number of possible moves // If -r is specified, there are more possible moves if (rFlag) { total = (width-1)*height + (height-1)*width; } else { total = width + height; } char *primes[total]; // The array of possible positions P' char *copy; // Used to find all P' to put in the array // If the -r flag is specified, we can move right or down multiple times if (rFlag) { for (int i = 1; i <= height; i++) { copy = pos; for (int j = 1; j < width; j++){ copy = moveRight(i, width, copy); primes[(i-1)*(width-1)+j-1] = copy; } } for (int i = 1; i <= width; i++) { copy = pos; for (int j = 1; j < height; j++){ copy = moveDown(i, width, height, copy); primes[height*(width-1)+(i-1)*(height-1)+j-1] = copy; } } } // Otherwise, we can only make one move else { for (int i = 1; i <= height; i++) { primes[i-1] = moveRight(i, width, pos); } for (int i = 1; i <= width; i++) { primes[i+height-1] = moveDown(i, width, height, pos); } } // P' checking for loop for (int i = 0; i < total; i++) { // If P' is INITIAL, print the moves and exit if (strcmp(primes[i], initial) == 0) { printf("%s\n", primes[i]); printf("%s\n", pos); while (getFromT(&dict, pos, 0) != NULL) { pos = getFromT(&dict, pos, 0); printf("%s\n", pos); } // Free the sorted INITIAL and GOAL free(initialSort); free(goalSort); exit(0); } // Else if P' is not in the dictionary, add it to the dict and queue else if (!isMemberT(&dict, primes[i], 0)) { addT(&dict, primes[i], pos, len+1, 0); enQ(&moves, primes[i]); } // Else free the storage else { free(primes[i]); } } } } // Free the sorted INITIAL and GOAL free(initialSort); free(goalSort); return 0; }
/* RubikSq.c | Stephen Krewson | CPSC 223b. USAGE: RubikSq [-r] [HEIGHT WIDTH] MAXLENGTH INITIAL GOAL. RubikSq solves a Rubik's square puzzle using a trie data structure and breadth-first search to find the fewest number of moves necessary to transform INITIAL into GOAL. */ int main (int argc, char *argv[]) { // 1. PARSING COMMAND-LINE ARGS bool rFlag = false; int maxLength = 0; int pos = 0; // pos is counter for moving through argv[] int height = 3, width = 3; // default values char *initial = NULL; char *goal = NULL; if (argc % 2 != 0) // "-r" specified { if (argc > 3) { if (strcmp(argv[1], "-r") != 0) KILL("ERROR: '-r' flag improperly specified."); else rFlag = true; } else KILL("ERROR: Insufficient number of arguments."); } if (argc == 6 || argc == 7) // HEIGHT and WIDTH specified { // Indexes depend on -r flag pos = (rFlag == true) ? 2 : 1; initial = strdup(argv[pos+3]); // use malloc bc we will call free() goal = strdup(argv[pos+4]); // on all the dict nodes if (!(height = atoi(argv[pos])) || !(width = atoi(argv[pos+1])) || (height < 2 || height > 5) || (width < 2 || width > 5)) KILL("ERROR: Invalid HEIGHT and WIDTH values."); char *endPtr; maxLength = (int) strtol(argv[pos+2], &endPtr, 10); if (endPtr < argv[pos+2] + strlen(argv[pos+2])) KILL("ERROR: MAXLENGTH contains nun-numeric characters."); else if (maxLength < 0) KILL ("ERROR: MAXLENGTH is negative."); if (!checkTray(height, width, initial, goal)) KILL("ERROR: Invalid tray sequences."); } // HEIGHT, WIDTH NOT specified else if (argc == 4 || argc == 5) { pos = (rFlag == true) ? 2 : 1; initial = strdup(argv[pos+1]); goal = strdup(argv[pos+2]); char *endPtr; maxLength = (int) strtol(argv[pos], &endPtr, 10); if (endPtr < argv[pos] + strlen(argv[pos])) KILL("ERROR: MAXLENGTH contains nun-numeric characters."); else if (maxLength < 0) KILL ("ERROR: MAXLENGTH is negative."); if (!checkTray(height, width, initial, goal)) KILL("ERROR: Invalid tray sequences."); } else { KILL("ERROR: Invalid number of arguments."); } Trie dict; // Initialize trie data structure createT(&dict); Stack stk1, stk2; // Initialize the "queue" createS(&stk1); createS(&stk2); char *currentPos = NULL; // pointer for position being processed char *prevPos = NULL; // pointer to "from" attr in the dict long lengthPos = 0; // address to hold "length" attr in the dict int permutations = 0; // hold # of permutations getPerms returns insertT(&dict, goal, NULL, 0); // Add GOAL to dictionary enqueue(&stk1, &stk2, goal); // push GOAL onto the queue while (!isEmptyQ(&stk1, &stk2)) // While the queue is not empty { dequeue(&stk1, &stk2, ¤tPos); // Remove P from head of queue searchT(&dict, currentPos, &prevPos, &lengthPos); // lengPos holds length of P if (lengthPos + 2 < maxLength) // +2 because currentPos is 1 { // more than the previous distance and each // permutation is another distance of 1 char **perms; // array of pointers to permutations of P perms = getPerms(currentPos, height, width, rFlag, &permutations); for (int j = 0; j < permutations; j++) // for each position . . . { if (strcmp(initial, perms[j]) == 0) // if P' is the INITIAL { // add it so we can trace insertT(&dict, perms[j], currentPos, lengthPos+1); printf("%s\n", initial); // print INITIAL printf("%s\n", currentPos); // reached INITIAL from... char *holder2; // follow path of search holder2 = currentPos; // start at currentPos while (strcmp(holder2, goal) != 0) { if(!searchT(&dict, currentPos, &holder2, &lengthPos)) { KILL("ERROR: searchT() failed."); } printf("%s\n", holder2); currentPos = holder2; } destroyS(&stk1); // get rid of the queue destroyS(&stk2); deleteT(dict, dict); free(dict); // Remember root node free(perms[j]); free(perms); // free the pointer array exit(0); // Successful exit! } else if (!searchT(&dict, perms[j], &prevPos, &lengthPos)) { // Put p' in dict, on queue if (!insertT(&dict, perms[j], currentPos, lengthPos+1)) { KILL("ERROR: insertT() failed."); } enqueue(&stk1, &stk2, perms[j]); } else // else P' is already in the dictionary { free(perms[j]); // don't need it anymore! } } free(perms); // Free the pointer array } } destroyS(&stk1); // Cleanup in case of no valid sequence destroyS(&stk2); deleteT(dict, dict); free(dict); // Remember to clean root node of dict return EXIT_SUCCESS; }