// CSC444H1F Solution Code for Assignment 1 (with no input validation). // By Prof. Penny, October 29, 2006 // ~70 lines of code, ~150 minutes to code, 2 defects // Defect 1: used a tiles[1][1] declaration and then was surprised when stride was 1, not N! // Defect 2: off by one error in allocation of boards array // #include "stdafx.h" // standard pre-compiled headers int N; // board dimension int BoardBytes; // Bytes to allocate for each board structure (below) // Need to keep track of all boards in the current depth-first search // in order to both // 1. remember the sequence of moves // 2. ensure we are not looping const int MaxDepth = 30; // Would take over 1 day to solve depth 30 struct board { int blankRow; // 0..N-1 int blankCol; // 0..N-1 int move; // Index into "moveDirections" for next move for this board int tiles[1]; // indexed as tiles[row*N+col] - will allocate sufficient storage for NxN } *boards[MaxDepth+1]; // Static array of possible move directions for the blank square const int NumMoveDirections = 4; struct MoveDirection { int row; // -1,0,+1 int col; // -1,0,+1 const char *name; // user-readable name of this move } moveDirections[NumMoveDirections] = { {-1,0,"up"}, {+1,0,"down"}, {0,-1,"left"}, {0,+1,"right"} }; // Apply the move in direction "md" to the board "b" if possible and return true. // If not possible (because at the edge of the board), return false. bool move(struct board* b, int md) { int blankRow = b->blankRow + moveDirections[md].row; if( blankRow < 0 || blankRow >= N ) return false; int blankCol = b->blankCol + moveDirections[md].col; if( blankCol < 0 || blankCol >= N ) return false; b->tiles[b->blankRow*N+b->blankCol] = b->tiles[blankRow*N+blankCol]; b->blankCol = blankCol; b->blankRow = blankRow; b->tiles[blankRow*N+blankCol] = 0; // nice for printing boards, not otherwise required return true; } // Return if the board "b" is in the correct final position or not. bool isSolved(struct board *b) { for(int i=0; i < N*N-1; i++) if( b->tiles[i] != i+1 ) return false; return true; } // Return if board "b1" is the same configuration as board "b2" or not. bool isSameBoard(struct board *b1, struct board *b2) { for(int i=0; i < N*N; i++) if( b1->tiles[i] != b2->tiles[i] ) return false; return true; } // Attempt to solve the board at "board[curlevel]". // Do not recurse deeper than "maxlevel" in total. // Return if successful at solving the board within maxlevel moves. bool solve(int maxlevel, int curlevel) { // alias for current board struct board *curb = boards[curlevel]; // Return solved if this board represents a solution if( isSolved(curb) ) return true; // Return with no solution if at maximum depth if(curlevel == maxlevel) return false; // Return with no solution if seen this board before on this descent (a move loop) for(int n=curlevel-1; n>=0; n--) if( isSameBoard(curb,boards[n]) ) return false; // Iterate through all possible moves struct board *nextb = boards[curlevel+1]; for(curb->move=0; curb->move < NumMoveDirections; curb->move++) { // make a copy of the current board into the next memcpy(nextb,curb,BoardBytes); // if we can move in this direction and the solve the board, it is solved if( move(nextb,curb->move) && solve(maxlevel,curlevel+1) ) return true; } // Could not solve after all legal moves - no solution from the current board. return false; } int _tmain(int argc, _TCHAR* argv[]) { // Read size of board into "N". scanf("%d",&N); // Allocate board "stack" storage. BoardBytes = sizeof(struct board) + sizeof(int)*(N*N-1); for(int n=0; n<=MaxDepth; n++) boards[n] = (struct board*)malloc(BoardBytes); // Input the board into "boards[0]". for(int row=0; row<N; row++) for(int col=0; col<N; col++) { scanf("%d",&(boards[0]->tiles[row*N+col])); if( boards[0]->tiles[row*N+col] == 0 ) { // this is the blank space boards[0]->blankCol = col; boards[0]->blankRow = row; } } // Depeen the search one move at a time for(int maxlevel = 0; maxlevel <= MaxDepth; maxlevel++) { // Can we solve within "maxlevel" moves? if( solve(maxlevel,0) ) { // If yes, print out the move sequence that solves it printf("Solved in %d moves\n", maxlevel); for(int n=0; n<maxlevel; n++) printf("%s\n",moveDirections[boards[n]->move].name); return 0; } } // Could not find a solution printf("No solution found in %d moves.\n", MaxDepth); return 1; }