home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / XAP / XGAMES / SPIDER.TAR / spider / movelog.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-09-28  |  17.9 KB  |  987 lines

  1. /*
  2.  *    Spider
  3.  *
  4.  *    (c) Copyright 1989, Donald R. Woods and Sun Microsystems, Inc.
  5.  *    (c) Copyright 1990, David Lemke and Network Computing Devices Inc.
  6.  *
  7.  *    See copyright.h for the terms of the copyright.
  8.  *
  9.  *    @(#)movelog.c    2.3    91/05/09
  10.  *
  11.  */
  12.  
  13. /*
  14.  * move logging code & save/restore
  15.  */
  16.  
  17. #include    "defs.h"
  18. #include    "globals.h"
  19. #include    <string.h>
  20. #include    <sys/file.h>
  21. #include    <ctype.h>
  22. #ifdef SVR4
  23. #include    <unistd.h>
  24. #endif
  25.  
  26. #define    CACHE_SIZE    50
  27. static int    move_index = 0;
  28. static int    *move_cache = NULL;
  29. static int    cache_size = 0;
  30.  
  31. int    deck_cache[NUM_CARDS];
  32. int    deck_index = 0;
  33.  
  34. extern int    cheat_count;
  35.  
  36. make_deck_cache()
  37. {
  38. CardPtr    tmp;
  39.  
  40.     deck_index = 0;
  41.     tmp = deck->cards;
  42.     while(tmp)    {
  43.         deck_cache[deck_index++] = card_to_int(tmp);
  44.         tmp = tmp->next;
  45.     }
  46. }
  47.  
  48. init_cache()
  49. {
  50.     if (cache_size)
  51.         free((char *)move_cache);
  52.     move_cache = (int *) calloc(CACHE_SIZE, sizeof(int));
  53.     cache_size = CACHE_SIZE;
  54.     move_index = 0;
  55. }
  56.  
  57. grow_cache()
  58. {
  59. int    *new;
  60.  
  61.     cache_size += CACHE_SIZE;
  62.     new = (int *) realloc((char *)move_cache, 
  63.                 (unsigned)(cache_size * sizeof(int)));
  64.     if (new == (int *) NULL)    {
  65.         (void)fprintf(stderr,"realloc failed\n");
  66.         exit(-1);
  67.     }
  68.     move_cache = new;
  69. }
  70.  
  71. record(from, dest, num_cards, exposed)
  72. int    from, dest, num_cards;
  73. Bool    exposed;
  74. {
  75. int    val;
  76.  
  77.     val = 11 * ( 11 * ((exposed ? 1 : 0) * 14 + num_cards) + dest) + from;
  78.     move_cache[move_index++] = val;
  79.     if (move_index >= cache_size)
  80.         grow_cache();
  81. }
  82.  
  83. unencode(val, from, dest, num_cards, exposed)
  84. int    val;
  85. int    *from, *dest, *num_cards;
  86. Bool    *exposed;
  87. {
  88.     *from = val % 11;
  89.     val /= 11;
  90.     *dest = val % 11;
  91.     val /= 11;
  92.     *num_cards = val % 14;
  93.     *exposed = (val >= 14);
  94. }
  95.  
  96. undo()
  97. {
  98. int    val;
  99. int    from, dest, num_cards;
  100. Bool    exposed;
  101.  
  102.     if (move_index == 0)    {
  103.         show_message("No moves available to back up over.");
  104.         spider_bell(dpy, 0);
  105.         return;
  106.     }
  107.     val = move_cache[--move_index];
  108.     if (val > 11 * 11 * 14)    {
  109.         show_message("Cheater!");
  110.         cheat_count++;
  111.         spider_bell(dpy, 0);
  112.     }
  113.     unencode(val, &from, &dest, &num_cards, &exposed);
  114.  
  115.     if (from == 0)    {    /* undo deal */
  116.         undo_deal();
  117.         show_message("Cheater!");
  118.         cheat_count++;
  119.         spider_bell(dpy, 0);
  120.     } else    {
  121.         /*
  122.          * note that cols are from 0-9, but saved as 1-10,
  123.          * so we decrement here before doing the work
  124.          */
  125.         if (dest == 0)    {
  126.             undo_suit(from - 1, exposed);
  127.         } else    {
  128.             undo_normal(from - 1, dest - 1, num_cards, exposed);
  129.         }
  130.     }
  131. }
  132.  
  133. /*
  134.  * undoes latest deal
  135.  */
  136. undo_deal()
  137. {
  138. int    i;
  139. CardPtr    tmp;
  140.  
  141.     for (i = (NUM_STACKS - 1); i >= 0; i--)    {
  142.         tmp = last_card(stack[i]);
  143.         remove_card(tmp);
  144.         add_card(tmp, deck->cards, LOC_BEFORE, deck);
  145.         flip_card(tmp, Facedown);
  146.  
  147.         /* fix up stack */
  148.         if (stack[i]->card_delta != CARD_DELTA)    {
  149.             recompute_list_deltas(stack[i]);
  150.             show_list(stack[i], stack[i]->cards);
  151.         } else    {
  152.             show_list(stack[i], last_card(stack[i]));
  153.         }
  154.     }
  155.     deal_number--;
  156.     deck_index += 10;
  157. }
  158.  
  159. /*
  160.  * pulls suit back down from pile
  161.  */
  162. undo_suit(from, exposed)
  163. int    from;
  164. Bool    exposed;
  165. {
  166. int    i;
  167.  
  168.     if (exposed)
  169.         flip_card(last_card(stack[from]), Facedown);
  170.  
  171.     for (i = (NUM_PILES - 1); i >= 0; i--)    {
  172.         if (piles[i]->cards)    {
  173.             move_to_list(piles[i]->cards, stack[from], False);
  174.             break;
  175.         }
  176.     }
  177. }
  178.  
  179. undo_normal(from, dest, num_cards, exposed)
  180. int    from, dest, num_cards;
  181. Bool    exposed;
  182. {
  183. CardPtr    tmp;
  184.  
  185.     if (exposed)
  186.         flip_card(last_card(stack[from]), Facedown);
  187.     tmp = last_card(stack[dest]);
  188.  
  189.     /* get start of run to move */
  190.     while (--num_cards)    {
  191.         tmp = tmp->prev;
  192.     }
  193.  
  194.     move_to_list(tmp, stack[from], False);
  195. }
  196.  
  197. /* file I/O */
  198.  
  199. /*
  200.  * this was teken from the NeWS version of spider, which copied
  201.  * it verbatim from the Mesa version, so they'll all work together.
  202.  * but the results of 2 language translations gets a bit messy...
  203.  */
  204.  
  205. static int    hash_card();
  206. static int    char_index = 0;
  207. static int    prev_hash = 0;
  208.  
  209. #define    EOS    0xffff        /* end of seq flag */
  210. #define    FUS    0xeeee        /* flag to say rest of seq is faceup */
  211.  
  212. static int
  213. hash_card(val)
  214. int    val;
  215. {
  216. int    ret;
  217.  
  218.     char_index += 5;
  219.  
  220.     ret = ((val ^ prev_hash) ^ (char_index % 4) + (char_index * 4)) & 077;
  221.  
  222.     return (ret);
  223. }
  224.  
  225. static    int*
  226. read_sequence(str)
  227. char    *str;
  228. {
  229. int    i, len;
  230. int    *seq, *seqp;
  231. int    val;
  232.  
  233.     len = strlen(str);
  234.     /* need number of cards plus EOS and FUS */
  235.     seqp = seq = (int *)calloc((unsigned)(len + 2), sizeof(int));
  236.     if (strchr(str, '/') == NULL)    {    /* if no '/', all are faceup */
  237.         *seqp++ = FUS;
  238.     }
  239.     for (i = 0; i < len; i++)    {
  240.         if (str[i] == '/')    {    /* flag '/' */
  241.             *seqp++ = FUS;
  242.             continue;
  243.         }
  244.         if (!(str[i] >= '0' && str[i] <= 'o'))    {
  245.             return NULL;
  246.         }
  247.         val = (int) (str[i] - '0');
  248.         val = hash_card(val);
  249.         prev_hash = val;
  250.         *seqp++ = ((13 - val/4) + ((3 - val % 4) * 13)) % 52;
  251.     }
  252.     *seqp = EOS;
  253.     return (seq);
  254. }
  255.  
  256. static void
  257. write_sequence(fp, seq)
  258. FILE    *fp;
  259. int    *seq;
  260. {
  261. int    *seqp;
  262. char    c;
  263. int    val;
  264.  
  265.     seqp = seq;
  266.     while (*seqp != EOS)    {
  267.         if (*seqp == FUS)    {
  268.             (void)fputc('/', fp);
  269.             seqp++;
  270.             continue;
  271.         }
  272.         val = *seqp;
  273.         val = (3 - val/13) + ((13 - val % 13) * 4);
  274.         c = (char) hash_card(val) + '0';
  275.         prev_hash = val;
  276.         assert (c >= '0' && c <= 'o');
  277.         /* depend on file buffering to make this efficient */
  278.         (void)fputc(c, fp);    
  279.         seqp++;
  280.     }
  281. }
  282.  
  283. Rank    flip_ranks[NUM_RANKS] =    {
  284.     King, Queen, Jack, Ten, Nine, Eight, Seven, 
  285.     Six, Five, Four, Three, Deuce, Ace
  286. };
  287.  
  288. static void
  289. int_to_card(val, suit, rank)
  290. int    val;
  291. Suit    *suit;
  292. Rank    *rank;
  293. {
  294.     *suit = val / 13;
  295.     *rank = val % 13;
  296.     *rank = flip_ranks[*rank];
  297.     assert (*suit >= Spade && *suit <= Club);
  298.     assert (*rank >= Ace && *suit <= King);
  299. }
  300.  
  301. static int
  302. card_to_int(card)
  303. CardPtr    card;
  304. {
  305. int    val;
  306.  
  307.     val = card->suit * 13 + flip_ranks[card->rank];
  308.     return (val);
  309. }
  310.  
  311. static CardPtr
  312. find_card(cache, suit, rank)
  313. CardPtr    *cache;
  314. Suit    suit;
  315. Rank    rank;
  316. {
  317. int    i;
  318. CardPtr    tmp = CARDNULL;
  319.  
  320.     for (i = 0; i < NUM_CARDS; i++)    {
  321.         if (cache[i] == CARDNULL)
  322.             continue;
  323.         else if ((cache[i]->suit == suit) && 
  324.             (cache[i]->rank == rank))    {
  325.             tmp = cache[i];
  326.             cache[i] = CARDNULL;
  327.             break;
  328.         }
  329.     }
  330.     return (tmp);
  331. }
  332.  
  333. /*
  334.  * get all the cards back in the deck to recover from something
  335.  * evil in the restore process
  336.  */
  337. static void
  338. recover(cache)
  339. CardPtr    *cache;
  340. {
  341. int    i;
  342.  
  343.     for (i = 0; i < NUM_CARDS; i++)    {
  344.         if (cache[i])    {
  345.             cache[i]->type = Facedown;
  346.             add_card(cache[i], deck->cards, LOC_END, deck);
  347.         }
  348.     }
  349. }
  350.  
  351. static int
  352. read_position(str)
  353. char    *str;
  354. {
  355. char    *tmp;
  356. char    *card_str, *cards_left;
  357. int    *seq, *seqp;
  358. CardPtr    card;
  359. CardPtr    cache[NUM_CARDS];
  360. Suit    suit;
  361. Rank    rank;
  362. Type    type;
  363. int    i, num_dealt, num_undealt;
  364. int    dealt[NUM_CARDS], undealt[NUM_CARDS];
  365.  
  366.     prev_hash = 0;
  367.     char_index = 0;
  368.     deck_index = 0;
  369.  
  370.     /* stash all cards temporarily */
  371.     remove_all_cards(cache);
  372.  
  373.     /* deck is everything up to a ' ' */
  374.     tmp = strchr(str, ' ');
  375.     if (tmp == NULL)    {        /* bad data */
  376.         recover(cache);
  377.         return (-1);
  378.     }
  379.     card_str = calloc((unsigned)(tmp - str + 1), 1);
  380.     (void)strncpy(card_str, str, tmp - str);
  381.  
  382.     /*
  383.      * first read in the hand.  first come the undealt cards, then
  384.      * the dealt cards.  the first undealt is the next one that 
  385.      * will be dealt, and the first dealt card is the first card that 
  386.      * was dealt
  387.      */
  388.     seq = read_sequence(card_str);
  389.     if (seq == NULL)    {
  390.         recover(cache);
  391.         return (-1);
  392.     }
  393.     free(card_str);
  394.     seqp = seq;
  395.     num_undealt = 0;
  396.     while (*seqp != FUS)    {    /* stop at dealt cards */
  397.         undealt[num_undealt++] = *seqp;
  398.         int_to_card(*seqp, &suit, &rank);
  399.         card = find_card(cache, suit, rank);
  400.         if (card == CARDNULL)    {
  401.             recover(cache);
  402.             return (-1);
  403.         }
  404.         card->type = Facedown;
  405.         add_card(card, deck->cards, LOC_END, deck);
  406.         seqp++;
  407.     }
  408.     seqp++;
  409.  
  410.     num_dealt = 0;
  411.     while (*seqp != EOS)    {
  412.         dealt[num_dealt++] = *seqp;
  413.         seqp++;
  414.     }
  415.     assert (num_dealt + num_undealt == NUM_CARDS);
  416.  
  417.     /* reverse the dealt cards and stick them in cache */
  418.     while (--num_dealt >= 0)    {
  419.         deck_cache[deck_index++] = dealt[num_dealt];
  420.     }
  421.     for (i = 0; i < num_undealt; i++)    {
  422.         deck_cache[deck_index++] = undealt[i];
  423.     }
  424.     assert(deck_index == NUM_CARDS);
  425.     deck_index = num_undealt;
  426.     /* reset deal_number correctly */
  427.     deal_number = 6 - deck_index/10;
  428.  
  429.     free((char *)seq);
  430.  
  431.     /*
  432.      * now deal with the stacks
  433.      */
  434.     cards_left = tmp;
  435.     cards_left++;        /* skip space */
  436.  
  437.     /* deal with each stack */
  438.     for (i = 0; i < 10; i++)    {
  439.         stack[i]->card_delta = CARD_DELTA;    /* restore delta */
  440.         type = Facedown;
  441.         tmp = strchr(cards_left, ' ');
  442.  
  443.         /* deal with '.' at end of string */
  444.         if (tmp == NULL)    {
  445.             tmp = strchr(cards_left, '.');
  446.             if (tmp == NULL)    {        /* bad data */
  447.                 recover(cache);
  448.                 return (-1);
  449.             }
  450.         }
  451.         if (tmp == cards_left)    {    /* empty col */
  452.             cards_left++;
  453.             continue;
  454.         }
  455.  
  456.         /* make local copy of stack */
  457.         card_str = calloc((unsigned)((tmp - cards_left) + 1), 1);
  458.         (void)strncpy(card_str, cards_left, tmp - cards_left);
  459.         cards_left = tmp + 1;
  460.  
  461.         seqp = seq = read_sequence(card_str);
  462.         if (seq == NULL)    {
  463.             recover(cache);
  464.             return (-1);
  465.         }
  466.         while (*seqp != FUS && *seqp != EOS)    {
  467.             int_to_card(*seqp, &suit, &rank);
  468.             card = find_card(cache, suit, rank);
  469.             if (card == CARDNULL)    {
  470.                 recover(cache);
  471.                 return (-1);
  472.             }
  473.             card->type = type;
  474.             add_card(card, stack[i]->cards, LOC_END, stack[i]);
  475.             seqp++;
  476.         }
  477.  
  478.         /* handle faceup cards */
  479.         if (*seqp != EOS)    {
  480.             seqp++;        /* skip FUS */
  481.             type = Faceup;
  482.             while (*seqp != EOS)    {
  483.                 int_to_card(*seqp, &suit, &rank);
  484.                 card = find_card(cache, suit, rank);
  485.                 if (card == CARDNULL)    {
  486.                     recover(cache);
  487.                     return (-1);
  488.                 }
  489.                 card->type = type;
  490.                 add_card(card, stack[i]->cards, LOC_END, 
  491.                     stack[i]);
  492.                 seqp++;
  493.             }
  494.         }
  495.         free((char *)seq);
  496.         free(card_str);
  497.     }
  498.  
  499.     /* deal with remaining stuff -- should all be piles */
  500.     if (*tmp != '.')    {
  501.         assert (*tmp == ' ');
  502.         tmp = strchr(cards_left, '.');
  503.         if (tmp == NULL)    {        /* bad data */
  504.             recover(cache);
  505.             return (-1);
  506.         }
  507.         /* make local copy of piles */
  508.         card_str = calloc((unsigned)((tmp - cards_left) + 1), 1);
  509.         (void)strncpy(card_str, cards_left, tmp - cards_left);
  510.         cards_left = tmp + 1;
  511.         type = Faceup;
  512.  
  513.         seqp = seq = read_sequence(card_str);
  514.         if (seq == NULL)    {
  515.             recover(cache);
  516.             return (-1);
  517.         }
  518.         i = 0;
  519.         while (*seqp != EOS)    {
  520.             if (*seqp == FUS)    {
  521.                 seqp++;
  522.                 continue;
  523.             }
  524.             int_to_card(*seqp, &suit, &rank);
  525.             assert(rank == Ace);
  526.             for (rank = Ace; rank <= King; rank++)    {
  527.                 card = find_card(cache, suit, rank);
  528.                 if (card == CARDNULL)    {
  529.                     recover(cache);
  530.                     return (-1);
  531.                 }
  532.                 card->type = type;
  533.                 add_card(card, piles[i]->cards, LOC_START, 
  534.                     piles[i]);
  535.             }
  536.             seqp++;
  537.             i++;
  538.         }
  539.     }
  540.  
  541.     return (0);
  542. }
  543.  
  544. static void
  545. read_moves(str)
  546. char    *str;
  547. {
  548. char    *s;
  549.     
  550.     s = str;
  551.     while (*s != '.')    {
  552.         move_cache[move_index++] = (int)(*s - '0') * 64 + 
  553.             (int)(*(s+1) - '0');
  554.         assert (move_cache[move_index - 1] >= 0);
  555.         if (move_index >= cache_size)
  556.             grow_cache();
  557.         s += 2;
  558.     }
  559. }
  560.  
  561. static void
  562. write_moves(fp)
  563. FILE    *fp;
  564. {
  565. int    i;
  566. int    val;
  567.  
  568.     for (i = 0; i < move_index; i++)    {
  569.         val = move_cache[i];
  570.         (void)fputc((char)(val/64 + '0'), fp);
  571.         (void)fputc((char)(val%64 + '0'), fp);
  572.     }
  573. }
  574.  
  575. write_file(fname, confirmer)
  576. char    *fname;
  577. Bool    (*confirmer)();
  578. {
  579. FILE    *fp;
  580. char    buf[512];
  581. int    i, num;
  582. int    seq[1024], *seqp;
  583. CardPtr    tmp;
  584.  
  585.     fname = remove_newlines(fname);
  586.  
  587.     if (access(fname, F_OK) == 0)    {
  588.         if ((*confirmer)())    {
  589.             show_message("Overwriting existing file.");
  590.         } else    {
  591.             show_message("Cancelling save.");
  592.             return;
  593.         }
  594.     }
  595.  
  596.     if ((fp = fopen(fname, "w")) == NULL)    {
  597.         (void)sprintf(buf, "Can't open output file \"%s\".", fname);
  598.         show_message(buf);
  599.         return;
  600.     }
  601.  
  602.     seqp = seq;
  603.  
  604.     prev_hash = 0;
  605.     char_index = 0;
  606.  
  607.     num = NUM_CARDS - deck_index;
  608.     for (i = num; i < NUM_CARDS; i++)    {
  609.         *seqp++ = deck_cache[i];
  610.     }
  611.     *seqp++ = FUS;
  612.     for (i = (num - 1); i >= 0; i--)    {
  613.         *seqp++ = deck_cache[i];
  614.     }
  615.  
  616.     *seqp = EOS;
  617.     write_sequence(fp, seq);
  618.     seqp = seq;
  619.  
  620.  
  621.     for (i = 0; i < NUM_STACKS; i++)    {
  622.         (void)fputc(' ', fp);
  623.         tmp = stack[i]->cards;
  624.         seqp = seq;
  625.         if (tmp)    {
  626.             while (tmp->type == Facedown)    {
  627.                 *seqp++ = card_to_int(tmp);
  628.                 tmp = tmp->next;
  629.             }
  630.             if (seqp != seq)    {
  631.                 *seqp++ = FUS;
  632.             }
  633.  
  634.             while (tmp)    {
  635.                 *seqp++ = card_to_int(tmp);
  636.                 tmp = tmp->next;
  637.             }
  638.  
  639.             if (seqp != seq)    {
  640.                 *seqp = EOS;
  641.                 write_sequence(fp, seq);
  642.             }
  643.         }
  644.     }
  645.  
  646.     /* save piles */
  647.     seqp = seq;
  648.     for (i = 0; i < NUM_PILES; i++)    {
  649.         if (piles[i]->cards)    {
  650.             *seqp++ = card_to_int(last_card(piles[i]));
  651.         }
  652.     }
  653.     if (seqp != seq)    {
  654.         *seqp = EOS;
  655.         (void)fputc(' ', fp);
  656.         write_sequence(fp, seq);
  657.     }
  658.     fputs(".\n", fp);
  659.  
  660.     /* write out the moves */
  661.     write_moves(fp);
  662.     fputs(".\n\n", fp);
  663.  
  664.     /* write human readable version */
  665.     write_human(fp);
  666.     (void)fclose(fp);
  667.     (void)sprintf(buf, "Position saved to file \"%s\".", fname);
  668.     show_message(buf);
  669. }
  670.  
  671. write_human(fp)
  672. FILE    *fp;
  673. {
  674. CardPtr    tmps[NUM_STACKS];
  675. int    i;
  676. int    done = 0;
  677. Bool    toprow = True;
  678.  
  679.     for (i = 0; i < NUM_STACKS; i++)    {
  680.         tmps[i] = stack[i]->cards;
  681.     }
  682.  
  683.     while (done < NUM_STACKS)    {
  684.         done = 0;
  685.         for (i = 0; i < NUM_STACKS; i++)    {
  686.             if (tmps[i] == CARDNULL)    {
  687.                 /* empty stack */
  688.                 if (toprow)    {
  689.                     fputs("(sp)\t", fp);
  690.                 } else    {
  691.                     (void)fputc('\t', fp);
  692.                 }
  693.                 done++;
  694.                 continue;
  695.             } else    {
  696.                 if (tmps[i]->type == Facedown)    {
  697.                     fputs(" --", fp);
  698.                 } else    {
  699.                     (void)fprintf(fp, "%2s%c", 
  700.                         rnk_name(tmps[i]->rank),
  701.                         tolower(*suit_name(tmps[i]->suit)));
  702.                 }
  703.             }
  704.             (void)fputc('\t', fp);
  705.             tmps[i] = tmps[i]->next;
  706.         }
  707.         (void)fputc('\n', fp);
  708.         toprow = False;
  709.     }
  710. }
  711.  
  712. read_selection(buf)
  713. char    *buf;
  714. {
  715. char    *moves;
  716.  
  717.     buf = remove_newlines(buf);
  718.     moves = strchr(buf, '.');
  719.     if (moves)
  720.         moves++;
  721.     if (moves && !strchr(moves, '.'))
  722.         moves = NULL;
  723.     if (restore_game(buf, moves) != 0)    {
  724.         show_message("Bogus data in selection.");
  725.         restart = True;
  726.     } else    {
  727.         show_message("Position loaded from selection.");
  728.     }
  729.     free(buf);
  730. }
  731.  
  732. read_file_or_selection(fname)
  733. char    *fname;
  734. {
  735.     if (access(fname, R_OK) == -1)    {
  736.         read_selection(fname);
  737.     } else    {
  738.         read_file(fname);
  739.     }
  740. }
  741.  
  742. read_file(fname)
  743. char    *fname;
  744. {
  745. FILE    *fp;
  746. char    buf[1024], buf2[1024];
  747. char    *dp;
  748.  
  749.     fname = remove_newlines(fname);
  750.     if ((fp = fopen(fname, "r")) == NULL)    {
  751.         (void)sprintf(buf, "Can't open file \"%s\" for loading.", 
  752.                 fname);
  753.         show_message(buf);
  754.         return;
  755.     }
  756.  
  757.     /* read card string */
  758.     dp = buf;
  759.     while ((*dp = (char)fgetc(fp)) != EOF)    {
  760.         if (*dp == '\n')    /* ignore any CR */
  761.             continue;
  762.         if (*dp == '.')
  763.             break;
  764.         dp++;
  765.     }
  766.     *++dp = '\0';
  767.  
  768.     /* read moves string */
  769.     dp = buf2;
  770.     while ((*dp = (char)fgetc(fp)) != EOF)    {
  771.         if (*dp == '\n')    /* ignore any CR */
  772.             continue;
  773.         if (*dp == '.')
  774.             break;
  775.         dp++;
  776.     }
  777.     *++dp = '\0';
  778.  
  779.     if (restore_game(buf, buf2) == 0)    {
  780.         (void)sprintf(buf, "Saved game \"%s\" loaded.", fname);
  781.     } else    {
  782.         (void)sprintf(buf, "Bogus save file \"%s\".", fname);
  783.         restart = True;
  784.     }
  785.  
  786.     show_message(buf);
  787. }
  788.  
  789. static int
  790. restore_game(str, str2)
  791. char    *str, *str2;
  792. {
  793.  
  794.     if (read_position(str) != 0)    {
  795.         return (-1);
  796.     }
  797.  
  798.     init_cache();        /* clear out the move cache */
  799.  
  800.     if (str2)
  801.         read_moves(str2);
  802.  
  803.     return (0);
  804. }
  805.  
  806. /*
  807.  * play the same deck again
  808.  */
  809. int
  810. replay()
  811. {
  812. CardPtr    cache[NUM_CARDS];
  813. CardPtr    card;
  814. int    i;
  815. Rank    rank;
  816. Suit    suit;
  817.  
  818.     remove_all_cards(cache);
  819.  
  820.     /* reset card spacing */
  821.     for (i = 0; i < NUM_STACKS; i++)    {
  822.         stack[i]->card_delta = CARD_DELTA;
  823.     }
  824.  
  825.     for (i = 0; i < NUM_CARDS; i++)    {
  826.         int_to_card(deck_cache[i], &suit, &rank);
  827.         card = find_card(cache, suit, rank);
  828.         if (card == CARDNULL)    {
  829.             show_message("Old deck is corrupted -- can't replay.");
  830.             recover(cache);
  831.             return -1;
  832.         }
  833.         card->type = Facedown;
  834.         add_card(card, deck->cards, LOC_END, deck);
  835.     }
  836.     /* wipe the old stuff */
  837.     XClearArea(dpy, table, 0, 0, table_width, table_height, False);
  838.  
  839.     /* force piles and deck to redraw -- stacks will paint in deal */
  840.     XClearArea(dpy, table, 0, 0, table_width, DECK_Y + CARD_HEIGHT, True);
  841.  
  842.     deck_index = NUM_CARDS;
  843.     deal_number = 0;
  844.     deal_cards();
  845.  
  846.     return 0;
  847. }
  848.  
  849.  
  850. /*
  851.  * replay removing a suit
  852.  */
  853. static void
  854. show_suit(from)
  855. int    from;
  856. {
  857. CardPtr    tmp;
  858. int    i;
  859.  
  860.     tmp = last_card(stack[from]);
  861.     assert (tmp->rank == Ace);
  862.     while (tmp && tmp->rank != King)    {
  863.         tmp = tmp->prev;
  864.     }
  865.     assert (tmp->rank == King);
  866.  
  867.     for (i = 0; i < NUM_PILES; i++)    {
  868.         if (piles[i]->cards == CARDNULL)    {
  869.             break;
  870.         }
  871.     }
  872.     assert (i < NUM_PILES);
  873.  
  874.     move_to_list(tmp, piles[i], False);
  875. }
  876.  
  877. /*
  878.  * replay a normal move
  879.  */
  880. static void
  881. show_normal(from, dest, num)
  882. int    from, dest, num;
  883. {
  884. CardPtr    tmp;
  885.  
  886.     tmp = last_card(stack[from]);
  887.  
  888.     while (--num)    {
  889.         tmp = tmp->prev;
  890.     }
  891.  
  892.     move_to_list(tmp, stack[dest], False);
  893. }
  894.  
  895. #ifdef XVIEW
  896. get_move_index() 
  897. {
  898.         return(move_index);
  899. }
  900.  
  901. Bool
  902. show_n_moves(place, number)
  903. int place, number;
  904. {
  905. int     val;
  906. int     from, dest, num, exposed;
  907. int     i;
  908.  
  909.         for (i=0; i < number; i++) {
  910.                 if ((i+place) > move_index) 
  911.                         return (False);
  912.                 val = move_cache[place + i];
  913.                 unencode(val, &from, &dest, &num, &exposed);
  914.  
  915.                 if (from == 0)  {
  916.                         deal_next_hand(False);
  917.                 } else  {
  918.                         if (dest == 0)  {
  919.                                 show_suit(from - 1);
  920.                         } else  {
  921.                                 show_normal(from - 1, dest - 1, num);
  922.                         }
  923.                 }
  924.         }
  925.         return (True);
  926. }
  927. #else
  928.  
  929. /*
  930.  * show the moves made so far
  931.  *
  932.  * start is the position into the movelog, num is the number of moves
  933.  * (0 specifies all)
  934.  * event_check is the routine that checks for an abort and handles
  935.  * damage, etc.  delay_func pauses as necessary
  936.  */
  937. void
  938. show_play(start, num_moves, event_check, delay_func)
  939. int    start, num_moves;
  940. Bool    (*event_check)();
  941. void    (*delay_func)();
  942. {
  943. int    i;
  944. int    val;
  945. int    from, dest, num, exposed;
  946. Bool    aborted = False;
  947.  
  948.     if (replay() == -1)
  949.         return;
  950.  
  951.     /* handle any events from reseting */
  952.     (void) show_play_events();
  953.  
  954.     show_message("Showing all moves -- hit any key or button to abort");
  955.  
  956.     if (num_moves == 0)    /* show all case */
  957.         num_moves = move_index;
  958.  
  959.     for (i = start; (i < move_index) && (i < (start + num_moves)); i++) {
  960.         val = move_cache[i];
  961.         unencode(val, &from, &dest, &num, &exposed);
  962.  
  963.         if (from == 0)    {
  964.             deal_next_hand(False);
  965.         } else    {
  966.             if (dest == 0)    {
  967.                 show_suit(from - 1);
  968.             } else    {
  969.                 show_normal(from - 1, dest - 1, num);
  970.             }
  971.         }
  972.         if ((*event_check)() == False)    {
  973.             aborted = True;
  974.             /* restore to a known state */
  975.             (void) replay();
  976.             break;
  977.         }
  978.         (*delay_func)();
  979.     }
  980.     if (aborted)    {
  981.         show_message("Aborted -- cleaning up");
  982.     } else    {
  983.         show_message("Replay finished");
  984.     }
  985. }
  986. #endif
  987.