Free Cell Solitaire Player

This solver is just using various simple search techniques, mainly iterative deepening. It really knows very little about the game itself. It knows what moves are legal, and has a sense of how close it is to a solution (heuristic), but it has no concept of strategy.

The rules of Free Cell are simple. You can move any card to any empty Free Cell. You have to move cards in the right order to the Home Cells. E.g., 8 of hearts can only go on top of the 7 of hearts. Cards can only be moved on the board to cards one higher and different color. E.g., a red 7 can only go on a black 8.
View Cards and see how they were cropped


src/freecell.c - Game server agent

   1: /* freecell environment */
   2: 
   3: #include <stdio.h>
   4: #include <stdlib.h>
   5: #include <string.h>
   6: #include <time.h>
   7: 
   8: #include "../inc/rand.h"
   9: #include "../inc/split_stdin.h"
  10: #include "../inc/state.h"
  11: 
  12: int highrank;
  13: 
  14: void usage(char *app_name)
  15: {
  16:     printf("Usage:\n");
  17:     printf("   %s [-v] [-r rank] [-s seed]\n\n", app_name);
  18:     printf("Explanation of options:\n");
  19:     printf("   -v         causes cells and columns to be displayed\n");
  20:     printf("   -r rank    value of highest rank (1-13), 1 is ace, 13 is king\n");
  21:     printf("   -s seed    integer seed for random number generation\n");
  22:     printf("Freecell environment\n");
  23:     printf("    This game simulates the freecell card solitaire game.\n");
  24:     printf("Environment Description:\n");
  25:     printf("    Initially, the 8 columns are output on 8 separate lines, the last\n");
  26:     printf("    card in each column is playable.\n");
  27:     printf("    The freecell program accepts a line of two characters as input, the\n");
  28:     printf("    first character specifies the column or cell from which a card is\n");
  29:     printf("    taken.  The second character specifies the column or cell to which\n");
  30:     printf("    the card is moved.  1-8 specifies one of the 8 columns.  A-D (or\n");
  31:     printf("    (a-d) specifies one of the four free cells.  F (or f) can be used\n");
  32:     printf("    to move to the first empty free cell.  H (or h) can only be used\n");
  33:     printf("    as the second character and specifies a move to the home cell of\n");
  34:     printf("    the card's suit.\n");
  35:     printf("    The game is considered finished when all the columns are in descending\n");
  36:     printf("    order.\n");
  37:     printf("Rules of freecell (more or less copied from Microsoft Windows):\n");
  38:     printf("    The object of the game is to move all the cards to the home cells,\n");
  39:     printf("    using the free cells as place holders.  To win, you make four stacks\n");
  40:     printf("    of cards on the home cells: one for each suit, stacked in order of\n");
  41:     printf("    rank.\n");
  42:     printf("    The FreeCell game area consists of the four home cells, four free\n");
  43:     printf("    cells, and the deck of cards, which is dealt face-up in eight columns\n");
  44:     printf("    at the beginning of the game.  There are three ways you can move cards\n");
  45:     printf("    in freecell:\n");
  46:     printf("    (1) Any card from the bottom of a column can be moved to an empty\n");
  47:     printf("    free cell.\n");
  48:     printf("    (2) A card in a free cell or the bottom of a column can be moved\n");
  49:     printf("    to a home cell if it is an ace or if the card with the same suit\n");
  50:     printf("    and next lowest rank has been moved to its home cell.\n");
  51:     printf("    (3) A card in a free cell or the bottom of a column can be moved\n");
  52:     printf("    to the bottom of another column if the column is empty or if the\n");
  53:     printf("    current bottom of the column has a different color and the next\n");
  54:     printf("    highest rank.\n");
  55: 
  56:     exit(1);	 
  57: }
  58: 
  59: 
  60: /* The cards are specified by integers 0 to 51.  -1 specifies no card
  61: * in that location.  The aces are integers 0 to 3, twos are from 4 to
  62: * 7, etc.  If x is a card, then x % 4 == 0, 1, 2, or 3 respectively
  63: * indicates a spade, heart, club, or diamond.  Thus 1 + x/4 computes
  64: * the rank of a card, and x % 4, its suit, and x % 2, its color.
  65: */
  66: 
  67: /* globals */
  68: State S;
  69: 
  70: void state_visited()
  71: {
  72: }
  73: 
  74: void print_card(FILE *out, int card, char *nocard)
  75: {
  76:     int suit, rank;
  77: 
  78:     if (card < 0 || card >= highrank*NSUITS)
  79:     {
  80:         fprintf(out, nocard);
  81:     }
  82:     else
  83:     {
  84:         rank = RANK(card);
  85:         if (rank == 1) fprintf(out, "A");
  86:         else if (rank == 13) fprintf(out, "K");
  87:         else if (rank == 12) fprintf(out, "Q");
  88:         else if (rank == 11) fprintf(out, "J");
  89:         else if (rank == 10) fprintf(out, "T");
  90:         else fprintf(out, "%d", rank);
  91:         suit = SUIT(card);
  92:         if (suit == 0) fprintf(out, "S");
  93:         else if (suit == 1) fprintf(out, "h");
  94:         else if (suit == 2) fprintf(out, "C");
  95:         else if (suit == 3) fprintf(out, "d");
  96:     }
  97: }
  98: 
  99: 
 100: void printcards()
 101: {
 102:     int i,j,flag;
 103:     fprintf(stderr, "    free cells(A-D):");
 104:     for (i = 0; i < NFREECELLS; i++)
 105:     {
 106:         fprintf(stderr, "  ");
 107:         print_card(stderr, S->fcell[i], "--");
 108:     }
 109: 
 110:     fprintf(stderr, "    home cells(H):");
 111:     for (i = 0; i < NSUITS; i++)
 112:     {
 113:         fprintf(stderr, "  ");
 114:         print_card(stderr, S->hcell[i], "--");
 115:     }
 116: 
 117:     fprintf(stderr, "\n\n");
 118:     for (j = 0; j < LONGEST_COLUMN; j++)
 119:     {
 120:         if (j == 0) fprintf(stderr, "    columns(1-%d):", NCOLUMNS);
 121:         else fprintf(stderr, "                 ");
 122:         flag = 1;
 123:         for (i = 0; i < NCOLUMNS; i++)
 124:         {
 125:             fprintf(stderr, "  ");
 126:             print_card(stderr, S->column[i][j], (j == 0) ? "--" : "  ");
 127:             if (S->column[i][j] >= 0) flag = 0;
 128:         }
 129:         fprintf(stderr, "\n");
 130:         if (flag) break;
 131:     }
 132:     fflush(stderr);
 133: }
 134: 
 135: 
 136: int main(int argc, char *argv[]) {
 137:     char **response;
 138:     int num_fields;
 139:     int done, legal, solved;
 140:     int fromfree, fromcolumn, tofree, tohome, tocolumn;
 141:     int source, sourcecard, dest, destcard;
 142:     int i, j, temp;
 143:     int user_seed, seed, visible, rand_num;
 144:     int deck[52];
 145: 
 146:     int argNum = 1;
 147: 
 148:     S = freecell_alloc();
 149:     visible = 0; 
 150:     user_seed = 0;
 151:     highrank = HIGHEST_RANK;
 152: 
 153:     while (argNum < argc)
 154:     {
 155:         if (strcmp(argv[argNum], "-v") == 0)
 156:         {
 157:             visible = 1;
 158:         }
 159:         else if (strcmp(argv[argNum], "-r") == 0 && argNum < argc-1)
 160:         {
 161:             highrank = atoi(argv[argNum+1]);
 162:             if (highrank < 1) highrank = 1;
 163:             if (highrank > HIGHEST_RANK) highrank = HIGHEST_RANK;
 164:             argNum++;
 165:         }
 166:         else if (strcmp(argv[argNum], "-s") == 0 && argNum < argc-1)
 167:         {
 168:             user_seed = 1;
 169:             seed = atoi(argv[argNum+1]);
 170:             fprintf(stderr, "\n**** Forcing seed = %d\n", seed);
 171:             fflush(stderr);
 172:             argNum++;
 173:         }
 174:         else
 175:         {
 176:             usage(argv[0]);
 177:             exit(0);
 178:         }
 179:         argNum++;
 180:     }
 181: 
 182:     if (user_seed == 0)
 183:     {
 184:         seed = (int) time(NULL);
 185:         fprintf(stderr, "\n**** Initial seed = %d\n", seed);
 186:         fflush(stderr);
 187:     }
 188:     srand48(seed);
 189: 
 190:     for (i = 0; i < NFREECELLS; i++) {
 191:         S->fcell[i] = -1;
 192:         S->hcell[i] = -1;
 193:     }
 194:     for (i = 0; i < NCOLUMNS; i++)
 195:     {
 196:         for (j = 0; j < LONGEST_COLUMN; j++)
 197:         {
 198:             S->column[i][j] = -1;
 199:         }
 200:     }
 201: 
 202:     /* init the deck */
 203:     for (i = 0; i < highrank*NSUITS; i++)
 204:     {
 205:         deck[i] = i;
 206:     }
 207: 
 208:     /* shuffle the deck */
 209:     for (i = 0; i < highrank*NSUITS - 1; i++) {
 210:         rand_num = i + (int) (lrand48() % (highrank*NSUITS - i));
 211:         temp = deck[rand_num];
 212:         deck[rand_num] = deck[i];
 213:         deck[i] = temp;
 214:     }
 215: 
 216:     /* deal the cards */
 217:     for (i = 0; i < highrank*NSUITS; i++)
 218:     {
 219:         S->column[i % NCOLUMNS][i / NCOLUMNS] = deck[i];
 220:     }
 221: 
 222:     /* display the cards */
 223:     if (visible) printcards();
 224: 
 225:     // Tell solver what rank and seed -- only used for logging purposes
 226: #ifndef UNIX
 227:     printf("rank %d\n", highrank);
 228:     printf("seed %d\n", seed);
 229: #endif
 230: 
 231:     /* send initial configuration */
 232:     for (i = 0; i < NCOLUMNS; i++)
 233:     {
 234:         for (j = 0; S->column[i][j] >= 0; j++)
 235:         {
 236:             if (j > 0) printf(" ");
 237:             print_card(stdout, S->column[i][j], "  ");
 238:         }
 239:         printf("\n");
 240:         fflush(stdout);
 241:     }
 242: 
 243:     done = 0;
 244:     while (!done) {
 245:         response = split_stdin(" ", &num_fields);
 246:         if (num_fields == -1) exit(0);
 247: 
 248:         if (num_fields == 1 && strcmp(response[0], "x") == 0)
 249:         {
 250:             done = 1;
 251:         }
 252: 
 253:         if (num_fields >= 1 && strcmp(response[0], "user") == 0)
 254:         {
 255:             continue;
 256:         }
 257: 
 258:         /* messy parsing of input */
 259:         legal = 0;
 260:         solved = 0;
 261:         if (num_fields == 1 && 2 == strlen(response[0]))
 262:         {
 263:             source = response[0][0];
 264:             sourcecard = -1;
 265:             fromfree = 0;
 266:             fromcolumn = 0;
 267: 
 268:             switch (source)
 269:             {
 270:             case 'A': case 'a':
 271:             case 'B': case 'b':
 272:             case 'C': case 'c':
 273:             case 'D': case 'd':
 274:                 fromfree = 1;
 275:                 source = (source - 1) % 32;
 276:                 sourcecard = S->fcell[source];
 277:                 break;
 278:             case '1': case '2':
 279:             case '3': case '4':
 280:             case '5': case '6':
 281:             case '7': case '8':
 282:                 fromcolumn = 1;
 283:                 source = source - '1';
 284:                 for (i = 1; S->column[source][i] >= 0; i++);
 285:                 sourcecard = S->column[source][i-1];
 286:                 break;
 287:             }
 288: 
 289:             if (!NULLCARD(sourcecard) &&
 290:                 RANK(sourcecard) > 0 &&
 291:                 RANK(sourcecard) <= highrank)
 292:             {
 293:                 dest = response[0][1];
 294:                 tofree = 0;
 295:                 tohome = 0;
 296:                 tocolumn = 0;
 297:                 switch (dest)
 298:                 {
 299:                 case 'A': case 'a':
 300:                 case 'B': case 'b':
 301:                 case 'C': case 'c':
 302:                 case 'D': case 'd':
 303:                 case 'F': case 'f':
 304:                     tofree = 1;
 305:                     dest = (dest - 1) % 32;
 306:                     if (dest < 0 || dest >= NFREECELLS)
 307:                     {
 308:                         for (dest = 0; dest < NFREECELLS-1 && S->fcell[dest] >= 0; dest++);
 309:                     }
 310:                     destcard = S->fcell[dest];
 311:                     break;
 312:                 case 'H': case 'h':
 313:                     tohome = 1;
 314:                     dest = SUIT(sourcecard);
 315:                     destcard = S->hcell[dest];
 316:                     break;
 317:                 case '1': case '2':
 318:                 case '3': case '4':
 319:                 case '5': case '6':
 320:                 case '7': case '8':
 321:                     tocolumn = 1;
 322:                     dest = dest - '1';
 323:                     for (j = 1; S->column[dest][j] >= 0; j++);
 324:                     destcard = S->column[dest][j-1];
 325:                     break;
 326:                 }
 327:             }
 328: 
 329:             /* test for legal move */
 330:             if (!NULLCARD(sourcecard) &&
 331:                 RANK(sourcecard) > 0 && RANK(sourcecard) <= highrank &&
 332:                 ((tohome && (RANK(sourcecard) == 1 ?
 333:                 NULLCARD(destcard) :
 334:                 RANK(sourcecard) == 1 + RANK(destcard)) ||
 335:                 (tofree && NULLCARD(destcard)) ||
 336:                 (tocolumn && (NULLCARD(destcard) ||
 337:                 (COLOR(destcard) != COLOR(sourcecard) &&
 338:                 RANK(destcard) == 1 + RANK(sourcecard)))))))
 339:             {
 340:                 legal = 1;
 341:             }
 342:             else legal = 0;
 343: 
 344:             /* perform the move */
 345:             if (legal)
 346:             {
 347:                 /* pick it up */
 348:                 if (fromfree) S->fcell[source] = -1;
 349:                 else S->column[source][i-1] = -1;
 350: 
 351:                 /* put it down */
 352:                 if (tofree) S->fcell[dest] = sourcecard;
 353:                 else if (tohome) S->hcell[dest] = sourcecard;
 354:                 else if (NULLCARD(destcard)) S->column[dest][j-1] = sourcecard;
 355:                 else S->column[dest][j] = sourcecard;
 356: 
 357:                 /* test for doneness */
 358:                 solved = 1;
 359:                 for (i = 0; i < NSUITS; i++)
 360:                 {
 361:                     if (S->hcell[i] < (highrank-1)*NSUITS) solved = 0;
 362:                 }
 363:                 done = solved;
 364:             }
 365:         }
 366: 
 367:         if (visible) printcards();
 368: 
 369:         /* print response */
 370:         if (solved) printf("solved\n");
 371:         else if (done) printf("quit\n");
 372:         else if (legal) printf("legal\n");
 373:         else printf("illegal\n");
 374:         fflush(stdout);
 375:     }
 376: }
 377: 

src/freecell_solver.c - Plays the game

   1: /* freecell solver */
   2: 
   3: #include <stdio.h>
   4: #include <stdlib.h>
   5: #include <string.h>
   6: #include <time.h>
   7: 
   8: #include "../inc/split_stdin.h"
   9: #include "../inc/state.h"
  10: #include "../inc/idastar.h"
  11: 
  12: #define MAX 100
  13: 
  14: // Defaults
  15: #ifndef CHEAT
  16: #define CHEAT 0
  17: #endif
  18: #ifndef HEUR
  19: #define HEUR 0
  20: #endif
  21: 
  22: int states_visited;
  23: 
  24: #ifndef UNIX
  25: FILE *htmlFile;
  26: #endif
  27: 
  28: void usage(char *app_name)
  29: {
  30:     printf("Usage:\n");
  31:     printf("   %s [-h num]\n\n", app_name);
  32:     printf("Explanation of options:\n");
  33:     printf("   -h num     heuristic number 0=idsearch(default) 1 or 2\n\n");
  34: 
  35:     exit(1);
  36: }
  37: 
  38: // Parse the card, like "2S" => 4
  39: int parseCard(char *s)
  40: {
  41:     char c1, c2;
  42:     int seq, suit;
  43: 
  44:     if (strlen(s) != 2) return -1;
  45:     c1 = s[0];
  46:     c2 = s[1];
  47: 
  48:     switch (s[0])
  49:     {
  50:     case '2' : seq = 1; break;
  51:     case '3' : seq = 2; break;
  52:     case '4' : seq = 3; break;
  53:     case '5' : seq = 4; break;
  54:     case '6' : seq = 5; break;
  55:     case '7' : seq = 6; break;
  56:     case '8' : seq = 7; break;
  57:     case '9' : seq = 8; break;
  58:     case 'A': case 'a' : seq = 0; break;
  59:     case 'K': case 'k' : seq = 12; break;
  60:     case 'Q': case 'q' : seq = 11; break;
  61:     case 'J': case 'j' : seq = 10; break;
  62:     case 'T': case 't' : seq = 9; break;
  63:     default: return -1;
  64:     }
  65: 
  66:     switch (s[1])
  67:     {
  68:     case 'S': case 's' : suit = 0; break;
  69:     case 'H': case 'h' : suit = 1; break;
  70:     case 'C': case 'c' : suit = 2; break;
  71:     case 'D': case 'd' : suit = 3; break;
  72:     default: return -1;
  73:     }
  74: 
  75:     // 0 = A spades
  76:     // 1 = A hearts
  77:     // 2 = A clubs
  78:     // 3 = A diamonds
  79:     // 4 = 2 of spades
  80:     // 51 = K diamonds
  81:     return 4 * seq + suit;
  82: }
  83: 
  84: // Called whenever a new state is visited, i.e., in goal calculation
  85: void state_visited()
  86: {
  87:     states_visited++;
  88: }
  89: 
  90: // Find what changed between two states and print it out nicely
  91: // heur = 0 means don't show distance (for idsearch and dfsearch)
  92: int showMove(int heur, State S1, State S2)
  93: {
  94:     int i, j;
  95:     int c;
  96: 
  97:     int distance;
  98:     char distStr[MAX+1];
  99: 
 100:     int fromFree = -1;
 101:     char fromStr[MAX+1];
 102:     char fromChar;
 103: 
 104:     int toHome = -1;
 105:     int toFree = -1;
 106:     char toStr[MAX+1];
 107:     char toChar;
 108: 
 109:     char **response;
 110:     int fields;
 111: 
 112:     // Find out where it came from
 113: #ifdef UNIX
 114:     sprintf(fromStr, "?");
 115: #else
 116:     sprintf_s(fromStr, MAX, "?");
 117: #endif
 118:     fromChar = '?';
 119: 
 120:     // Moved away from a free cell?
 121:     for (i = 0; i < NFREECELLS; i++)
 122:     {
 123:         if (S1->fcell[i] != S2->fcell[i] && NULLCARD(S2->fcell[i]))
 124:         {
 125:             fromFree = i;
 126:             c = S1->fcell[i];
 127:             fromChar = 'A' + i;
 128: #ifdef UNIX
 129:             sprintf(fromStr, "Move %c%c from free %c",
 130:                 displayRank(c), displaySuit(c), 'A'+i);
 131: #else
 132:             sprintf_s(fromStr, MAX, "Move %c%c from free %c",
 133:                 displayRank(c), displaySuit(c), 'A'+i);
 134:             fprintf(htmlFile, "  moveCard('free', %d, 0, '%c%c'",
 135:                 i+1, displayRank(c), displaySuit(c));
 136: #endif
 137:             break;
 138:         }
 139:     }
 140: 
 141:     // Must have moved away from a column
 142:     if (fromFree < 0)
 143:     {
 144:         for (i = 0; i < NCOLUMNS; i++)
 145:         {
 146:             j = S1->collen[i];
 147:             if (j == S2->collen[i] + 1)
 148:             {
 149:                 c = S1->column[i][j-1];
 150:                 fromChar = '1' + i;
 151: #ifdef UNIX
 152:                 sprintf(fromStr, "Move %c%c from column %d",
 153:                     displayRank(c), displaySuit(c), i+1);
 154: #else
 155:                 sprintf_s(fromStr, MAX, "Move %c%c from column %d",
 156:                     displayRank(c), displaySuit(c), i+1);
 157:                 fprintf(htmlFile, "  moveCard('col', %d, %d, '%c%c'",
 158:                     i+1, j, displayRank(c), displaySuit(c));
 159: #endif
 160:                 break;
 161:             }
 162:         }
 163:     }
 164: 
 165:     // Find out where it moved to
 166: #ifdef UNIX
 167:     sprintf(toStr, "?");
 168: #else
 169:     sprintf_s(toStr, MAX, "?");
 170: #endif
 171:     toChar = '?';
 172: 
 173:     // Moved to a home?
 174:     for (i = 0; i < NSUITS; i++)
 175:     {
 176:         if (S1->hcell[i] != S2->hcell[i])
 177:         {
 178:             toHome = i;
 179:             toChar = 'H';
 180: #ifdef UNIX
 181:             sprintf(toStr, "to Home");
 182: #else
 183:             sprintf_s(toStr, MAX, "to Home");
 184:             fprintf(htmlFile, ", 'home', %d, 0);", i+1);
 185: #endif
 186:             break;
 187:         }
 188:     }
 189: 
 190:     // Moved to a free cell
 191:     if (toHome < 0)
 192:     {
 193:         for (i = 0; i < NFREECELLS; i++)
 194:         {
 195:             if (S1->fcell[i] != S2->fcell[i] && NULLCARD(S1->fcell[i]))
 196:             {
 197:                 toFree = i;
 198:                 toChar = 'A' + i;
 199: #ifdef UNIX
 200:                 sprintf(toStr, "to free %c", 'A'+i);
 201: #else
 202:                 sprintf_s(toStr, MAX, "to free %c", 'A'+i);
 203:                 fprintf(htmlFile, ", 'free', %d, 0);", i+1);
 204: #endif
 205:                 break;
 206:             }
 207:         }
 208:     }
 209: 
 210:     // Must have moved to a column
 211:     if (toHome < 0 && toFree < 0)
 212:     {
 213:         for (i = 0; i < NCOLUMNS; i++)
 214:         {
 215:             j = S1->collen[i];
 216:             if (j + 1 == S2->collen[i])
 217:             {
 218:                 toChar = '1' + i;
 219: #ifdef UNIX
 220:                 sprintf(toStr, "to column %d", i+1);
 221: #else
 222:                 sprintf_s(toStr, MAX, "to column %d", i+1);
 223:                 fprintf(htmlFile, ", 'col', %d, %d);", i+1, j+1);
 224: #endif
 225:                 break;
 226:             }
 227:         }
 228:     }
 229: 
 230:     switch (heur)
 231:     {
 232:     case 0:
 233:     default:
 234:         distance = 0;
 235: #ifdef UNIX
 236:         sprintf(distStr, "");
 237: #else
 238:         sprintf_s(distStr, MAX, "");
 239: #endif
 240:         break;
 241:     case 1:
 242:         distance = freecell_heuristic1(S2);
 243: #ifdef UNIX
 244:         sprintf(distStr, ", Heuristic1 = %d", distance);
 245: #else
 246:         sprintf_s(distStr, MAX, ", Heuristic1 = %d", distance);
 247: #endif
 248:         break;
 249:     case 2:
 250:         distance = freecell_heuristic2(S2);
 251: #ifdef UNIX
 252:         sprintf(distStr, ", Heuristic2 = %d", distance);
 253: #else
 254:         sprintf_s(distStr, MAX, ", Heuristic2 = %d", distance);
 255: #endif
 256:         break;
 257:     }
 258: #ifndef UNIX
 259:     fprintf(htmlFile, "   distance(%d);\n", distance);
 260: #endif
 261: 
 262:     printf("user %s %s%s\n", fromStr, toStr, distStr);
 263:     printf("%c%c\n", fromChar, toChar);     // For other program to act on
 264:     fflush(stdout);
 265: 
 266:     // Wait for the other program to act on it
 267:     response = split_stdin(" ", &fields);
 268:     if (fields == 0 || strncmp(response[0], "legal", 5) != 0)
 269:     {
 270:         return 0;
 271:     }
 272:     free_split_stdin(response, fields);
 273:     return 1;
 274: }
 275: 
 276: // Main -- does all the work
 277: int main(int argc, char *argv[])
 278: {
 279:     State initial_state;
 280:     State winnable_state;
 281:     struct statefns fns;
 282:     State *solution_path;
 283:     char **response;
 284:     int i, r, c, fields;
 285:     clock_t start, finish;
 286:     int status = 0;
 287:     FILE *logFile;
 288:     float elapsed;
 289: 
 290:     int heur = HEUR;
 291:     int len1 = 0, len2 = 0;
 292:     int rank;
 293:     int seed;
 294:     int cheat = CHEAT;
 295: 
 296:     int argNum = 1;
 297:     while (argNum < argc)
 298:     {
 299:         if (strcmp(argv[argNum], "-c") == 0)
 300:         {
 301:             cheat = 1;
 302:         }
 303:         else if (strcmp(argv[argNum], "-h") == 0 && argNum < argc-1)
 304:         {
 305:             heur = atoi(argv[argNum+1]);
 306:             switch (heur)
 307:             {
 308:             case 0:
 309:                 fprintf(stderr, "\n**** Using simple idsearch\n");
 310:                 break;
 311:             case 1:
 312:             case 2:
 313:                 fprintf(stderr, "\n**** Using idastar with heuristic %d\n", heur);
 314:                 break;
 315:             default:
 316:                 fprintf(stderr, "\n**** Invalid heuristic. Use 0 1 or 2, not %d\n", heur);
 317:                 fflush(stderr);
 318:                 exit(1);
 319:             }
 320:             fflush(stderr);
 321:             argNum++;
 322:         }
 323:         else
 324:         {
 325:             usage(argv[0]);
 326:             exit(0);
 327:         }
 328:         argNum++;
 329:     }
 330: 
 331: #ifndef UNIX
 332:     /* Open file to write html (javascript actually) */
 333:     if (fopen_s(&htmlFile, "fc.js", "w") != 0)
 334:     {
 335:         fprintf(stderr, "\nUnable to write to fc.js\n");
 336:         exit(1);
 337:     }
 338: #endif
 339: 
 340: #ifndef UNIX
 341:     // Pick up rank and seed (for logging only)
 342:     response = split_stdin(" ", &fields);
 343:     if (strcmp(response[0], "rank") != 0 || fields < 2)
 344:     {
 345:         fprintf(stderr, "\nExpected rank as first line, not %s\n", response[0]);
 346:     }
 347:     rank = atoi(response[1]);
 348:     response = split_stdin(" ", &fields);
 349:     if (strcmp(response[0], "seed") != 0 || fields < 2)
 350:     {
 351:         fprintf(stderr, "\nExpected seed as second line, not %s\n", response[0]);
 352:     }
 353:     seed = atoi(response[1]);
 354: #endif
 355: 
 356:     /* read in initial state */
 357:     initial_state = freecell_alloc();
 358:     for (c = 0; c < NCOLUMNS; c++)
 359:     {
 360:         response = split_stdin(" ", &fields);
 361:         for (r = 0; r < fields; r++)
 362:         {
 363:             i = parseCard(response[r]);
 364:             if (i < 0 && (c < NSUITS || r < NCOLUMNS))
 365:             {
 366:                 fprintf(stderr, "\nInvalid card: %s\n", response[r]);
 367:                 exit(1);
 368:             }
 369:             initial_state->column[c][r] = i;
 370:             //fprintf(stderr, "Col[%d][%d] = %d\n", c, r, i);
 371: #ifndef UNIX
 372:             fprintf(htmlFile, "  setCard('col', %d, %d, '%s');\n",
 373:                 c+1, r+1, response[r]);
 374: #endif
 375:         }
 376:         initial_state->collen[c] = fields;
 377:         free_split_stdin(response, fields);
 378:     }
 379: #ifndef UNIX
 380:     fprintf(htmlFile, "\n");
 381: #endif
 382: 
 383:     /* additional initialization */
 384:     states_visited = 0;
 385:     fns.expandfn = (cheat ? freecell_expand_cheat : freecell_expand);
 386:     fns.freefn = freecell_free;
 387:     fns.goalfn = freecell_goal;
 388:     fns.equalfn = freecell_equal;
 389:     fns.costfn = (cheat ? freecell_edge_cheat : freecell_edge);
 390: 
 391:     /* find a solution path and print out statistics */
 392:     start = clock();
 393:     switch (heur)
 394:     {
 395:     case 0:
 396:     default:
 397:         fns.heuristicfn = NULL;
 398:         solution_path = idsearch(initial_state, fns);
 399:         break;
 400:     case 1:
 401:         fns.heuristicfn = freecell_heuristic1;
 402:         solution_path = idastar(initial_state, fns);
 403:         break;
 404:     case 2:
 405:         fns.heuristicfn = freecell_heuristic2;
 406:         solution_path = idastar(initial_state, fns);
 407:         break;
 408:     }
 409:     finish = clock();
 410:     elapsed = (finish - start) / (float)CLOCKS_PER_SEC;
 411: 
 412:     printf("user states visited = %d.\n", states_visited);
 413:     printf("user %g seconds used.\n", elapsed);
 414: 
 415:     /* follow solution path */
 416: 
 417:     if (NULL != solution_path)
 418:     {
 419:         for (len1 = 0; solution_path[len1] != NULL; len1++);
 420:         printf("user Solution part 1 of length %d found!\n", len1 - 1);
 421: 
 422:         for (i = 1; i < len1; i++)
 423:         {
 424:             if (!showMove(heur, solution_path[i-1], solution_path[i])) break;
 425:         }
 426: 
 427:         /* Now lets do a little depth first search to complete the solution */
 428:         fns.goalfn = freecell_perfect;
 429:         winnable_state = solution_path[len1-1];
 430:         // Just let it do random moves, they all lead to a solution
 431:         // Cannot do a losing move now, but can do plenty of wasteful moves
 432:         solution_path = dfsearch(winnable_state, winnable_state, 1000, fns);
 433: 
 434:         for (len2 = 0; solution_path[len2] != NULL; len2++);
 435:         printf("user Solution part 2 of length %d found!\n", len2 - 1);
 436: 
 437:         for (i = 1; i < len2; i++)
 438:         {
 439:             if (!showMove(0, solution_path[i-1], solution_path[i])) break;
 440:         }
 441:     }
 442:     else
 443:     {
 444:         printf("user No solution found!\n");
 445: 
 446:         printf("x\n");  // Quit
 447:         fflush(stdout);
 448: 
 449:         // Wait for "quit" message from freecell program
 450:         response = split_stdin(" ", &fields);
 451:         free_split_stdin(response, fields);
 452:         status = 1;    // Failed to find a solution
 453:     }
 454: 
 455: #ifndef UNIX
 456:     /* Open file to write a log entry */
 457:     if (fopen_s(&logFile, "lab1.csv", "a") != 0)
 458:     {
 459:         fprintf(stderr, "\nUnable to write to lab1.csv\n");
 460:     }
 461:     // Cheat, Heur, Rank, Seed, FoundIt, Steps1, Steps2, StatesVisited, Elapsed
 462:     fprintf(logFile, "%d, %d, %d, %d, %s, %d, %d, %d, %.3f\n",
 463:         cheat, heur, rank, seed, solution_path==NULL ? "false" : "true",
 464:         len1, len2, states_visited, elapsed);
 465:     fclose(logFile);
 466: #endif
 467: 
 468: #ifndef UNIX
 469:     fclose(htmlFile);
 470: #endif
 471: 
 472:     exit(status);
 473: }
 474: 

src/state.c - Generates moves, etc

   1: #include <stdlib.h>
   2: #include <stdio.h>
   3: 
   4: #include "../inc/state.h"
   5: 
   6: #define SHOW_POSSIBLE_MOVES 0   // For debugging
   7: 
   8: #define MAXMOVES 100
   9: 
  10: char displayRank(int c)
  11: {
  12:     int rank;
  13: 
  14:     rank = RANK(c);
  15:     switch (rank)
  16:     {
  17:     case 1 : return 'A';
  18:     case 2 : return '2';
  19:     case 3 : return '3';
  20:     case 4 : return '4';
  21:     case 5 : return '5';
  22:     case 6 : return '6';
  23:     case 7 : return '7';
  24:     case 8 : return '8';
  25:     case 9 : return '9';
  26:     case 10 : return 'T';
  27:     case 11 : return 'J';
  28:     case 12 : return 'Q';
  29:     case 13 : return 'K';
  30:     }
  31:     return '?';
  32: }
  33: 
  34: char displaySuit(int c)
  35: {
  36:     int suit;
  37: 
  38:     suit = SUIT(c);
  39:     switch (suit)
  40:     {
  41:     case 0 : return 'S';
  42:     case 1 : return 'h';
  43:     case 2 : return 'C';
  44:     case 3 : return 'd';
  45:     }
  46:     return '?';
  47: }
  48: 
  49: /* Allocate space for a dice cover state,
  50: * but do not properly initialize the space.
  51: */
  52: 
  53: State freecell_alloc()
  54: {
  55:     int i, j;
  56:     State S;
  57: 
  58:     S = (State) malloc(sizeof(struct layout));
  59: 
  60:     for (i = 0; i < NSUITS; i++) S->hcell[i] = 0;
  61:     for (i = 0; i < NFREECELLS; i++) S->fcell[i] = -1;
  62:     for (i = 0; i < NCOLUMNS; i++)
  63:     {
  64:         for (j = 0; j < LONGEST_COLUMN; j++)
  65:         {
  66:             S->column[i][j] = -1;
  67:         }
  68:         S->collen[i] = 0;
  69:     }
  70: 
  71:     return S;
  72: }
  73: 
  74: 
  75: /* Return a copy of the state.
  76: * This is how all states, except for the initial state, should be allocated.
  77: */
  78: 
  79: State freecell_copy(State S)
  80: {
  81:     int i, j;
  82:     State newcopy;
  83: 
  84:     newcopy = freecell_alloc();
  85:     for (i = 0; i < NFREECELLS; i++)
  86:     {
  87:         newcopy->fcell[i] = S->fcell[i];
  88:     }
  89:     for (i = 0; i < NSUITS; i++)
  90:     {
  91:         newcopy->hcell[i] = S->hcell[i];
  92:     }
  93:     for (i = 0; i < NCOLUMNS; i++)
  94:     {
  95:         for (j = 0; j < LONGEST_COLUMN; j++)
  96:         {
  97:             newcopy->column[i][j] = S->column[i][j];
  98:         }
  99:         newcopy->collen[i] = S->collen[i];
 100:     }
 101:     
 102:     return newcopy;
 103: }
 104: 
 105: 
 106: /* Free the space used by a state. */
 107: void freecell_free (State S)
 108: {
 109:     free(S);
 110: }
 111: 
 112: // Find all possible moves
 113: State *freecell_expand_shared(State S, int cheat)
 114: {
 115:     int i, j, k, l;
 116:     int c, c2;
 117:     int numStates;
 118:     State *states;
 119:     State newState;
 120: 
 121:     // Force a NULL at the end of the list
 122:     states = (State *) calloc (MAXMOVES, sizeof(State));
 123:     for (i = 0; i < MAXMOVES; i++) states[i] = NULL;
 124: 
 125:     numStates = 0;
 126: 
 127:     if (SHOW_POSSIBLE_MOVES)
 128:     {
 129:         fprintf(stderr, "\n**** Looking for moves\n");
 130:     }
 131: 
 132:     // Can we move anything up to the home cells?
 133:     for (i = 0; i < NSUITS; i++)
 134:     {
 135:         for (j = 0; j < NCOLUMNS; j++)
 136:         {
 137:             k = S->collen[j];
 138:             if (k > 0)
 139:             {
 140:                 c = S->column[j][k-1];
 141:                 if (SUIT(c) == i && RANK(c) == (S->hcell[i] + 1))
 142:                 {
 143:                     // Yes, we can move a card from columns to home
 144:                     newState = freecell_copy(S);
 145:                     states[numStates] = newState;
 146:                     (newState->hcell[i])++;
 147:                     newState->column[j][k-1] = -1;
 148:                     newState->collen[j]--;
 149:                     numStates++;
 150: 
 151:                     if (SHOW_POSSIBLE_MOVES)
 152:                     {
 153:                         fprintf(stderr, "**** Move %c%c from column %d to Home\n",
 154:                             displayRank(c), displaySuit(c), j+1);
 155:                     }
 156: 
 157:                     if (cheat) return states;
 158:                 }
 159:             }
 160:         }
 161:     }
 162: 
 163:     // Can we move from free cells to the home cells?
 164:     for (i = 0; i < NSUITS; i++)
 165:     {
 166:         for (j = 0; j < NFREECELLS; j++)
 167:         {
 168:             c = S->fcell[j];
 169:             if (!NULLCARD(c) && SUIT(c) == i && RANK(c) == (S->hcell[i] + 1))
 170:             {
 171:                 // Yes, we can move a card from free cells to home
 172:                 newState = freecell_copy(S);
 173:                 states[numStates] = newState;
 174:                 (newState->hcell[i])++;
 175:                 newState->fcell[j] = -1;
 176:                 numStates++;
 177: 
 178:                 if (SHOW_POSSIBLE_MOVES)
 179:                 {
 180:                     fprintf(stderr, "**** Move %c%c from %c to Home\n",
 181:                         displayRank(c), displaySuit(c), 'A'+i);
 182:                 }
 183: 
 184:                 if (cheat) return states;
 185:             }
 186:         }
 187:     }
 188: 
 189:     // Can we move anything up to the free cells?
 190:     for (i = 0; i < NFREECELLS; i++)
 191:     {
 192:         if (NULLCARD(S->fcell[i]))
 193:         {
 194:             for (j = 0; j < NCOLUMNS; j++)
 195:             {
 196:                 k = S->collen[j];
 197:                 if (k > 1)      // Don't bother if there is only card in column
 198:                 {
 199:                     // Yes, we can move a card from columns to free cell
 200:                     newState = freecell_copy(S);
 201:                     states[numStates] = newState;
 202:                     c = S->column[j][k-1];
 203:                     newState->fcell[i] = c;
 204:                     newState->column[j][k-1] = -1;
 205:                     newState->collen[j]--;
 206:                     numStates++;
 207: 
 208:                     if (SHOW_POSSIBLE_MOVES)
 209:                     {
 210:                         fprintf(stderr, "**** Move %c%c from column %d to freecell %c\n",
 211:                             displayRank(c), displaySuit(c), j+1, 'A'+i);
 212:                     }
 213:                 }
 214:             }
 215: 
 216:             break;  // One freecell is enough
 217:         }
 218:     }
 219: 
 220:     // Can we move anything from one column to another?
 221:     for (i = 0; i < NCOLUMNS; i++)
 222:     {
 223:         j = S->collen[i];
 224:         if (j+1 < LONGEST_COLUMN)
 225:         {
 226:             if (j == 0)
 227:             {
 228:                 c = -1;     // Destination column is empty
 229:             }
 230:             else
 231:             {
 232:                 c = S->column[i][j-1];
 233:             }
 234: 
 235:             for (k = 1; k < NCOLUMNS; k++)
 236:             {
 237:                 if (i == k) continue;   // Can't move to itself
 238: 
 239:                 l = S->collen[k];
 240:                 if (l > 0)
 241:                 {
 242:                     c2 = S->column[k][l-1];
 243:                     if (c == -1 || (COLOR(c) != COLOR(c2) && RANK(c) == (RANK(c2) + 1)))
 244:                     {
 245:                         // Yes, we can move a card between columns
 246:                         newState = freecell_copy(S);
 247:                         states[numStates] = newState;
 248:                         newState->column[i][j] = c2;
 249:                         newState->column[k][l-1] = -1;
 250:                         newState->collen[i]++;
 251:                         newState->collen[k]--;
 252:                         numStates++;
 253: 
 254:                         if (SHOW_POSSIBLE_MOVES)
 255:                         {
 256:                             fprintf(stderr, "**** Move %c%c from column %d to column %d\n",
 257:                                 displayRank(c2), displaySuit(c2), k+1, i+1);
 258:                         }
 259:                     }
 260:                 }
 261:             }
 262:         }
 263:     }
 264: 
 265:     if (numStates >= MAXMOVES)
 266:     {
 267:         fprintf(stderr, "**** Too many possible states. Limit is %d\n", MAXMOVES);
 268:         return 0;
 269:     }
 270: 
 271:     return states;
 272: }
 273: 
 274: // Find all possible moves
 275: State *freecell_expand(State S)
 276: {
 277:     return freecell_expand_shared(S, 0);
 278: }
 279: 
 280: // Cheat: If can move a card to home, force it
 281: // Might be sub-optimal but sure is faster!
 282: State *freecell_expand_cheat(State S)
 283: {
 284:     return freecell_expand_shared(S, 1);
 285: }
 286: 
 287: // Many goal states exist
 288: int freecell_goal(State S)
 289: {
 290:     int i, j;
 291:     int c, c2;
 292: 
 293:     state_visited();
 294: 
 295:     // Fail if cells are NOT in nice order in any column
 296:     for (i = 0; i < NCOLUMNS; i++)
 297:     {
 298:         for (j = 1; j < S->collen[i]; j++)    // Don't bother with 0
 299:         {
 300:             c = S->column[i][j];
 301:             c2 = S->column[i][j-1];
 302:             if (RANK(c2) < (RANK(c)))
 303:             {
 304:                 return 0;   // Darn, something is out of order
 305:             }
 306:         }
 307:     }
 308:     return 1;   // Good shape, easy to complete!
 309: }
 310: 
 311: // Only one perfect state exists
 312: int freecell_perfect(State S)
 313: {
 314:     int i;
 315: 
 316:     state_visited();
 317: 
 318:     // Fail if cards in free cells or columns
 319:     for (i = 0; i < NFREECELLS; i++)
 320:     {
 321:         if (!NULLCARD(S->fcell[i])) return 0;
 322:     }
 323:     for (i = 0; i < NCOLUMNS; i++)
 324:     {
 325:         if (S->collen[i] > 0) return 0;
 326:     }
 327:     return 1;   // Perfect!
 328: }
 329: 
 330: // Estimate distance from S to goal state
 331: int freecell_heuristic1(State S)
 332: {
 333:     int i;
 334:     int distance;
 335: 
 336:     // Just count cards on the table
 337:     distance = 0;
 338:     for (i = 0; i < NCOLUMNS; i++) distance += S->collen[i];
 339:     for (i = 0; i < NFREECELLS; i++)
 340:     {
 341:         if (!NULLCARD(S->fcell[i])) distance++;
 342:     }
 343: 
 344:     // fprintf(stderr, "**** Distance = %d\n", distance);
 345:     return distance;
 346: }
 347: 
 348: // Estimate distance from S to goal state
 349: int freecell_heuristic2(State S)
 350: {
 351:     int i, j;
 352:     int c, c2;
 353:     int distance;
 354: 
 355:     // Add distance if cells are in bad order in the columns
 356:     distance = 0;
 357:     for (i = 0; i < NCOLUMNS; i++)
 358:     {
 359:         for (j = 1; j < S->collen[i]; j++)    // Don't bother with 0
 360:         {
 361:             c = S->column[i][j];
 362:             c2 = S->column[i][j-1];
 363:             if (RANK(c2) < RANK(c))
 364:             {
 365:                 // Number of cards on top of this bad pair, including this one
 366:                 distance += (S->collen[i] - j);
 367:                 break;  // Just one distance per column
 368:             }
 369:         }
 370:     }
 371: 
 372:     // fprintf(stderr, "**** Distance = %d\n", distance);
 373:     return distance;
 374: }
 375: 
 376: // This heuristic is inadmissable -- way over-estimates #moves
 377: int freecell_heuristic999(State S)
 378: {
 379:     int i, j;
 380:     int c, c2;
 381:     int distance;
 382:     int PENALTY = 10;   // For out-of-order cards
 383:     int BONUS = 3;      // For each empty free cell
 384: 
 385:     // Add distance if cells are in bad order in the columns
 386:     distance = 0;
 387:     for (i = 0; i < NCOLUMNS; i++)
 388:     {
 389:         distance += S->collen[i];
 390:         for (j = 1; j < S->collen[i]; j++)    // Don't bother with 0
 391:         {
 392:             c = S->column[i][j];
 393:             c2 = S->column[i][j-1];
 394:             if (RANK(c2) < RANK(c))
 395:             {
 396:                 // Number of cards on top of this bad pair, including this one
 397:                 distance += PENALTY * (S->collen[i] - j);
 398:             }
 399:         }
 400:     }
 401: 
 402:     // Take away from distance if there are empty free cells
 403:     for (i = 0; i < NFREECELLS; i++)
 404:     {
 405:         if (NULLCARD(S->fcell[i])) distance -= BONUS;
 406:     }
 407:     if (distance < 1) distance = 1;
 408: 
 409:     // fprintf(stderr, "**** Distance = %d\n", distance);
 410:     return distance;
 411: }
 412: 
 413: int freecell_equal(State S1, State S2)
 414: {
 415:     int i, j;
 416: 
 417:     if (S1 == NULL && S2 == NULL) return 1;
 418:     if (S1 == NULL || S2 == NULL) return 0;
 419: 
 420:     // Check the free cells first
 421:     for (i = 0; i < NFREECELLS; i++)
 422:     {
 423:         if (S1->fcell[i] != S2->fcell[i]) return 0;
 424:     }
 425: 
 426:     // Maybe the home cells are different
 427:     for (i = 0; i < NSUITS; i++)
 428:     {
 429:         if (S1->hcell[i] != S2->hcell[i]) return 0;
 430:     }
 431: 
 432:     // See if the columns differ
 433:     for (i = 0; i < NFREECELLS; i++)
 434:     {
 435:         for (j = 0; j < LONGEST_COLUMN; j++)
 436:         {
 437:             if (S1->column[i][j] != S2->column[i][j]) return 0;
 438:         }
 439:     }
 440: 
 441:     // They are identical
 442:     return 1;
 443: }
 444: 
 445: // This assumes that S1 and S2 are exactly one move apart ...
 446: // If not, this function is the entire solver !!
 447: int freecell_edge(State S1, State S2)
 448: {
 449:     return 1;
 450: }
 451: 
 452: // Cheat: Zero cost for moving cards to Home Cells!
 453: int freecell_edge_cheat(State S1, State S2)
 454: {
 455:     int i;
 456:     
 457:     // If added something to home, cost is zero
 458:     for (i = 0; i < NSUITS; i++)
 459:     {
 460:         if (S2->hcell[i] > S1->hcell[i]) return 0;
 461:     }
 462: 
 463:     return 1;
 464: }
 465: 

inc/state.h - header file

   1: #ifndef STATE_H
   2: #define STATE_H
   3: 
   4: /* The cards are specified by integers 0 to 51.  -1 specifies no card
   5: * in that location.  The aces are integers 0 to 3, twos are from 4 to
   6: * 7, etc.  If x is a card, then x % 4 == 0, 1, 2, or 3 respectively
   7: * indicates a spade, heart, club, or diamond.  Thus 1 + x/4 computes
   8: * the rank of a card, and x % 4, its suit, and x % 2, its color.
   9: */
  10: 
  11: #define NULLCARD(x) ((x) == -1)
  12: #define RANK(x) (1 + (x)/4)
  13: #define SUIT(x) ((x)%4)
  14: #define COLOR(x) ((x)%2)
  15: 
  16: #define NSUITS 4
  17: #define NFREECELLS 4
  18: #define NCOLUMNS 8
  19: #define LONGEST_COLUMN 20
  20: #define HIGHEST_RANK 13
  21: 
  22: /* The game area has free cells, home cells, and columns. */
  23: 
  24: typedef struct layout {
  25:     int fcell[NFREECELLS];			/* The 4 free cells */
  26:     int hcell[NSUITS];	        /* The top home cell card for each suit */
  27:     int column[NCOLUMNS][LONGEST_COLUMN];		/* The 8 columns  */
  28:     int collen[NCOLUMNS];
  29: } *State;
  30: 
  31: char displayRank(int c);
  32: char displaySuit(int c);
  33: 
  34: 
  35: /* This function should allocate space for a dice cover state,
  36: * but does not need to properly initialize the space.
  37: */
  38: 
  39: State freecell_alloc();
  40: 
  41: 
  42: /* This function should return a copy of the state.
  43: * This is how all states, except for the initial state, should be allocated.
  44: */
  45: 
  46: State freecell_copy(State S);
  47: 
  48: 
  49: /* This function should free the space used by a state. */
  50: 
  51: void freecell_free (State S);
  52: 
  53: // Note: Cheating means moving cards to home whenever possible
  54: // and changing cost to zero for moving them home
  55: State *freecell_expand(State S);
  56: State *freecell_expand_cheat(State S);
  57: int freecell_goal(State S);           // Are all the cards in nice order?
  58: int freecell_perfect(State S);        // Is it completely solved?
  59: int freecell_heuristic1(State S);   // How far from goal state are we?
  60: int freecell_heuristic2(State S);   // Little better algorithm
  61: int freecell_equal(State S1, State S2);
  62: int freecell_edge(State S1, State S2);
  63: int freecell_edge_cheat(State S1, State S2);
  64: 
  65: void state_visited();
  66: 
  67: #endif
  68: 

src/split_stdin.c - Line reader

   1: #include <stdio.h>
   2: #include <stdlib.h>
   3: #include <string.h>
   4: 
   5: #include "../inc/split_stdin.h"
   6: 
   7: /* splits a line from stdin into several strings.
   8: * A line is assumed to consist of several fields separated by
   9: * characters from separators.
  10: * num_fields is set to the number of strings.
  11: * num_fields is -1 if EOF before any strings are found.
  12: */
  13: 
  14: char **split_stdin(char *separators, int *num_fields) {
  15:     int c, nfields, nchars, clen, flen;
  16:     char *current;
  17:     char **fields;
  18:     current = (char *) calloc(10, sizeof(char));
  19:     clen = 10;
  20:     nchars = 0;
  21:     fields = (char **) calloc(10, sizeof(char *));
  22:     flen = 10;
  23:     nfields = 0;
  24:     do {
  25:         c = getc(stdin);
  26:         if (NULL == strchr(separators,c) && '\n' != c && EOF != c) {
  27:             if (nchars == clen) {
  28:                 clen += clen;
  29:                 current = (char *) realloc(current, clen * sizeof(char));
  30:             }
  31:             current[nchars] = c;
  32:             nchars++;
  33:         }
  34:         else if (nchars > 0) {
  35:             current = (char *) realloc(current, (nchars+1) * sizeof(char));
  36:             current[nchars] = '\0';
  37:             if (nfields == flen) {
  38:                 flen += flen;
  39:                 fields = (char **) realloc(fields, flen * sizeof(char *));
  40:             }
  41:             fields[nfields] = current;
  42:             nfields++;
  43:             current = (char *) calloc(10, sizeof(char));
  44:             clen = 10;
  45:             nchars = 0;
  46:         }
  47:     }
  48:     while ('\n' != c && EOF != c);
  49: 
  50:     free(current);
  51:     fields = (char **) realloc(fields, nfields * sizeof(char *));
  52:     if (EOF == c && nfields == 0) nfields = -1;
  53:     *num_fields = nfields;
  54:     return fields;
  55: }
  56: 
  57: /* Free up memory allocated by by split_stdin.
  58: * response is the data returned by a call to split_stdin.
  59: * num_fields is the number of strings in response.
  60: */
  61: 
  62: void free_split_stdin(char **response, int num_fields) {
  63:     int i;
  64:     for (i = 0; i < num_fields; i++) free(response[i]);
  65:     free(response);
  66: }
  67: 

inc/split_stdin.h - header file

   1: /* split_stdin.h */
   2: 
   3: char **split_stdin(char *separators, int *num_fields);
   4: 
   5: void free_split_stdin(char **response, int num_fields);
   6: 

src/idastar.c - Iterative Deepening Search

   1: #include <limits.h>
   2: #include <stdio.h>
   3: #include <time.h>
   4: #include <stdlib.h>
   5: 
   6: #include "../inc/state.h"
   7: #include "../inc/idastar.h"
   8: 
   9: /* dfs_contour implements the depth-limited search needed by idastar.
  10: */
  11: 
  12: State *dfs_contour(State current_state, State parent_state,
  13:                    int g_cost, int f_limit, int *next_f,
  14:                    struct statefns fns)
  15: {
  16:     int f_cost;
  17:     int i, j, len;
  18:     State *solution_path;
  19:     State *successors;
  20:     f_cost = g_cost + (* fns.heuristicfn)(current_state);
  21:     //fprintf(stderr, "@@@@@@@ f=%d g=%d limit=%d\n", f_cost-g_cost, g_cost, f_limit);
  22: 
  23:     if (f_cost > f_limit) {
  24:         if (f_cost < *next_f) *next_f = f_cost;
  25:         return NULL;
  26:     }
  27:     if ((* fns.goalfn)(current_state)) {
  28:         solution_path = (State *) calloc(2, sizeof(State));
  29:         solution_path[0] = current_state;
  30:         solution_path[1] = NULL;
  31:         return solution_path;
  32:     }
  33: 
  34:     successors = (* fns.expandfn)(current_state);
  35:     for (i = 0; successors[i] != NULL; i++) {
  36:         //printf("user i=%d g_cost=%d\n", i, g_cost); fflush(stdout);
  37: 
  38:         /* parent check */
  39:         if (! (* fns.equalfn)(parent_state, successors[i])) {
  40:             solution_path = dfs_contour(successors[i], current_state,
  41:                 g_cost + (* fns.costfn)(current_state, successors[i]), // WHY +1 here? Removed it ...
  42:                 f_limit, next_f, fns);
  43:             if (NULL != solution_path) {
  44:                 /* Add current_state to solution_path and return solution_path */
  45:                 for (len = 0; solution_path[len] != NULL; len++);
  46:                 for (j = len; j > 0; j--) solution_path[j] = solution_path[j-1];
  47:                 solution_path[0] = current_state;
  48:                 solution_path =
  49:                     (State *) realloc(solution_path, (len+2)*sizeof(State));
  50:                 solution_path[len+1] = NULL;
  51:                 for (j = 0; successors[j] != NULL; j++)
  52:                     if (j != i) (* fns.freefn)(successors[j]);
  53:                 free(successors);
  54:                 return solution_path;
  55:             }
  56:         }
  57:     }
  58: 
  59:     /* Have to free memory or else we'll run out. */
  60:     for (i = 0; successors[i] != NULL; i++)
  61:         (* fns.freefn)(successors[i]);
  62:     free(successors);
  63:     return NULL;
  64: }
  65: 
  66: 
  67: /* idastar returns a path from the initial state to a goal state or
  68: * NULL if it times out (more than TIMEOUT seconds) or runs out of
  69: * states to search.
  70: */
  71: 
  72: State *idastar(State initial_state, struct statefns fns) {
  73:     clock_t start_time;
  74:     int f_limit, next_f;
  75:     State *solution_path;
  76:     float elapsed_seconds;
  77: 
  78:     start_time = clock();
  79:     f_limit = (* fns.heuristicfn)(initial_state);
  80:     for (;;) {
  81:         next_f = INT_MAX;
  82:         solution_path = dfs_contour(initial_state, initial_state,
  83:             0, f_limit, &next_f, fns);
  84:         elapsed_seconds = (clock() - start_time)/(float)CLOCKS_PER_SEC;
  85: 
  86:         fprintf(stderr, "**** Contour depth = %d  Elapsed time = %.3f seconds\n",
  87:             next_f, elapsed_seconds);
  88:         fflush(stderr);
  89: 
  90:         if (NULL != solution_path) return solution_path;
  91:         if (next_f == INT_MAX) return NULL;
  92:         if (TIMEOUT <= elapsed_seconds) return NULL;
  93:         f_limit = next_f;
  94:     }
  95: }
  96: 
  97: 
  98: 
  99: /* dfsearch implements the depth-limited search needed by idsearch.
 100: */
 101: 
 102: State *dfsearch(State current_state, State parent_state,
 103:                 int depth, struct statefns fns)
 104: {
 105:     int i, j, len;
 106:     State *solution_path;
 107:     State *successors;
 108: 
 109:     if ((* fns.goalfn)(current_state)) {
 110:         solution_path = (State *) calloc(2, sizeof(State));
 111:         solution_path[0] = current_state;
 112:         solution_path[1] = NULL;
 113:         return solution_path;
 114:     }
 115: 
 116:     if (depth <= 0) return NULL;
 117: 
 118:     successors = (* fns.expandfn)(current_state);
 119:     for (i = 0; successors[i] != NULL; i++) {
 120:         /* parent check */
 121:         if (! (* fns.equalfn)(parent_state, successors[i])) {
 122:             solution_path = dfsearch(successors[i], current_state, depth - 1, fns);
 123:             if (NULL != solution_path) {
 124:                 /* Add current_state to solution_path and return solution_path */
 125:                 for (len = 0; solution_path[len] != NULL; len++);
 126:                 for (j = len; j > 0; j--) solution_path[j] = solution_path[j-1];
 127:                 solution_path[0] = current_state;
 128:                 solution_path =
 129:                     (State *) realloc(solution_path, (len+2)*sizeof(State));
 130:                 solution_path[len+1] = NULL;
 131:                 for (j = 0; successors[j] != NULL; j++)
 132:                     if (j != i) (* fns.freefn)(successors[j]);
 133:                 free(successors);
 134:                 return solution_path;
 135:             }
 136:         }
 137:     }
 138: 
 139:     /* Have to free memory or else we'll run out. */
 140:     for (i = 0; successors[i] != NULL; i++)
 141:         (* fns.freefn)(successors[i]);
 142:     free(successors);
 143:     return NULL;
 144: }
 145: 
 146: 
 147: /* idsearch returns a path from the initial state to a goal state or
 148: * NULL if it times out (more than TIMEOUT seconds).
 149: */
 150: 
 151: State *idsearch(State initial_state, struct statefns fns) {
 152:     clock_t start_time;
 153:     int depth;
 154:     State *solution_path;
 155: 
 156:     start_time = clock();
 157:     for (depth = 0; ; depth++) {
 158:         solution_path = dfsearch(initial_state, initial_state, depth, fns);
 159:         if (NULL != solution_path) return solution_path;
 160:         if (TIMEOUT <= (clock() - start_time)/CLOCKS_PER_SEC) return NULL;
 161:     }
 162: }
 163: 
 164: 

inc/idastar.h - header file

   1: /* state.h needs to be included before this file 
   2: * because state.h defines the State type.
   3: */
   4: 
   5: 
   6: /* An expand_state function inputs a state and returns an array of states.
   7: * The last element in the array should be set to NULL.
   8: * It should be safe to free the array if it is no longer needed.
   9: * It should be safe to free a state if it is no longer needed.
  10: */
  11: 
  12: typedef State * (* expand_state)(State);
  13: 
  14: 
  15: /* A free_state function frees the space used by the State.
  16: */
  17: 
  18: typedef void (* free_state)(State);
  19: 
  20: 
  21: /* A goal_state function inputs a state and returns true (1)
  22: * if the state is a goal state and false (0) otherwise.
  23: */
  24: 
  25: typedef int (* goal_state)(State);
  26: 
  27: 
  28: /* An equal_states function inputs two states and returns true (1)
  29: * if the two states are equal and false (0) otherwise.
  30: * NULL is a possible value for a State.
  31: */
  32: 
  33: typedef int (* equal_states)(State, State);
  34: 
  35: 
  36: /* A heuristic_state function inputs a state and returns an estimate
  37: * of the distance from the state to a goal state.
  38: */
  39: 
  40: typedef int (* heuristic_state)(State);
  41: 
  42: 
  43: /* An edge_cost function inputs two states and returns the cost of
  44: * moving from the first state to the second state.
  45: */
  46: 
  47: typedef int (* edge_cost)(State, State);
  48: 
  49: 
  50: /* This structure holds the functions we need for heuristic search. */
  51: 
  52: struct statefns {
  53:     expand_state expandfn;
  54:     free_state freefn;
  55:     goal_state goalfn;
  56:     equal_states equalfn;
  57:     heuristic_state heuristicfn;
  58:     edge_cost costfn;
  59: };
  60: 
  61: 
  62: /* dfs_contour implements the depth-limited search needed by idastar.
  63: * It probably would be a bit more efficient if the functions were global
  64: * rather than recursively passed everywhere.
  65: * It probably would be better to do this in an object-oriented
  66: * language.
  67: */
  68: 
  69: State * dfs_contour(State current_state, State parent_state,
  70:                     int g_cost, int f_limit, int *next_f,
  71:                     struct statefns fns);
  72: 
  73: 
  74: #define TIMEOUT 60
  75: 
  76: 
  77: /* idastar returns a path from the initial state to a goal state or
  78: * NULL if it times out (more than TIMEOUT seconds) or runs out of
  79: * states to search.
  80: */
  81: 
  82: State * idastar(State initial_state, struct statefns fns);
  83: 
  84: 
  85: 
  86: /* dfsearch implements the depth-limited search needed by idsearch.
  87: */
  88: 
  89: State * dfsearch(State current_state, State parent_state,
  90:                  int depth, struct statefns fns);
  91: 
  92: 
  93: 
  94: /* idsearch returns a path from the initial state to a goal state or
  95: * NULL if it times out (more than TIMEOUT seconds).
  96: */
  97: 
  98: State *idsearch(State initial_state, struct statefns fns);
  99: 

src/rand.c - Random number generator

   1: /*-------------------------------------------------------------------------
   2: *
   3: * rand.c
   4: *    Missing rand implementations for Win32
   5: *
   6: *-------------------------------------------------------------------------
   7: */
   8: 
   9: #include "../inc/rand.h"
  10: 
  11: /*
  12: * Copyright (c) 1993 Martin Birgmeier
  13: * All rights reserved.
  14: *
  15: * You may redistribute unmodified or modified versions of this source
  16: * code provided that the above copyright notice and this and the
  17: * following conditions are retained.
  18: *
  19: * This software is provided ``as is'', and comes with no warranties
  20: * of any kind. I shall in no event be liable for anything that happens
  21: * to anyone/anything when using this software.
  22: */
  23: #define RAND48_SEED_0   (0x330e)
  24: #define RAND48_SEED_1   (0xabcd)
  25: #define RAND48_SEED_2   (0x1234)
  26: #define RAND48_MULT_0   (0xe66d)
  27: #define RAND48_MULT_1   (0xdeec)
  28: #define RAND48_MULT_2   (0x0005)
  29: #define RAND48_ADD      (0x000b)
  30: 
  31: unsigned short _rand48_seed[3] = {
  32:     RAND48_SEED_0,
  33:     RAND48_SEED_1,
  34:     RAND48_SEED_2
  35: };
  36: unsigned short _rand48_mult[3] = {
  37:     RAND48_MULT_0,
  38:     RAND48_MULT_1,
  39:     RAND48_MULT_2
  40: };
  41: unsigned short _rand48_add = RAND48_ADD;
  42: 
  43: static void
  44: _dorand48(unsigned short xseed[3])
  45: {
  46:     unsigned long accu;
  47:     unsigned short temp[2];
  48: 
  49:     accu = (unsigned long) _rand48_mult[0] * (unsigned long) xseed[0] +
  50:         (unsigned long) _rand48_add;
  51:     temp[0] = (unsigned short) accu;    /* lower 16 bits */
  52:     accu >>= sizeof(unsigned short) * 8;
  53:     accu += (unsigned long) _rand48_mult[0] * (unsigned long) xseed[1] +
  54:         (unsigned long) _rand48_mult[1] * (unsigned long) xseed[0];
  55:     temp[1] = (unsigned short) accu;    /* middle 16 bits */
  56:     accu >>= sizeof(unsigned short) * 8;
  57:     accu += _rand48_mult[0] * xseed[2] + _rand48_mult[1] * xseed[1] + _rand48_mult[2] * xseed[0];
  58:     xseed[0] = temp[0];
  59:     xseed[1] = temp[1];
  60:     xseed[2] = (unsigned short) accu;
  61: }
  62: 
  63: long
  64: lrand48(void)
  65: {
  66:     _dorand48(_rand48_seed);
  67:     return ((long) _rand48_seed[2] << 15) + ((long) _rand48_seed[1] >> 1);
  68: }
  69: 
  70: void
  71: srand48(long seed)
  72: {
  73:     _rand48_seed[0] = RAND48_SEED_0;
  74:     _rand48_seed[1] = (unsigned short) seed;
  75:     _rand48_seed[2] = (unsigned short) (seed > 16);
  76:     _rand48_mult[0] = RAND48_MULT_0;
  77:     _rand48_mult[1] = RAND48_MULT_1;
  78:     _rand48_mult[2] = RAND48_MULT_2;
  79:     _rand48_add = RAND48_ADD;
  80: }
  81: 

inc/rand.h - header file

   1: #ifndef RAND_H
   2: #define RAND_H
   3: 
   4: void srand48(long int seedval);
   5: long int lrand48(void);
   6: 
   7: #endif
   8: 

src/freecell_user.c - Allows person to play the game

   1: /* Simply freecell user interface */
   2: 
   3: #include <stdio.h>
   4: #include <stdlib.h>
   5: #include <string.h>
   6: 
   7: #include "../inc/split_stdin.h"
   8: 
   9: 
  10: int main(int argc, char *argv[]) {
  11:   int num_fields;
  12:   int i;
  13:   char **response;
  14: 
  15:   /* skip 8 lines */
  16:   for (i = 0; i < 8; i++) {
  17:     response = split_stdin(" ", &num_fields);
  18:     free_split_stdin(response, num_fields);
  19:   }
  20: 
  21:   printf("user Enter move:\n"); fflush(stdout);
  22: 
  23:   i = 0;
  24:   for (;;) {
  25:     i++;
  26:     if (i == 1) printf("1f\n");
  27:     else if (i == 2) printf("2f\n");
  28:     else printf("x\n");
  29:     fflush(stdout);
  30: 
  31:     response = split_stdin(" ", &num_fields);
  32:     
  33:     if (num_fields == -1) exit(0);
  34:     else if (num_fields >= 1 && 0 == strcmp("user", response[0])) {
  35:       if (num_fields > 1) {
  36: 	    printf("%s\n", response[1]); fflush(stdout);
  37:       } else {
  38: 	    printf("user Enter move:\n"); fflush(stdout);
  39:       }
  40:     }
  41:     else if (num_fields == 1) {
  42:       if (0 == strcmp("solved",response[0])) {
  43: 	    printf("user You finished the game.  Bye.\n"); fflush(stdout);
  44: 	    exit(0);
  45:       }
  46:       else if (0 == strcmp("illegal",response[0])) {
  47: 	    printf("user Enter a legal move:\n"); fflush(stdout);
  48:       }
  49:       else if (0 == strcmp("quit",response[0])) {
  50: 	    printf("user You told me to quit\n"); fflush(stdout);
  51:         exit(0);
  52:       }
  53:       else {
  54: 	    printf("user Enter a move:\n"); fflush(stdout);
  55:       }
  56:     }
  57: 
  58:     /* free storage used by response */
  59:     free_split_stdin(response, num_fields);
  60:   } 
  61: }
  62: 

src/Interact.java - Manages server and player

   1: /*
   2:  * Created on Aug 26, 2007
   3:  * Steve O'Hara
   4:  */
   5: 
   6: import java.io.InputStream;
   7: 
   8: public class Interact
   9: {
  10:     private final int SLEEP_MS = 50;                // 50 ms = 1/20 of a second
  11:     
  12:     private final int MAX = 1000;
  13:     private byte[] bytes = new byte[MAX+1];
  14: 
  15:     private Process p1 = null;
  16:     private Process p2 = null;
  17: 
  18:     private int read(InputStream stream) throws Exception
  19:     {
  20:         int nc = 0;
  21:         int c;
  22:         while ((c = stream.read()) > 0)
  23:         {
  24:             bytes[nc++] = (byte) c;
  25:             if (nc == MAX || c == '\n') break;
  26:         }
  27:         return nc;
  28:     }
  29: 
  30:     private void prt(String prefix, int nb)
  31:     {
  32:         StringBuffer sb = new StringBuffer();
  33:         for (int i = 0; i < nb; i++) sb.append((char)bytes[i]);
  34:         System.out.print(prefix + sb);
  35:     }
  36: 
  37:     private boolean isUserInput(int nb)
  38:     {
  39:         return (nb >= 4 && bytes[0] == 'u' && bytes[1] == 's' &&
  40:             bytes[2] == 'e' && bytes[3] == 'r');
  41:     }
  42:         
  43:     private int doit(boolean verbose, String pgm1, String pgm2) throws Exception
  44:     {
  45:         Runtime rt = Runtime.getRuntime();
  46:         
  47:         try
  48:         {
  49:             p1 = rt.exec(pgm1);
  50:         }
  51:         catch (Exception ex)
  52:         {
  53:             System.err.println("Unable to run program1 " + pgm1);
  54:             p1 = null;
  55:             return 1;
  56:         }
  57: 
  58:         try
  59:         {
  60:             p2 = rt.exec(pgm2);
  61:         }
  62:         catch (Exception ex)
  63:         {
  64:             System.err.println("Unable to run program2 " + pgm2);
  65:             p1.destroy();
  66:             p1 = null;
  67:             p2 = null;
  68:             return 2;
  69:         }
  70:         
  71:         boolean ok1 = true;
  72:         boolean ok2 = true;
  73:         while (ok1 || ok2)
  74:         {
  75:             if (p1 == null) ok1 = false;
  76:             else if (p2 == null) ok2 = false;
  77:             
  78:             // See if process 1 had anything on stderr
  79:             else if (ok1 && p1.getErrorStream().available() > 0)
  80:             {
  81:                 int nc1 = read(p1.getErrorStream());
  82:                 if (nc1 < 0) ok1 = false;
  83:                 prt("", nc1);
  84:             }
  85:             
  86:             // See if process 2 had anything on stderr
  87:             else if (ok2 && p2.getErrorStream().available() > 0)
  88:             {
  89:                 int nc2 = read(p2.getErrorStream());
  90:                 if (nc2 < 0) ok2 = false;
  91:                 prt("", nc2);
  92:             }
  93:             
  94:             // See if process 1 had anything on stdout, send it to process 2
  95:             else if (ok1 && p1.getInputStream().available() > 0)
  96:             {
  97:                 int nc1 = read(p1.getInputStream());
  98:                 if (nc1 < 0)
  99:                 {
 100:                     ok1 = false;
 101:                 }
 102:                 else if (isUserInput(nc1))
 103:                 {
 104:                     prt("", nc1);
 105:                 }
 106:                 else
 107:                 {
 108:                     if (verbose) prt("**** p1->p2: ", nc1);
 109:                     p2.getOutputStream().write(bytes, 0, nc1);
 110:                     p2.getOutputStream().flush();
 111:                 }
 112:             }
 113: 
 114:             // See if process 2 had anything on stdout, send it to process 1
 115:             else if (ok2 && p2.getInputStream().available() > 0)
 116:             {
 117:                 int nc2 = read(p2.getInputStream());
 118:                 if (nc2 < 0)
 119:                 {
 120:                     ok2 = false;
 121:                 }
 122:                 else if (isUserInput(nc2))
 123:                 {
 124:                     prt("", nc2);
 125:                 }
 126:                 else
 127:                 {
 128:                     if (verbose) prt("**** p2->p1: ", nc2);
 129:                     p1.getOutputStream().write(bytes, 0, nc2);
 130:                     p1.getOutputStream().flush();
 131:                 }
 132:             }
 133: 
 134:             else    // Nothing happening!
 135:             {
 136:                 boolean done = true;
 137:                 int ret1 = 0;
 138:                 int ret2 = 0;
 139:                 try
 140:                 {
 141:                     ret1 = p1.exitValue();
 142:                     ret2 = p2.exitValue();
 143:                 }
 144:                 catch (IllegalThreadStateException ex)
 145:                 {
 146:                     done = false;
 147:                 }
 148:                 
 149:                 if (done)
 150:                 {
 151:                     System.out.println("Process 1 exit code = " + ret1 + " for \"" + pgm1 + "\"");
 152:                     System.out.println("Process 2 exit code = " + ret2 + " for \"" + pgm2 + "\"");
 153:                     return 0;
 154:                 }
 155:                 
 156:                 Thread.sleep(SLEEP_MS);    // Take a break for a few ms
 157:             }
 158:         }
 159: 
 160:         return 0;
 161: 	}
 162: 
 163:     // If they hit control-c, be nice about it and kill the sub-processes
 164:     private static class Quitter extends Thread
 165:     {
 166:         Interact main;
 167:         
 168:         Quitter(Interact intr)
 169:         {
 170:             main = intr;
 171:         }
 172:         
 173:         public void run()
 174:         {
 175:             if (main.p1 != null)
 176:             {
 177:                 main.p1.destroy();
 178:                 main.p1 = null;
 179:             }
 180:             if (main.p2 != null)
 181:             {
 182:                 main.p2.destroy();
 183:                 main.p2 = null;
 184:             }
 185:         }
 186:     }
 187:     
 188:     public static void main(String[] args)
 189:     {
 190:         Interact intr = new Interact();
 191:         Quitter quitter = new Quitter(intr);
 192: 
 193:         Runtime.getRuntime().addShutdownHook(quitter);     
 194:         try
 195:         {
 196:             int indx = 0;
 197:             boolean verbose = false;
 198:             if (args[indx].equals("-v"))
 199:             {
 200:                 verbose = true;
 201:                 indx++;
 202:             }
 203: 
 204:             String program1 = args[indx++];
 205:             String program2 = args[indx++];
 206: 
 207:             int ret = intr.doit(verbose, program1, program2);
 208:             intr.p1 = null;
 209:             intr.p2 = null;
 210:             System.exit(ret);
 211:         }
 212:         catch (Exception ex)
 213:         {
 214:             ex.printStackTrace();
 215:             System.exit(1);
 216:         }        
 217:     }
 218: }
 219: 

freecell.bat - How to compile and run

   1: @gcc src\freecell.c src\rand.c src\split_stdin.c src\state.c -o bin\freecell
   2: @gcc src\freecell_solver.c src\idastar.c src\split_stdin.c src\state.c -o bin\freecell_solver
   3: 
   4: @echo Starting at %TIME%
   5: @java -classpath bin Interact -v "bin\freecell.exe -v -r 13 -s 1189379139" "bin\freecell_solver.exe -c -h 2"
   6: @echo Finished at %TIME%
   7: 

freecell.out - Sample detailed output

   1: Starting at 23:39:02.98
   2: 
   3: **** Forcing seed = 1189379139
   4:     free cells(A-D):  --  --  --  --    home cells(H):  --  --  --  --
   5: 
   6:     columns(1-8):  Th  8C  JS  2C  5S  Kh  8d  QC
   7:                    9C  5h  4d  6h  7d  KC  2h  7C
   8:                    4S  TS  8S  Qh  9h  6S  2S  AC
   9:                    2d  4C  4h  8h  3S  9S  7S  6C
  10:                    9d  Qd  TC  Ad  Td  QS  JC  6d
  11:                    Jd  5d  Jh  AS  3C  KS  5C  3h
  12:                    3d  7h  Ah  Kd                
  13:                                                  
  14: 
  15: **** Using idastar with heuristic 2
  16: **** p1->p2: rank 13
  17: **** p1->p2: seed 1189379139
  18: **** p1->p2: Th 9C 4S 2d 9d Jd 3d
  19: **** p1->p2: 8C 5h TS 4C Qd 5d 7h
  20: **** p1->p2: JS 4d 8S 4h TC Jh Ah
  21: **** p1->p2: 2C 6h Qh 8h Ad AS Kd
  22: **** p1->p2: 5S 7d 9h 3S Td 3C
  23: **** p1->p2: Kh KC 6S 9S QS KS
  24: **** p1->p2: 8d 2h 2S 7S JC 5C
  25: **** p1->p2: QC 7C AC 6C 6d 3h
  26: **** Contour depth = 34  Elapsed time = 1.703 seconds
  27: **** Contour depth = 35  Elapsed time = 1.703 seconds
  28: user states visited = 76777.
  29: user 1.703 seconds used.
  30: user Solution part 1 of length 69 found!
  31: user Move Ah from column 3 to Home, Heuristic2 = 32
  32: **** p2->p1: 3H
  33:     free cells(A-D):  --  --  --  --    home cells(H):  --  Ah  --  --
  34: 
  35:     columns(1-8):  Th  8C  JS  2C  5S  Kh  8d  QC
  36:                    9C  5h  4d  6h  7d  KC  2h  7C
  37:                    4S  TS  8S  Qh  9h  6S  2S  AC
  38:                    2d  4C  4h  8h  3S  9S  7S  6C
  39:                    9d  Qd  TC  Ad  Td  QS  JC  6d
  40:                    Jd  5d  Jh  AS  3C  KS  5C  3h
  41:                    3d  7h      Kd                
  42:                                                  
  43: **** p1->p2: legal
  44: user Move 3d from column 1 to free A, Heuristic2 = 31
  45: **** p2->p1: 1A
  46:     free cells(A-D):  3d  --  --  --    home cells(H):  --  Ah  --  --
  47: 
  48:     columns(1-8):  Th  8C  JS  2C  5S  Kh  8d  QC
  49:                    9C  5h  4d  6h  7d  KC  2h  7C
  50:                    4S  TS  8S  Qh  9h  6S  2S  AC
  51:                    2d  4C  4h  8h  3S  9S  7S  6C
  52:                    9d  Qd  TC  Ad  Td  QS  JC  6d
  53:                    Jd  5d  Jh  AS  3C  KS  5C  3h
  54:                        7h      Kd                
  55:                                                  
  56: **** p1->p2: legal
  57: user Move Jd from column 1 to free B, Heuristic2 = 30
  58: **** p2->p1: 1B
  59: **** p1->p2: legal
  60:     free cells(A-D):  3d  Jd  --  --    home cells(H):  --  Ah  --  --
  61: 
  62:     columns(1-8):  Th  8C  JS  2C  5S  Kh  8d  QC
  63:                    9C  5h  4d  6h  7d  KC  2h  7C
  64:                    4S  TS  8S  Qh  9h  6S  2S  AC
  65:                    2d  4C  4h  8h  3S  9S  7S  6C
  66:                    9d  Qd  TC  Ad  Td  QS  JC  6d
  67:                        5d  Jh  AS  3C  KS  5C  3h
  68:                        7h      Kd                
  69:                                                  
  70: user Move 9d from column 1 to free C, Heuristic2 = 29
  71: **** p2->p1: 1C
  72: **** p1->p2: legal
  73:     free cells(A-D):  3d  Jd  9d  --    home cells(H):  --  Ah  --  --
  74: 
  75:     columns(1-8):  Th  8C  JS  2C  5S  Kh  8d  QC
  76:                    9C  5h  4d  6h  7d  KC  2h  7C
  77:                    4S  TS  8S  Qh  9h  6S  2S  AC
  78:                    2d  4C  4h  8h  3S  9S  7S  6C
  79:                        Qd  TC  Ad  Td  QS  JC  6d
  80:                        5d  Jh  AS  3C  KS  5C  3h
  81:                        7h      Kd                
  82:                                                  
  83: user Move Kd from column 4 to free D, Heuristic2 = 28
  84: **** p2->p1: 4D
  85: **** p1->p2: legal
  86:     free cells(A-D):  3d  Jd  9d  Kd    home cells(H):  --  Ah  --  --
  87: 
  88:     columns(1-8):  Th  8C  JS  2C  5S  Kh  8d  QC
  89:                    9C  5h  4d  6h  7d  KC  2h  7C
  90:                    4S  TS  8S  Qh  9h  6S  2S  AC
  91:                    2d  4C  4h  8h  3S  9S  7S  6C
  92:                        Qd  TC  Ad  Td  QS  JC  6d
  93:                        5d  Jh  AS  3C  KS  5C  3h
  94:                        7h                        
  95:                                                  
  96: user Move AS from column 4 to Home, Heuristic2 = 27
  97: **** p2->p1: 4H
  98: **** p1->p2: legal
  99:     free cells(A-D):  3d  Jd  9d  Kd    home cells(H):  AS  Ah  --  --
 100: 
 101:     columns(1-8):  Th  8C  JS  2C  5S  Kh  8d  QC
 102:                    9C  5h  4d  6h  7d  KC  2h  7C
 103:                    4S  TS  8S  Qh  9h  6S  2S  AC
 104:                    2d  4C  4h  8h  3S  9S  7S  6C
 105:                        Qd  TC  Ad  Td  QS  JC  6d
 106:                        5d  Jh      3C  KS  5C  3h
 107:                        7h                        
 108:                                                  
 109: user Move Ad from column 4 to Home, Heuristic2 = 26
 110: **** p2->p1: 4H
 111: **** p1->p2: legal
 112:     free cells(A-D):  3d  Jd  9d  Kd    home cells(H):  AS  Ah  --  Ad
 113: 
 114:     columns(1-8):  Th  8C  JS  2C  5S  Kh  8d  QC
 115:                    9C  5h  4d  6h  7d  KC  2h  7C
 116:                    4S  TS  8S  Qh  9h  6S  2S  AC
 117:                    2d  4C  4h  8h  3S  9S  7S  6C
 118:                        Qd  TC      Td  QS  JC  6d
 119:                        5d  Jh      3C  KS  5C  3h
 120:                        7h                        
 121:                                                  
 122: user Move 2d from column 1 to Home, Heuristic2 = 26
 123: **** p2->p1: 1H
 124: **** p1->p2: legal
 125:     free cells(A-D):  3d  Jd  9d  Kd    home cells(H):  AS  Ah  --  2d
 126: 
 127:     columns(1-8):  Th  8C  JS  2C  5S  Kh  8d  QC
 128:                    9C  5h  4d  6h  7d  KC  2h  7C
 129:                    4S  TS  8S  Qh  9h  6S  2S  AC
 130:                        4C  4h  8h  3S  9S  7S  6C
 131:                        Qd  TC      Td  QS  JC  6d
 132:                        5d  Jh      3C  KS  5C  3h
 133:                        7h                        
 134:                                                  
 135: user Move 3d from free A to Home, Heuristic2 = 26
 136: **** p2->p1: AH
 137: **** p1->p2: legal
 138:     free cells(A-D):  --  Jd  9d  Kd    home cells(H):  AS  Ah  --  3d
 139: 
 140:     columns(1-8):  Th  8C  JS  2C  5S  Kh  8d  QC
 141:                    9C  5h  4d  6h  7d  KC  2h  7C
 142:                    4S  TS  8S  Qh  9h  6S  2S  AC
 143:                        4C  4h  8h  3S  9S  7S  6C
 144:                        Qd  TC      Td  QS  JC  6d
 145:                        5d  Jh      3C  KS  5C  3h
 146:                        7h                        
 147:                                                  
 148: user Move 4S from column 1 to free A, Heuristic2 = 26
 149: **** p2->p1: 1A
 150: **** p1->p2: legal
 151:     free cells(A-D):  4S  Jd  9d  Kd    home cells(H):  AS  Ah  --  3d
 152: 
 153:     columns(1-8):  Th  8C  JS  2C  5S  Kh  8d  QC
 154:                    9C  5h  4d  6h  7d  KC  2h  7C
 155:                        TS  8S  Qh  9h  6S  2S  AC
 156:                        4C  4h  8h  3S  9S  7S  6C
 157:                        Qd  TC      Td  QS  JC  6d
 158:                        5d  Jh      3C  KS  5C  3h
 159:                        7h                        
 160:                                                  
 161: user Move 8h from column 4 to column 1, Heuristic2 = 25
 162: **** p2->p1: 41
 163: **** p1->p2: legal
 164:     free cells(A-D):  4S  Jd  9d  Kd    home cells(H):  AS  Ah  --  3d
 165: 
 166:     columns(1-8):  Th  8C  JS  2C  5S  Kh  8d  QC
 167:                    9C  5h  4d  6h  7d  KC  2h  7C
 168:                    8h  TS  8S  Qh  9h  6S  2S  AC
 169:                        4C  4h      3S  9S  7S  6C
 170:                        Qd  TC      Td  QS  JC  6d
 171:                        5d  Jh      3C  KS  5C  3h
 172:                        7h                        
 173:                                                  
 174: user Move Qh from column 4 to column 6, Heuristic2 = 25
 175: **** p2->p1: 46
 176: **** p1->p2: legal
 177:     free cells(A-D):  4S  Jd  9d  Kd    home cells(H):  AS  Ah  --  3d
 178: 
 179:     columns(1-8):  Th  8C  JS  2C  5S  Kh  8d  QC
 180:                    9C  5h  4d  6h  7d  KC  2h  7C
 181:                    8h  TS  8S      9h  6S  2S  AC
 182:                        4C  4h      3S  9S  7S  6C
 183:                        Qd  TC      Td  QS  JC  6d
 184:                        5d  Jh      3C  KS  5C  3h
 185:                        7h              Qh        
 186:                                                  
 187: user Move 5C from column 7 to column 4, Heuristic2 = 25
 188: **** p2->p1: 74
 189: **** p1->p2: legal
 190:     free cells(A-D):  4S  Jd  9d  Kd    home cells(H):  AS  Ah  --  3d
 191: 
 192:     columns(1-8):  Th  8C  JS  2C  5S  Kh  8d  QC
 193:                    9C  5h  4d  6h  7d  KC  2h  7C
 194:                    8h  TS  8S  5C  9h  6S  2S  AC
 195:                        4C  4h      3S  9S  7S  6C
 196:                        Qd  TC      Td  QS  JC  6d
 197:                        5d  Jh      3C  KS      3h
 198:                        7h              Qh        
 199:                                                  
 200: user Move JC from column 7 to column 6, Heuristic2 = 25
 201: **** p2->p1: 76
 202:     free cells(A-D):  4S  Jd  9d  Kd    home cells(H):  AS  Ah  --  3d
 203: 
 204:     columns(1-8):  Th  8C  JS  2C  5S  Kh  8d  QC
 205:                    9C  5h  4d  6h  7d  KC  2h  7C
 206:                    8h  TS  8S  5C  9h  6S  2S  AC
 207:                        4C  4h      3S  9S  7S  6C
 208:                        Qd  TC      Td  QS      6d
 209:                        5d  Jh      3C  KS      3h
 210:                        7h              Qh        
 211:                                        JC        
 212:                                                  
 213: **** p1->p2: legal
 214: user Move 7S from column 7 to column 1, Heuristic2 = 24
 215: **** p2->p1: 71
 216:     free cells(A-D):  4S  Jd  9d  Kd    home cells(H):  AS  Ah  --  3d
 217: 
 218:     columns(1-8):  Th  8C  JS  2C  5S  Kh  8d  QC
 219:                    9C  5h  4d  6h  7d  KC  2h  7C
 220:                    8h  TS  8S  5C  9h  6S  2S  AC
 221:                    7S  4C  4h      3S  9S      6C
 222:                        Qd  TC      Td  QS      6d
 223:                        5d  Jh      3C  KS      3h
 224:                        7h              Qh        
 225:                                        JC        
 226:                                                  
 227: **** p1->p2: legal
 228: user Move 2S from column 7 to Home, Heuristic2 = 24
 229: **** p2->p1: 7H
 230:     free cells(A-D):  4S  Jd  9d  Kd    home cells(H):  2S  Ah  --  3d
 231: 
 232:     columns(1-8):  Th  8C  JS  2C  5S  Kh  8d  QC
 233:                    9C  5h  4d  6h  7d  KC  2h  7C
 234:                    8h  TS  8S  5C  9h  6S      AC
 235:                    7S  4C  4h      3S  9S      6C
 236:                        Qd  TC      Td  QS      6d
 237:                        5d  Jh      3C  KS      3h
 238:                        7h              Qh        
 239:                                        JC        
 240:                                                  
 241: **** p1->p2: legal
 242: user Move 2h from column 7 to Home, Heuristic2 = 24
 243: **** p2->p1: 7H
 244:     free cells(A-D):  4S  Jd  9d  Kd    home cells(H):  2S  2h  --  3d
 245: 
 246:     columns(1-8):  Th  8C  JS  2C  5S  Kh  8d  QC
 247:                    9C  5h  4d  6h  7d  KC      7C
 248:                    8h  TS  8S  5C  9h  6S      AC
 249:                    7S  4C  4h      3S  9S      6C
 250:                        Qd  TC      Td  QS      6d
 251:                        5d  Jh      3C  KS      3h
 252:                        7h              Qh        
 253:                                        JC        
 254:                                                  
 255: **** p1->p2: legal
 256: user Move 3h from column 8 to Home, Heuristic2 = 23
 257: **** p2->p1: 8H
 258:     free cells(A-D):  4S  Jd  9d  Kd    home cells(H):  2S  3h  --  3d
 259: 
 260:     columns(1-8):  Th  8C  JS  2C  5S  Kh  8d  QC
 261:                    9C  5h  4d  6h  7d  KC      7C
 262:                    8h  TS  8S  5C  9h  6S      AC
 263:                    7S  4C  4h      3S  9S      6C
 264:                        Qd  TC      Td  QS      6d
 265:                        5d  Jh      3C  KS        
 266:                        7h              Qh        
 267:                                        JC        
 268:                                                  
 269: **** p1->p2: legal
 270: user Move 6d from column 8 to column 1, Heuristic2 = 22
 271: **** p2->p1: 81
 272:     free cells(A-D):  4S  Jd  9d  Kd    home cells(H):  2S  3h  --  3d
 273: 
 274:     columns(1-8):  Th  8C  JS  2C  5S  Kh  8d  QC
 275:                    9C  5h  4d  6h  7d  KC      7C
 276:                    8h  TS  8S  5C  9h  6S      AC
 277:                    7S  4C  4h      3S  9S      6C
 278:                    6d  Qd  TC      Td  QS        
 279:                        5d  Jh      3C  KS        
 280:                        7h              Qh        
 281:                                        JC        
 282:                                                  
 283: **** p1->p2: legal
 284: user Move 5C from column 4 to column 1, Heuristic2 = 21
 285: **** p2->p1: 41
 286:     free cells(A-D):  4S  Jd  9d  Kd    home cells(H):  2S  3h  --  3d
 287: 
 288:     columns(1-8):  Th  8C  JS  2C  5S  Kh  8d  QC
 289:                    9C  5h  4d  6h  7d  KC      7C
 290:                    8h  TS  8S      9h  6S      AC
 291:                    7S  4C  4h      3S  9S      6C
 292:                    6d  Qd  TC      Td  QS        
 293:                    5C  5d  Jh      3C  KS        
 294:                        7h              Qh        
 295:                                        JC        
 296:                                                  
 297: **** p1->p2: legal
 298: user Move 6C from column 8 to column 2, Heuristic2 = 21
 299: **** p2->p1: 82
 300:     free cells(A-D):  4S  Jd  9d  Kd    home cells(H):  2S  3h  --  3d
 301: 
 302:     columns(1-8):  Th  8C  JS  2C  5S  Kh  8d  QC
 303:                    9C  5h  4d  6h  7d  KC      7C
 304:                    8h  TS  8S      9h  6S      AC
 305:                    7S  4C  4h      3S  9S        
 306:                    6d  Qd  TC      Td  QS        
 307:                    5C  5d  Jh      3C  KS        
 308:                        7h              Qh        
 309:                        6C              JC        
 310:                                                  
 311: **** p1->p2: legal
 312: user Move AC from column 8 to Home, Heuristic2 = 21
 313: **** p2->p1: 8H
 314:     free cells(A-D):  4S  Jd  9d  Kd    home cells(H):  2S  3h  AC  3d
 315: 
 316:     columns(1-8):  Th  8C  JS  2C  5S  Kh  8d  QC
 317:                    9C  5h  4d  6h  7d  KC      7C
 318:                    8h  TS  8S      9h  6S        
 319:                    7S  4C  4h      3S  9S        
 320:                    6d  Qd  TC      Td  QS        
 321:                    5C  5d  Jh      3C  KS        
 322:                        7h              Qh        
 323:                        6C              JC        
 324:                                                  
 325: **** p1->p2: legal
 326: user Move 6h from column 4 to column 8, Heuristic2 = 20
 327: **** p2->p1: 48
 328:     free cells(A-D):  4S  Jd  9d  Kd    home cells(H):  2S  3h  AC  3d
 329: 
 330:     columns(1-8):  Th  8C  JS  2C  5S  Kh  8d  QC
 331:                    9C  5h  4d      7d  KC      7C
 332:                    8h  TS  8S      9h  6S      6h
 333:                    7S  4C  4h      3S  9S        
 334:                    6d  Qd  TC      Td  QS        
 335:                    5C  5d  Jh      3C  KS        
 336:                        7h              Qh        
 337:                        6C              JC        
 338:                                                  
 339: **** p1->p2: legal
 340: user Move 2C from column 4 to Home, Heuristic2 = 20
 341: **** p2->p1: 4H
 342:     free cells(A-D):  4S  Jd  9d  Kd    home cells(H):  2S  3h  2C  3d
 343: 
 344:     columns(1-8):  Th  8C  JS  --  5S  Kh  8d  QC
 345:                    9C  5h  4d      7d  KC      7C
 346:                    8h  TS  8S      9h  6S      6h
 347:                    7S  4C  4h      3S  9S        
 348:                    6d  Qd  TC      Td  QS        
 349:                    5C  5d  Jh      3C  KS        
 350:                        7h              Qh        
 351:                        6C              JC        
 352:                                                  
 353: **** p1->p2: legal
 354: user Move 3C from column 5 to Home, Heuristic2 = 19
 355: **** p2->p1: 5H
 356:     free cells(A-D):  4S  Jd  9d  Kd    home cells(H):  2S  3h  3C  3d
 357: 
 358:     columns(1-8):  Th  8C  JS  --  5S  Kh  8d  QC
 359:                    9C  5h  4d      7d  KC      7C
 360:                    8h  TS  8S      9h  6S      6h
 361:                    7S  4C  4h      3S  9S        
 362:                    6d  Qd  TC      Td  QS        
 363:                    5C  5d  Jh          KS        
 364:                        7h              Qh        
 365:                        6C              JC        
 366:                                                  
 367: **** p1->p2: legal
 368: user Move Jh from column 3 to column 4, Heuristic2 = 18
 369: **** p2->p1: 34
 370:     free cells(A-D):  4S  Jd  9d  Kd    home cells(H):  2S  3h  3C  3d
 371: 
 372:     columns(1-8):  Th  8C  JS  Jh  5S  Kh  8d  QC
 373:                    9C  5h  4d      7d  KC      7C
 374:                    8h  TS  8S      9h  6S      6h
 375:                    7S  4C  4h      3S  9S        
 376:                    6d  Qd  TC      Td  QS        
 377:                    5C  5d              KS        
 378:                        7h              Qh        
 379:                        6C              JC        
 380:                                                  
 381: **** p1->p2: legal
 382: user Move TC from column 3 to column 4, Heuristic2 = 17
 383: **** p2->p1: 34
 384:     free cells(A-D):  4S  Jd  9d  Kd    home cells(H):  2S  3h  3C  3d
 385: 
 386:     columns(1-8):  Th  8C  JS  Jh  5S  Kh  8d  QC
 387:                    9C  5h  4d  TC  7d  KC      7C
 388:                    8h  TS  8S      9h  6S      6h
 389:                    7S  4C  4h      3S  9S        
 390:                    6d  Qd          Td  QS        
 391:                    5C  5d              KS        
 392:                        7h              Qh        
 393:                        6C              JC        
 394:                                                  
 395: **** p1->p2: legal
 396: user Move 4h from column 3 to Home, Heuristic2 = 16
 397: **** p2->p1: 3H
 398:     free cells(A-D):  4S  Jd  9d  Kd    home cells(H):  2S  4h  3C  3d
 399: 
 400:     columns(1-8):  Th  8C  JS  Jh  5S  Kh  8d  QC
 401:                    9C  5h  4d  TC  7d  KC      7C
 402:                    8h  TS  8S      9h  6S      6h
 403:                    7S  4C          3S  9S        
 404:                    6d  Qd          Td  QS        
 405:                    5C  5d              KS        
 406:                        7h              Qh        
 407:                        6C              JC        
 408:                                                  
 409: **** p1->p2: legal
 410: user Move Td from column 5 to column 6, Heuristic2 = 16
 411: **** p2->p1: 56
 412:     free cells(A-D):  4S  Jd  9d  Kd    home cells(H):  2S  4h  3C  3d
 413: 
 414:     columns(1-8):  Th  8C  JS  Jh  5S  Kh  8d  QC
 415:                    9C  5h  4d  TC  7d  KC      7C
 416:                    8h  TS  8S      9h  6S      6h
 417:                    7S  4C          3S  9S        
 418:                    6d  Qd              QS        
 419:                    5C  5d              KS        
 420:                        7h              Qh        
 421:                        6C              JC        
 422:                                        Td        
 423:                                                  
 424: **** p1->p2: legal
 425: user Move 3S from column 5 to Home, Heuristic2 = 15
 426: **** p2->p1: 5H
 427:     free cells(A-D):  4S  Jd  9d  Kd    home cells(H):  3S  4h  3C  3d
 428: 
 429:     columns(1-8):  Th  8C  JS  Jh  5S  Kh  8d  QC
 430:                    9C  5h  4d  TC  7d  KC      7C
 431:                    8h  TS  8S      9h  6S      6h
 432:                    7S  4C              9S        
 433:                    6d  Qd              QS        
 434:                    5C  5d              KS        
 435:                        7h              Qh        
 436:                        6C              JC        
 437:                                        Td        
 438:                                                  
 439: **** p1->p2: legal
 440: user Move 4S from free A to Home, Heuristic2 = 15
 441: **** p2->p1: AH
 442:     free cells(A-D):  --  Jd  9d  Kd    home cells(H):  4S  4h  3C  3d
 443: 
 444:     columns(1-8):  Th  8C  JS  Jh  5S  Kh  8d  QC
 445:                    9C  5h  4d  TC  7d  KC      7C
 446:                    8h  TS  8S      9h  6S      6h
 447:                    7S  4C              9S        
 448:                    6d  Qd              QS        
 449:                    5C  5d              KS        
 450:                        7h              Qh        
 451:                        6C              JC        
 452:                                        Td        
 453:                                                  
 454: **** p1->p2: legal
 455: user Move 5C from column 1 to free A, Heuristic2 = 15
 456: **** p2->p1: 1A
 457:     free cells(A-D):  5C  Jd  9d  Kd    home cells(H):  4S  4h  3C  3d
 458: 
 459:     columns(1-8):  Th  8C  JS  Jh  5S  Kh  8d  QC
 460:                    9C  5h  4d  TC  7d  KC      7C
 461:                    8h  TS  8S      9h  6S      6h
 462:                    7S  4C              9S        
 463:                    6d  Qd              QS        
 464:                        5d              KS        
 465:                        7h              Qh        
 466:                        6C              JC        
 467:                                        Td        
 468:                                                  
 469: **** p1->p2: legal
 470: user Move 9h from column 5 to column 4, Heuristic2 = 14
 471: **** p2->p1: 54
 472:     free cells(A-D):  5C  Jd  9d  Kd    home cells(H):  4S  4h  3C  3d
 473: 
 474:     columns(1-8):  Th  8C  JS  Jh  5S  Kh  8d  QC
 475:                    9C  5h  4d  TC  7d  KC      7C
 476:                    8h  TS  8S  9h      6S      6h
 477:                    7S  4C              9S        
 478:                    6d  Qd              QS        
 479:                        5d              KS        
 480:                        7h              Qh        
 481:                        6C              JC        
 482:                                        Td        
 483:                                                  
 484: **** p1->p2: legal
 485: user Move 7d from column 5 to column 3, Heuristic2 = 14
 486: **** p2->p1: 53
 487:     free cells(A-D):  5C  Jd  9d  Kd    home cells(H):  4S  4h  3C  3d
 488: 
 489:     columns(1-8):  Th  8C  JS  Jh  5S  Kh  8d  QC
 490:                    9C  5h  4d  TC      KC      7C
 491:                    8h  TS  8S  9h      6S      6h
 492:                    7S  4C  7d          9S        
 493:                    6d  Qd              QS        
 494:                        5d              KS        
 495:                        7h              Qh        
 496:                        6C              JC        
 497:                                        Td        
 498:                                                  
 499: **** p1->p2: legal
 500: user Move 5S from column 5 to Home, Heuristic2 = 14
 501: **** p2->p1: 5H
 502:     free cells(A-D):  5C  Jd  9d  Kd    home cells(H):  5S  4h  3C  3d
 503: 
 504:     columns(1-8):  Th  8C  JS  Jh  --  Kh  8d  QC
 505:                    9C  5h  4d  TC      KC      7C
 506:                    8h  TS  8S  9h      6S      6h
 507:                    7S  4C  7d          9S        
 508:                    6d  Qd              QS        
 509:                        5d              KS        
 510:                        7h              Qh        
 511:                        6C              JC        
 512:                                        Td        
 513:                                                  
 514: **** p1->p2: legal
 515: user Move 7d from column 3 to column 5, Heuristic2 = 13
 516: **** p2->p1: 35
 517:     free cells(A-D):  5C  Jd  9d  Kd    home cells(H):  5S  4h  3C  3d
 518: 
 519:     columns(1-8):  Th  8C  JS  Jh  7d  Kh  8d  QC
 520:                    9C  5h  4d  TC      KC      7C
 521:                    8h  TS  8S  9h      6S      6h
 522:                    7S  4C              9S        
 523:                    6d  Qd              QS        
 524:                        5d              KS        
 525:                        7h              Qh        
 526:                        6C              JC        
 527:                                        Td        
 528:                                                  
 529: **** p1->p2: legal
 530: user Move 8S from column 3 to column 4, Heuristic2 = 12
 531: **** p2->p1: 34
 532:     free cells(A-D):  5C  Jd  9d  Kd    home cells(H):  5S  4h  3C  3d
 533: 
 534:     columns(1-8):  Th  8C  JS  Jh  7d  Kh  8d  QC
 535:                    9C  5h  4d  TC      KC      7C
 536:                    8h  TS      9h      6S      6h
 537:                    7S  4C      8S      9S        
 538:                    6d  Qd              QS        
 539:                        5d              KS        
 540:                        7h              Qh        
 541:                        6C              JC        
 542:                                        Td        
 543:                                                  
 544: **** p1->p2: legal
 545: user Move 4d from column 3 to Home, Heuristic2 = 12
 546: **** p2->p1: 3H
 547:     free cells(A-D):  5C  Jd  9d  Kd    home cells(H):  5S  4h  3C  4d
 548: 
 549:     columns(1-8):  Th  8C  JS  Jh  7d  Kh  8d  QC
 550:                    9C  5h      TC      KC      7C
 551:                    8h  TS      9h      6S      6h
 552:                    7S  4C      8S      9S        
 553:                    6d  Qd              QS        
 554:                        5d              KS        
 555:                        7h              Qh        
 556:                        6C              JC        
 557:                                        Td        
 558:                                                  
 559: **** p1->p2: legal
 560: user Move Td from column 6 to column 3, Heuristic2 = 11
 561: **** p2->p1: 63
 562:     free cells(A-D):  5C  Jd  9d  Kd    home cells(H):  5S  4h  3C  4d
 563: 
 564:     columns(1-8):  Th  8C  JS  Jh  7d  Kh  8d  QC
 565:                    9C  5h  Td  TC      KC      7C
 566:                    8h  TS      9h      6S      6h
 567:                    7S  4C      8S      9S        
 568:                    6d  Qd              QS        
 569:                        5d              KS        
 570:                        7h              Qh        
 571:                        6C              JC        
 572:                                                  
 573: **** p1->p2: legal
 574: user Move 6C from column 2 to column 5, Heuristic2 = 10
 575: **** p2->p1: 25
 576:     free cells(A-D):  5C  Jd  9d  Kd    home cells(H):  5S  4h  3C  4d
 577: 
 578:     columns(1-8):  Th  8C  JS  Jh  7d  Kh  8d  QC
 579:                    9C  5h  Td  TC  6C  KC      7C
 580:                    8h  TS      9h      6S      6h
 581:                    7S  4C      8S      9S        
 582:                    6d  Qd              QS        
 583:                        5d              KS        
 584:                        7h              Qh        
 585:                                        JC        
 586:                                                  
 587: **** p1->p2: legal
 588: user Move 7h from column 2 to column 4, Heuristic2 = 9
 589: **** p2->p1: 24
 590:     free cells(A-D):  5C  Jd  9d  Kd    home cells(H):  5S  4h  3C  4d
 591: 
 592:     columns(1-8):  Th  8C  JS  Jh  7d  Kh  8d  QC
 593:                    9C  5h  Td  TC  6C  KC      7C
 594:                    8h  TS      9h      6S      6h
 595:                    7S  4C      8S      9S        
 596:                    6d  Qd      7h      QS        
 597:                        5d              KS        
 598:                                        Qh        
 599:                                        JC        
 600:                                                  
 601: **** p1->p2: legal
 602: user Move 5d from column 2 to Home, Heuristic2 = 8
 603: **** p2->p1: 2H
 604:     free cells(A-D):  5C  Jd  9d  Kd    home cells(H):  5S  4h  3C  5d
 605: 
 606:     columns(1-8):  Th  8C  JS  Jh  7d  Kh  8d  QC
 607:                    9C  5h  Td  TC  6C  KC      7C
 608:                    8h  TS      9h      6S      6h
 609:                    7S  4C      8S      9S        
 610:                    6d  Qd      7h      QS        
 611:                                        KS        
 612:                                        Qh        
 613:                                        JC        
 614:                                                  
 615: **** p1->p2: legal
 616: user Move 6d from column 1 to Home, Heuristic2 = 8
 617: **** p2->p1: 1H
 618:     free cells(A-D):  5C  Jd  9d  Kd    home cells(H):  5S  4h  3C  6d
 619: 
 620:     columns(1-8):  Th  8C  JS  Jh  7d  Kh  8d  QC
 621:                    9C  5h  Td  TC  6C  KC      7C
 622:                    8h  TS      9h      6S      6h
 623:                    7S  4C      8S      9S        
 624:                        Qd      7h      QS        
 625:                                        KS        
 626:                                        Qh        
 627:                                        JC        
 628:                                                  
 629: **** p1->p2: legal
 630: user Move 6C from column 5 to column 4, Heuristic2 = 8
 631: **** p2->p1: 54
 632:     free cells(A-D):  5C  Jd  9d  Kd    home cells(H):  5S  4h  3C  6d
 633: 
 634:     columns(1-8):  Th  8C  JS  Jh  7d  Kh  8d  QC
 635:                    9C  5h  Td  TC      KC      7C
 636:                    8h  TS      9h      6S      6h
 637:                    7S  4C      8S      9S        
 638:                        Qd      7h      QS        
 639:                                6C      KS        
 640:                                        Qh        
 641:                                        JC        
 642:                                                  
 643: **** p1->p2: legal
 644: user Move 7d from column 5 to Home, Heuristic2 = 8
 645: **** p2->p1: 5H
 646:     free cells(A-D):  5C  Jd  9d  Kd    home cells(H):  5S  4h  3C  7d
 647: 
 648:     columns(1-8):  Th  8C  JS  Jh  --  Kh  8d  QC
 649:                    9C  5h  Td  TC      KC      7C
 650:                    8h  TS      9h      6S      6h
 651:                    7S  4C      8S      9S        
 652:                        Qd      7h      QS        
 653:                                6C      KS        
 654:                                        Qh        
 655:                                        JC        
 656:                                                  
 657: **** p1->p2: legal
 658: user Move 8d from column 7 to Home, Heuristic2 = 8
 659: **** p2->p1: 7H
 660:     free cells(A-D):  5C  Jd  9d  Kd    home cells(H):  5S  4h  3C  8d
 661: 
 662:     columns(1-8):  Th  8C  JS  Jh  --  Kh  --  QC
 663:                    9C  5h  Td  TC      KC      7C
 664:                    8h  TS      9h      6S      6h
 665:                    7S  4C      8S      9S        
 666:                        Qd      7h      QS        
 667:                                6C      KS        
 668:                                        Qh        
 669:                                        JC        
 670:                                                  
 671: **** p1->p2: legal
 672: user Move 9d from free C to Home, Heuristic2 = 8
 673: **** p2->p1: CH
 674:     free cells(A-D):  5C  Jd  --  Kd    home cells(H):  5S  4h  3C  9d
 675: 
 676:     columns(1-8):  Th  8C  JS  Jh  --  Kh  --  QC
 677:                    9C  5h  Td  TC      KC      7C
 678:                    8h  TS      9h      6S      6h
 679:                    7S  4C      8S      9S        
 680:                        Qd      7h      QS        
 681:                                6C      KS        
 682:                                        Qh        
 683:                                        JC        
 684:                                                  
 685: **** p1->p2: legal
 686: user Move Td from column 3 to Home, Heuristic2 = 8
 687: **** p2->p1: 3H
 688:     free cells(A-D):  5C  Jd  --  Kd    home cells(H):  5S  4h  3C  Td
 689: 
 690:     columns(1-8):  Th  8C  JS  Jh  --  Kh  --  QC
 691:                    9C  5h      TC      KC      7C
 692:                    8h  TS      9h      6S      6h
 693:                    7S  4C      8S      9S        
 694:                        Qd      7h      QS        
 695:                                6C      KS        
 696:                                        Qh        
 697:                                        JC        
 698:                                                  
 699: **** p1->p2: legal
 700: user Move Jd from free B to Home, Heuristic2 = 8
 701: **** p2->p1: BH
 702:     free cells(A-D):  5C  --  --  Kd    home cells(H):  5S  4h  3C  Jd
 703: 
 704:     columns(1-8):  Th  8C  JS  Jh  --  Kh  --  QC
 705:                    9C  5h      TC      KC      7C
 706:                    8h  TS      9h      6S      6h
 707:                    7S  4C      8S      9S        
 708:                        Qd      7h      QS        
 709:                                6C      KS        
 710:                                        Qh        
 711:                                        JC        
 712:                                                  
 713: **** p1->p2: legal
 714: user Move Qd from column 2 to Home, Heuristic2 = 7
 715: **** p2->p1: 2H
 716:     free cells(A-D):  5C  --  --  Kd    home cells(H):  5S  4h  3C  Qd
 717: 
 718:     columns(1-8):  Th  8C  JS  Jh  --  Kh  --  QC
 719:                    9C  5h      TC      KC      7C
 720:                    8h  TS      9h      6S      6h
 721:                    7S  4C      8S      9S        
 722:                                7h      QS        
 723:                                6C      KS        
 724:                                        Qh        
 725:                                        JC        
 726:                                                  
 727: **** p1->p2: legal
 728: user Move 4C from column 2 to Home, Heuristic2 = 6
 729: **** p2->p1: 2H
 730:     free cells(A-D):  5C  --  --  Kd    home cells(H):  5S  4h  4C  Qd
 731: 
 732:     columns(1-8):  Th  8C  JS  Jh  --  Kh  --  QC
 733:                    9C  5h      TC      KC      7C
 734:                    8h  TS      9h      6S      6h
 735:                    7S          8S      9S        
 736:                                7h      QS        
 737:                                6C      KS        
 738:                                        Qh        
 739:                                        JC        
 740:                                                  
 741: **** p1->p2: legal
 742: user Move 5C from free A to Home, Heuristic2 = 6
 743: **** p2->p1: AH
 744:     free cells(A-D):  --  --  --  Kd    home cells(H):  5S  4h  5C  Qd
 745: 
 746:     columns(1-8):  Th  8C  JS  Jh  --  Kh  --  QC
 747:                    9C  5h      TC      KC      7C
 748:                    8h  TS      9h      6S      6h
 749:                    7S          8S      9S        
 750:                                7h      QS        
 751:                                6C      KS        
 752:                                        Qh        
 753:                                        JC        
 754:                                                  
 755: **** p1->p2: legal
 756: user Move 6C from column 4 to Home, Heuristic2 = 6
 757: **** p2->p1: 4H
 758:     free cells(A-D):  --  --  --  Kd    home cells(H):  5S  4h  6C  Qd
 759: 
 760:     columns(1-8):  Th  8C  JS  Jh  --  Kh  --  QC
 761:                    9C  5h      TC      KC      7C
 762:                    8h  TS      9h      6S      6h
 763:                    7S          8S      9S        
 764:                                7h      QS        
 765:                                        KS        
 766:                                        Qh        
 767:                                        JC        
 768:                                                  
 769: **** p1->p2: legal
 770: user Move Kd from free D to Home, Heuristic2 = 6
 771: **** p2->p1: DH
 772:     free cells(A-D):  --  --  --  --    home cells(H):  5S  4h  6C  Kd
 773: 
 774:     columns(1-8):  Th  8C  JS  Jh  --  Kh  --  QC
 775:                    9C  5h      TC      KC      7C
 776:                    8h  TS      9h      6S      6h
 777:                    7S          8S      9S        
 778:                                7h      QS        
 779:                                        KS        
 780:                                        Qh        
 781:                                        JC        
 782:                                                  
 783: **** p1->p2: legal
 784: user Move 7S from column 1 to free A, Heuristic2 = 6
 785: **** p2->p1: 1A
 786:     free cells(A-D):  7S  --  --  --    home cells(H):  5S  4h  6C  Kd
 787: 
 788:     columns(1-8):  Th  8C  JS  Jh  --  Kh  --  QC
 789:                    9C  5h      TC      KC      7C
 790:                    8h  TS      9h      6S      6h
 791:                                8S      9S        
 792:                                7h      QS        
 793:                                        KS        
 794:                                        Qh        
 795:                                        JC        
 796:                                                  
 797: **** p1->p2: legal
 798: user Move 8h from column 1 to free B, Heuristic2 = 6
 799: **** p2->p1: 1B
 800:     free cells(A-D):  7S  8h  --  --    home cells(H):  5S  4h  6C  Kd
 801: 
 802:     columns(1-8):  Th  8C  JS  Jh  --  Kh  --  QC
 803:                    9C  5h      TC      KC      7C
 804:                        TS      9h      6S      6h
 805:                                8S      9S        
 806:                                7h      QS        
 807:                                        KS        
 808:                                        Qh        
 809:                                        JC        
 810:                                                  
 811: **** p1->p2: legal
 812: user Move TS from column 2 to free C, Heuristic2 = 5
 813: **** p2->p1: 2C
 814:     free cells(A-D):  7S  8h  TS  --    home cells(H):  5S  4h  6C  Kd
 815: 
 816:     columns(1-8):  Th  8C  JS  Jh  --  Kh  --  QC
 817:                    9C  5h      TC      KC      7C
 818:                                9h      6S      6h
 819:                                8S      9S        
 820:                                7h      QS        
 821:                                        KS        
 822:                                        Qh        
 823:                                        JC        
 824:                                                  
 825: **** p1->p2: legal
 826: user Move 5h from column 2 to Home, Heuristic2 = 5
 827: **** p2->p1: 2H
 828:     free cells(A-D):  7S  8h  TS  --    home cells(H):  5S  5h  6C  Kd
 829: 
 830:     columns(1-8):  Th  8C  JS  Jh  --  Kh  --  QC
 831:                    9C          TC      KC      7C
 832:                                9h      6S      6h
 833:                                8S      9S        
 834:                                7h      QS        
 835:                                        KS        
 836:                                        Qh        
 837:                                        JC        
 838:                                                  
 839: **** p1->p2: legal
 840: user Move 6h from column 8 to Home, Heuristic2 = 5
 841: **** p2->p1: 8H
 842:     free cells(A-D):  7S  8h  TS  --    home cells(H):  5S  6h  6C  Kd
 843: 
 844:     columns(1-8):  Th  8C  JS  Jh  --  Kh  --  QC
 845:                    9C          TC      KC      7C
 846:                                9h      6S        
 847:                                8S      9S        
 848:                                7h      QS        
 849:                                        KS        
 850:                                        Qh        
 851:                                        JC        
 852:                                                  
 853: **** p1->p2: legal
 854: user Move 7h from column 4 to Home, Heuristic2 = 5
 855: **** p2->p1: 4H
 856:     free cells(A-D):  7S  8h  TS  --    home cells(H):  5S  7h  6C  Kd
 857: 
 858:     columns(1-8):  Th  8C  JS  Jh  --  Kh  --  QC
 859:                    9C          TC      KC      7C
 860:                                9h      6S        
 861:                                8S      9S        
 862:                                        QS        
 863:                                        KS        
 864:                                        Qh        
 865:                                        JC        
 866:                                                  
 867: **** p1->p2: legal
 868: user Move 7C from column 8 to Home, Heuristic2 = 5
 869: **** p2->p1: 8H
 870:     free cells(A-D):  7S  8h  TS  --    home cells(H):  5S  7h  7C  Kd
 871: 
 872:     columns(1-8):  Th  8C  JS  Jh  --  Kh  --  QC
 873:                    9C          TC      KC        
 874:                                9h      6S        
 875:                                8S      9S        
 876:                                        QS        
 877:                                        KS        
 878:                                        Qh        
 879:                                        JC        
 880:                                                  
 881: **** p1->p2: legal
 882: user Move 8C from column 2 to Home, Heuristic2 = 5
 883: **** p2->p1: 2H
 884:     free cells(A-D):  7S  8h  TS  --    home cells(H):  5S  7h  8C  Kd
 885: 
 886:     columns(1-8):  Th  --  JS  Jh  --  Kh  --  QC
 887:                    9C          TC      KC        
 888:                                9h      6S        
 889:                                8S      9S        
 890:                                        QS        
 891:                                        KS        
 892:                                        Qh        
 893:                                        JC        
 894:                                                  
 895: **** p1->p2: legal
 896: user Move 9C from column 1 to Home, Heuristic2 = 5
 897: **** p2->p1: 1H
 898:     free cells(A-D):  7S  8h  TS  --    home cells(H):  5S  7h  9C  Kd
 899: 
 900:     columns(1-8):  Th  --  JS  Jh  --  Kh  --  QC
 901:                                TC      KC        
 902:                                9h      6S        
 903:                                8S      9S        
 904:                                        QS        
 905:                                        KS        
 906:                                        Qh        
 907:                                        JC        
 908:                                                  
 909: **** p1->p2: legal
 910: user Move 8h from free B to Home, Heuristic2 = 5
 911: **** p2->p1: BH
 912:     free cells(A-D):  7S  --  TS  --    home cells(H):  5S  8h  9C  Kd
 913: 
 914:     columns(1-8):  Th  --  JS  Jh  --  Kh  --  QC
 915:                                TC      KC        
 916:                                9h      6S        
 917:                                8S      9S        
 918:                                        QS        
 919:                                        KS        
 920:                                        Qh        
 921:                                        JC        
 922:                                                  
 923: **** p1->p2: legal
 924: user Move JC from column 6 to free B, Heuristic2 = 4
 925: **** p2->p1: 6B
 926:     free cells(A-D):  7S  JC  TS  --    home cells(H):  5S  8h  9C  Kd
 927: 
 928:     columns(1-8):  Th  --  JS  Jh  --  Kh  --  QC
 929:                                TC      KC        
 930:                                9h      6S        
 931:                                8S      9S        
 932:                                        QS        
 933:                                        KS        
 934:                                        Qh        
 935:                                                  
 936: **** p1->p2: legal
 937: user Move Qh from column 6 to free D, Heuristic2 = 3
 938: **** p2->p1: 6D
 939:     free cells(A-D):  7S  JC  TS  Qh    home cells(H):  5S  8h  9C  Kd
 940: 
 941:     columns(1-8):  Th  --  JS  Jh  --  Kh  --  QC
 942:                                TC      KC        
 943:                                9h      6S        
 944:                                8S      9S        
 945:                                        QS        
 946:                                        KS        
 947:                                                  
 948: **** p1->p2: legal
 949: user Move KS from column 6 to column 2, Heuristic2 = 2
 950: **** p2->p1: 62
 951:     free cells(A-D):  7S  JC  TS  Qh    home cells(H):  5S  8h  9C  Kd
 952: 
 953:     columns(1-8):  Th  KS  JS  Jh  --  Kh  --  QC
 954:                                TC      KC        
 955:                                9h      6S        
 956:                                8S      9S        
 957:                                        QS        
 958:                                                  
 959: **** p1->p2: legal
 960: user Move QS from column 6 to column 5, Heuristic2 = 1
 961: **** p2->p1: 65
 962:     free cells(A-D):  7S  JC  TS  Qh    home cells(H):  5S  8h  9C  Kd
 963: 
 964:     columns(1-8):  Th  KS  JS  Jh  QS  Kh  --  QC
 965:                                TC      KC        
 966:                                9h      6S        
 967:                                8S      9S        
 968:                                                  
 969: **** p1->p2: legal
 970: user Move 9S from column 6 to column 1, Heuristic2 = 0
 971: **** p2->p1: 61
 972:     free cells(A-D):  7S  JC  TS  Qh    home cells(H):  5S  8h  9C  Kd
 973: 
 974:     columns(1-8):  Th  KS  JS  Jh  QS  Kh  --  QC
 975:                    9S          TC      KC        
 976:                                9h      6S        
 977:                                8S                
 978:                                                  
 979: **** p1->p2: legal
 980: user Solution part 2 of length 17 found!
 981: user Move 6S from column 6 to Home
 982: **** p2->p1: 6H
 983:     free cells(A-D):  7S  JC  TS  Qh    home cells(H):  6S  8h  9C  Kd
 984: 
 985:     columns(1-8):  Th  KS  JS  Jh  QS  Kh  --  QC
 986:                    9S          TC      KC        
 987:                                9h                
 988:                                8S                
 989:                                                  
 990: **** p1->p2: legal
 991: user Move 7S from free A to Home
 992: **** p2->p1: AH
 993:     free cells(A-D):  --  JC  TS  Qh    home cells(H):  7S  8h  9C  Kd
 994: 
 995:     columns(1-8):  Th  KS  JS  Jh  QS  Kh  --  QC
 996:                    9S          TC      KC        
 997:                                9h                
 998:                                8S                
 999:                                                  
1000: **** p1->p2: legal
1001: user Move 8S from column 4 to Home
1002: **** p2->p1: 4H
1003:     free cells(A-D):  --  JC  TS  Qh    home cells(H):  8S  8h  9C  Kd
1004: 
1005:     columns(1-8):  Th  KS  JS  Jh  QS  Kh  --  QC
1006:                    9S          TC      KC        
1007:                                9h                
1008:                                                  
1009: **** p1->p2: legal
1010: user Move 9S from column 1 to Home
1011: **** p2->p1: 1H
1012: **** p1->p2: legal
1013:     free cells(A-D):  --  JC  TS  Qh    home cells(H):  9S  8h  9C  Kd
1014: 
1015:     columns(1-8):  Th  KS  JS  Jh  QS  Kh  --  QC
1016:                                TC      KC        
1017:                                9h                
1018:                                                  
1019: user Move 9h from column 4 to Home
1020: **** p2->p1: 4H
1021: **** p1->p2: legal
1022:     free cells(A-D):  --  JC  TS  Qh    home cells(H):  9S  9h  9C  Kd
1023: 
1024:     columns(1-8):  Th  KS  JS  Jh  QS  Kh  --  QC
1025:                                TC      KC        
1026:                                                  
1027: user Move Th from column 1 to Home
1028: **** p2->p1: 1H
1029: **** p1->p2: legal
1030:     free cells(A-D):  --  JC  TS  Qh    home cells(H):  9S  Th  9C  Kd
1031: 
1032:     columns(1-8):  --  KS  JS  Jh  QS  Kh  --  QC
1033:                                TC      KC        
1034:                                                  
1035: user Move TC from column 4 to Home
1036: **** p2->p1: 4H
1037: **** p1->p2: legal
1038:     free cells(A-D):  --  JC  TS  Qh    home cells(H):  9S  Th  TC  Kd
1039: 
1040:     columns(1-8):  --  KS  JS  Jh  QS  Kh  --  QC
1041:                                        KC        
1042:                                                  
1043: user Move Jh from column 4 to Home
1044: **** p2->p1: 4H
1045: **** p1->p2: legal
1046:     free cells(A-D):  --  JC  TS  Qh    home cells(H):  9S  Jh  TC  Kd
1047: 
1048:     columns(1-8):  --  KS  JS  --  QS  Kh  --  QC
1049:                                        KC        
1050:                                                  
1051: user Move TS from free C to Home
1052: **** p2->p1: CH
1053: **** p1->p2: legal
1054:     free cells(A-D):  --  JC  --  Qh    home cells(H):  TS  Jh  TC  Kd
1055: 
1056:     columns(1-8):  --  KS  JS  --  QS  Kh  --  QC
1057:                                        KC        
1058:                                                  
1059: user Move JS from column 3 to Home
1060: **** p2->p1: 3H
1061: **** p1->p2: legal
1062:     free cells(A-D):  --  JC  --  Qh    home cells(H):  JS  Jh  TC  Kd
1063: 
1064:     columns(1-8):  --  KS  --  --  QS  Kh  --  QC
1065:                                        KC        
1066:                                                  
1067: user Move QS from column 5 to Home
1068: **** p2->p1: 5H
1069: **** p1->p2: legal
1070:     free cells(A-D):  --  JC  --  Qh    home cells(H):  QS  Jh  TC  Kd
1071: 
1072:     columns(1-8):  --  KS  --  --  --  Kh  --  QC
1073:                                        KC        
1074:                                                  
1075: user Move KS from column 2 to Home
1076: **** p2->p1: 2H
1077: **** p1->p2: legal
1078:     free cells(A-D):  --  JC  --  Qh    home cells(H):  KS  Jh  TC  Kd
1079: 
1080:     columns(1-8):  --  --  --  --  --  Kh  --  QC
1081:                                        KC        
1082:                                                  
1083: user Move Qh from free D to Home
1084: **** p2->p1: DH
1085: **** p1->p2: legal
1086:     free cells(A-D):  --  JC  --  --    home cells(H):  KS  Qh  TC  Kd
1087: 
1088:     columns(1-8):  --  --  --  --  --  Kh  --  QC
1089:                                        KC        
1090:                                                  
1091: user Move JC from free B to Home
1092: **** p2->p1: BH
1093: **** p1->p2: legal
1094:     free cells(A-D):  --  --  --  --    home cells(H):  KS  Qh  JC  Kd
1095: 
1096:     columns(1-8):  --  --  --  --  --  Kh  --  QC
1097:                                        KC        
1098:                                                  
1099: user Move QC from column 8 to Home
1100: **** p2->p1: 8H
1101: **** p1->p2: legal
1102:     free cells(A-D):  --  --  --  --    home cells(H):  KS  Qh  QC  Kd
1103: 
1104:     columns(1-8):  --  --  --  --  --  Kh  --  --
1105:                                        KC        
1106:                                                  
1107: user Move KC from column 6 to Home
1108: **** p2->p1: 6H
1109:     free cells(A-D):  --  --  --  --    home cells(H):  KS  Qh  KC  Kd
1110: 
1111:     columns(1-8):  --  --  --  --  --  Kh  --  --
1112:                                                  
1113: **** p1->p2: legal
1114: user Move Kh from column 6 to Home
1115: **** p2->p1: 6H
1116: **** p1->p2: solved
1117:     free cells(A-D):  --  --  --  --    home cells(H):  KS  Kh  KC  Kd
1118: 
1119:     columns(1-8):  --  --  --  --  --  --  --  --
1120: Process 1 exit code = 0 for "bin\freecell.exe -v -r 13 -s 1189379139"
1121: Process 2 exit code = 0 for "bin\freecell_solver.exe -c -h 2"
1122: Finished at 23:39:13.73
1123: 
Email: steve@oharasteve.com