home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / XAP / XGAMES / SPIDER.TAR / spider / spider.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-09-28  |  24.1 KB  |  1,302 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.  *    @(#)spider.c    2.4    91/05/09
  10.  *
  11.  */
  12.  
  13. /*
  14.  * Spider card logic
  15.  */
  16.  
  17. #include    "defs.h"
  18. #include    "globals.h"
  19. #include    <ctype.h>
  20.  
  21. static void    fix_coords();
  22.  
  23. int     deltamod = 0;
  24. Bool    squish = True;
  25. int    cheat_count = 0;
  26.  
  27. /*
  28.  * build all the cards, stacks, piles and the original deck
  29.  */
  30. card_init()
  31. {
  32. int    i;
  33. Suit    suit;
  34. Rank    rank;
  35. CardPtr    tmp, tmp2;
  36.  
  37.     for (i = 0; i < NUM_STACKS; i++)    {
  38.         stack[i] = (CardList) malloc(sizeof(CardListStruct));
  39.         stack[i]->place = i + 11;
  40.         stack[i]->cards = CARDNULL;
  41.         stack[i]->card_delta = CARD_DELTA;
  42.         stack[i]->x = STACK_LOC_X(stack[i]->place);
  43.         stack[i]->y = STACK_LOC_Y;
  44.     }
  45.  
  46.     for (i = 0; i < NUM_PILES; i++)    {
  47.         piles[i] = (CardList) malloc(sizeof(CardListStruct));
  48.         piles[i]->place = i + 1;
  49.         piles[i]->cards = CARDNULL;
  50.         piles[i]->card_delta = 0;
  51.         piles[i]->x = PILE_LOC_X(piles[i]->place);
  52.         piles[i]->y = PILE_LOC_Y;
  53.     }
  54.     deck = (CardList) malloc(sizeof(CardListStruct));
  55.     deck->place = DECK;
  56.     deck->x = DECK_X;
  57.     deck->y = DECK_Y;
  58.     deck->card_delta = 0;
  59.     deck->cards = CARDNULL;
  60.     tmp2 = CARDNULL;
  61.     for (i = 0; i < NUM_DECKS; i++)    {
  62.         for (suit = Spade; suit <= Club; suit++)    {
  63.             for (rank = Ace; rank <= King; rank++)    {
  64.                 tmp = (CardPtr) calloc(sizeof(CardStruct), 1);
  65.                 add_card(tmp, tmp2, LOC_BEFORE, deck);
  66.                 tmp->rank = rank;
  67.                 tmp->suit = suit;
  68.                 tmp->type = Facedown;
  69.                 tmp2 = tmp;
  70.             }
  71.         }
  72.     }
  73.     deck->cards = tmp;
  74.     srandom(getpid());
  75.     shuffle_cards();
  76. }
  77.  
  78. /*
  79.  * randomizes order of deck list
  80.  */
  81.  
  82. struct    shuffle {
  83.     CardPtr    card;
  84.     long    value;
  85. } shuffled_cards[NUM_CARDS];
  86.  
  87. compare(a1, a2)
  88. struct shuffle    *a1, *a2;
  89. {
  90.     return ((a2->value) - (a1->value));
  91. }
  92.  
  93. /*
  94.  * removes all the cards from the table and stcks them in a cache
  95.  */
  96. remove_all_cards(cache)
  97. CardPtr    cache[NUM_CARDS];
  98. {
  99. CardPtr    tmp;
  100. int    i, j;
  101.  
  102.     i = 0;
  103.     while (deck->cards)    {
  104.         tmp = deck->cards;
  105.         remove_card(tmp);
  106.         cache[i++] = tmp;
  107.     }
  108.  
  109.     for (j = 0; j < NUM_PILES; j++)    {
  110.         while (piles[j]->cards)    {
  111.             tmp = piles[j]->cards;
  112.             remove_card(tmp);
  113.             cache[i++] = tmp;
  114.         }
  115.     }
  116.  
  117.     for (j = 0; j < NUM_STACKS; j++)    {
  118.         while (stack[j]->cards)    {
  119.             tmp = stack[j]->cards;
  120.             remove_card(tmp);
  121.             cache[i++] = tmp;
  122.         }
  123.     }
  124.  
  125.     assert(i == NUM_CARDS);
  126. }
  127.  
  128. /*
  129.  * shuffle the cards 
  130.  */
  131. shuffle_cards()
  132. {
  133. int    i;
  134. CardPtr    cache[NUM_CARDS];
  135. extern long    random();
  136.  
  137.     remove_all_cards(cache);
  138.  
  139.     for (i = 0; i < NUM_CARDS; i++)    {
  140.         shuffled_cards[i].card = cache[i];
  141.         shuffled_cards[i].value = random();
  142.     }
  143.  
  144.     qsort((char *) shuffled_cards, NUM_CARDS, sizeof(struct shuffle), 
  145.         compare);
  146.  
  147.     for (i = 0; i < NUM_CARDS; i++)    {
  148.         shuffled_cards[i].card->type = Facedown;
  149.         add_card(shuffled_cards[i].card, deck->cards, LOC_START, deck);
  150.     }
  151.  
  152.     /* save the deal in the save cache */
  153.     make_deck_cache();
  154.  
  155.     /* reset card spacing */
  156.     for (i = 0; i < NUM_STACKS; i++)    {
  157.         stack[i]->card_delta = CARD_DELTA;
  158.     }
  159.  
  160.     /* force things to get fixed up */
  161.     XClearArea(dpy, table, 0, 0, 0, 0, True);
  162.  
  163.     deal_number = 0;
  164.     restart = False;
  165.     cheat_count = 0;
  166.  
  167.     /* reset move log */
  168.     init_cache();
  169. }
  170.  
  171. /*
  172.  * does orginal deal
  173.  */
  174. deal_cards()
  175. {
  176. int    i, j;
  177. int    num;
  178.     
  179.     /*
  180.      * this is the way the original does deals -- weird, but
  181.      * thats compatibility
  182.      */
  183.     for (i = 0; i < NUM_STACKS; i++)    {
  184.         CardPtr    tmp[6];
  185.  
  186.         /* stacks 1, 4, 7, and 10 have 1 extra card */
  187.         if (((i+1) % 3) == 1)    {
  188.             num = 5;
  189.         } else    {
  190.             num = 4;
  191.         }
  192.  
  193.         /* faceup first */
  194.         tmp[num] = deck->cards;
  195.         remove_card(tmp[num]);
  196.         tmp[num]->type = Faceup;
  197.  
  198.         for (j = (num - 1); j >= 0; j--)    {
  199.             tmp[j] = deck->cards;
  200.             remove_card(tmp[j]);
  201.             tmp[j]->type = Facedown;
  202.         }
  203.         for (j = 0; j <= num; j++)    {
  204.             add_card(tmp[j], stack[i]->cards, LOC_END, stack[i]);
  205.         }
  206.     }
  207.     deck_index -= 54;
  208.     deal_number = 1;
  209.  
  210.     /*
  211.      * show the deal
  212.      */
  213.     for (i = 0; i < NUM_STACKS; i++)    {
  214.         show_list(stack[i], stack[i]->cards);
  215.     }
  216. }
  217.  
  218. /*
  219.  * deal hand of 10
  220.  */
  221. deal_next_hand(log)
  222. Bool    log;
  223. {
  224. int    i;
  225. CardPtr    tmp;
  226. char    buf[128];
  227. int    old_delta;
  228.  
  229.     /* be sure all the spaces are filled */
  230.     for (i = 0; i < NUM_STACKS; i++)    {
  231.         if (stack[i]->cards == CARDNULL)    {
  232.             show_message("Can't deal until all spaces are filled");
  233.             spider_bell(dpy, 0);
  234.             return;
  235.         }
  236.     }
  237.     if (deck->cards == CARDNULL)    {
  238.         /* dealt them all */
  239.         show_message("No more cards in deck");
  240.         spider_bell(dpy, 0);
  241.         return;
  242.     }
  243.     /* deal face up cards */
  244.     for (i = 0; i < NUM_STACKS; i++)    {
  245.         old_delta = stack[i]->card_delta;
  246.         tmp = deck->cards;
  247.         remove_card(tmp);
  248.         tmp->type = Faceup;
  249.         add_card(tmp, stack[i]->cards, LOC_END, stack[i]);
  250.         if (old_delta != stack[i]->card_delta)    {
  251.             show_list(stack[i], stack[i]->cards);
  252.         } else    {
  253.             show_card(tmp);
  254.         }
  255.     }
  256.  
  257.     deck_index -= 10;
  258.  
  259.     /* force deck to repaint itself if its empty */
  260.     if (deck->cards == CARDNULL)
  261.         redraw_deck(0, 0, table_width, table_height);
  262.  
  263.     assert (deal_number >= 1);
  264.  
  265.     if (log)
  266.         record (0, 0, 0, True);
  267.     (void)sprintf(buf, "Dealt hand %d of 5", deal_number);
  268.     show_message(buf);
  269.  
  270.     assert((deal_number < 5) || (deck_index == 0));
  271.  
  272.     deal_number++;
  273. }
  274.  
  275. /*
  276.  * change the state of a card
  277.  */
  278. flip_card(card, state)
  279. CardPtr    card;
  280. Type    state;
  281. {
  282.     card->type = state;
  283.     show_card(card);
  284. }
  285.  
  286. /*
  287.  * place a card on a list
  288.  *
  289.  * expects 'new' to have been removed from any list
  290.  */
  291. add_card(new, old, location, list)
  292. CardPtr    new, old;
  293. int    location;
  294. CardList    list;
  295. {
  296.  
  297.     assert(new->prev == CARDNULL);
  298.     assert(new->next == CARDNULL);
  299.     assert((location == LOC_BEFORE) || (location == LOC_AFTER)
  300.         || (location == LOC_END) || (location == LOC_START));
  301.     assert ((old == NULL) || (old->list == list));
  302.  
  303.  
  304.     if (location == LOC_END)    {
  305.         old = last_card(list);
  306.         location = LOC_AFTER;
  307.         /* let the later code do the work */
  308.     } else if (location == LOC_START)    {
  309.         old = list->cards;
  310.         location = LOC_BEFORE;
  311.         /* let the later code do the work */
  312.     }
  313.  
  314.     assert((location == LOC_BEFORE) || (location == LOC_AFTER));
  315.  
  316.     /* fix the list */
  317.     if (list->cards == CARDNULL)
  318.         list->cards = new;
  319.     new->list = list;
  320.  
  321.     if (location == LOC_BEFORE)    {
  322.         if (old)    {
  323.             if (list->cards == old)
  324.                 list->cards = new;
  325.             if (old->prev)
  326.                 old->prev->next = new;
  327.             new->prev = old->prev;
  328.             new->next = old;
  329.             old->prev = new;
  330.         } else    {
  331.             new->next = old;
  332.         }
  333.     } else     {        /* LOC_AFTER */
  334.         if (old)    {
  335.             if (old->next)
  336.                 old->next->prev = new;
  337.             new->prev = old;
  338.             new->next = old->next;
  339.             old->next = new;
  340.         } else    {
  341.             new->prev = old;
  342.         }
  343.     }
  344.  
  345.     fix_coords(new, list, False);
  346. }
  347.  
  348. /*
  349.  * see if cards exist, are faceup, and part of the same run
  350.  */
  351. #define    in_sequence(a, b)                        \
  352.     ((a) && (b) &&                            \
  353.         ((a)->type == Faceup) && ((b)->type == Faceup) &&    \
  354.         ((a)->suit == (b)->suit) && ((a)->rank == (b)->rank + 1))
  355.  
  356. /*
  357.  * fix up the inter-card spacing for a stack
  358.  */
  359. static void
  360. fix_coords(new, list, display)
  361. CardPtr    new;
  362. CardList    list;
  363. Bool    display;
  364. {
  365.     /* fix the coords */
  366.     new->x = list->x;
  367.     if (new->prev)    {    /* added to bottom */
  368.         if ((new->prev->y + list->card_delta + CARD_HEIGHT) > 
  369.              table_height)    {
  370.             recompute_list_deltas(list);
  371.             if (display)
  372.                 show_list(list, list->cards);
  373.         }
  374.         /* runs are coallesced */
  375.         if (squish && in_sequence(new->prev, new) && 
  376.             in_sequence(new->prev->prev, new->prev))    {
  377.                 new->y = new->prev->y + (list->card_delta >> 2);
  378.         } else    {
  379.             new->y = new->prev->y + list->card_delta;
  380.         }
  381.     } else     {
  382.         new->y = list->y;
  383.     }
  384. }
  385.  
  386. /*
  387.  * compute the inter-card spacing for a stack
  388.  */
  389. void
  390. recompute_list_deltas(list)
  391. CardList    list;
  392. {
  393. CardPtr    tmp;
  394. int    delta, num = 0;
  395.     
  396.     assert (list->place >= STACK_1);
  397.  
  398.     tmp = list->cards;
  399.     while (tmp)    {
  400.         num++;
  401.         tmp = tmp->next;
  402.     }
  403.  
  404.     /* don't do anything if 1 or fewer cards */
  405.     if (num <= 1)    {
  406.         delta = CARD_DELTA;
  407.         return;
  408.     }
  409.  
  410.     /* adjust 'size' of stack to limit the amount of redrawing */
  411.     if (deltamod)
  412.         num = (num + deltamod - 1)/deltamod * deltamod;
  413.  
  414.     delta = (table_height - (STACK_LOC_Y + 10 + CARD_HEIGHT))/(num - 1);
  415.  
  416.     if (delta > CARD_DELTA)
  417.         delta = CARD_DELTA;
  418.  
  419.     if (list->card_delta != delta)    {
  420.         list->card_delta = delta;
  421.         tmp = list->cards;
  422.         while (tmp)    {
  423.             fix_coords(tmp, list, False);
  424.             tmp = tmp->next;
  425.         }
  426.     }
  427. }
  428.  
  429. /*
  430.  * remove a card from a list
  431.  */
  432. remove_card(card)
  433. CardPtr    card;
  434. {
  435.     /* fix card pointers */
  436.     if (card->prev)
  437.         card->prev->next = card->next;
  438.     if (card->next)
  439.         card->next->prev = card->prev;
  440.  
  441.     /* fix up card list */
  442.     if (card->prev == CARDNULL)
  443.         card->list->cards = card->next;
  444.  
  445.     /* clear pointers */
  446.     card->next = CARDNULL;
  447.     card->prev = CARDNULL;
  448.     card->list = CARDLISTNULL;
  449. }
  450.  
  451. /*
  452.  * move an entire sublist to another list
  453.  */
  454. void
  455. move_to_list(card, list, log)
  456. CardPtr        card;
  457. CardList    list;
  458. Bool        log;
  459. {
  460. CardPtr    tmp;
  461. int    from, dest;
  462. int    count = 0;
  463. Bool    exposed = False;
  464. int    delta;
  465.  
  466.     /* fix old list */
  467.     if (card->prev)    {
  468.         card->prev->next = CARDNULL;
  469.         if (card->prev->type == Facedown)    {
  470.             exposed = True;
  471.             card->prev->type = Faceup;
  472.         }
  473.     } else    {
  474.         card->list->cards = CARDNULL;
  475.     }
  476.  
  477.     /* shrink stack if necessary */
  478.     if (card->list->place >= STACK_1 && 
  479.         card->list->card_delta != CARD_DELTA)    {
  480.         recompute_list_deltas(card->list);
  481.         show_list(card->list, card->list->cards);
  482.     } else    {
  483.         show_list(card->list, card->prev);
  484.     }
  485.     from = STACK_INDEX(card->list->place) + 1;
  486.  
  487. #ifdef DEBUG
  488.     validate_card_list(card->list);
  489. #endif
  490.  
  491.     tmp = last_card(list);
  492.     if (tmp)    {
  493.         assert(tmp->next == CARDNULL);
  494.         tmp->next = card;
  495.         card->prev = tmp;
  496.     } else    {
  497.         list->cards = card;
  498.         card->prev = CARDNULL;
  499.     }
  500.     tmp = card;
  501.     while (tmp)    {
  502.         count++;
  503.         tmp->list = list;
  504.         delta = list->card_delta;
  505.         fix_coords(tmp, list, True);
  506.         /* only show card if fix_coords() didn't */
  507.         if (delta == list->card_delta)
  508.             show_card(tmp);
  509.         tmp = tmp->next;
  510.     }
  511.  
  512. #ifdef DEBUG
  513.     validate_card_list(list);
  514. #endif
  515.     if (log)    {
  516.         dest = (IS_PILE(list)) ? 0 : STACK_INDEX(list->place) + 1;
  517.         record(from, dest, count, exposed);
  518.     }
  519. }
  520.  
  521. #ifdef DEBUG
  522. print_list(list)
  523. CardList    list;
  524. {
  525. CardPtr    tmp;
  526.     
  527.     tmp = list->cards;
  528.  
  529.     while (tmp)    {
  530.         (void) fprintf(stderr,"card is %s of %s (%s)\n",
  531.             rank_name(tmp->rank), 
  532.             suit_name(tmp->suit), 
  533.             type_name(tmp->type));
  534.         tmp = tmp->next;
  535.     }
  536. }
  537.  
  538. validate_card_list(list)
  539. CardList    list;
  540. {
  541. CardPtr    tmp;
  542.     
  543.     tmp = list->cards;
  544.     if (tmp == CARDNULL)
  545.         return;
  546.     if (tmp->prev != CARDNULL)    {
  547.         (void) fprintf(stderr,
  548.             "validate list:  first card has non-null prev\n");
  549.     }
  550.     while (tmp->next)    {
  551.         if (tmp->next->prev != tmp)
  552.             (void) fprintf(stderr,"validate list: bad link\n");
  553.         if (tmp->list != list)
  554.             (void) fprintf(stderr,
  555.                 "validate list: card/list mismatch\n");
  556.         tmp = tmp->next;
  557.     }
  558. }
  559. #endif
  560.  
  561. /*
  562.  * rank & suit value->string roputines
  563.  */
  564.  
  565.  
  566. static    char    *rnk_names[] =    {
  567.     "A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"
  568. };
  569.  
  570. /*
  571.  * shortened version for save files and info
  572.  */
  573. char    *
  574. rnk_name(rank)
  575. Rank    rank;
  576. {
  577.     assert(rank >= Ace && rank <= King);
  578.  
  579.     return (rnk_names[rank]);
  580. }
  581.  
  582. static char    *rank_names[] =    {
  583.     "Ace", "Deuce", "Three", "Four", "Five", "Six", "Seven",
  584.     "Eight", "Nine", "Ten", "Jack", "Queen", "King"
  585. };
  586.  
  587. char    *
  588. rank_name(rank)
  589. Rank    rank;
  590. {
  591.     assert(rank >= Ace && rank <= King);
  592.  
  593.     return (rank_names[rank]);
  594. }
  595.  
  596. static char    *suit_names[] = {
  597.     "Spades", "Hearts", "Diamonds", "Clubs"
  598. }; 
  599.  
  600. char    *
  601. suit_name(suit)
  602. Suit    suit;
  603. {
  604.     assert (suit >= Spade && suit <= Club);
  605.  
  606.     return (suit_names[suit]);
  607. }
  608.  
  609. #ifdef DEBUG
  610. static char    *type_names[] =    {
  611.     "Faceup", "Facedown", "Joker"
  612. };
  613.  
  614. char    *
  615. type_name(type)
  616. Type    type;
  617. {
  618.     assert (type >= Faceup && type <= Joker);
  619.  
  620.     return (type_names[type]);
  621. }
  622. #endif DEBUG
  623.  
  624.  
  625. /*
  626.  * return the bottom-most card of a list
  627.  */
  628. CardPtr
  629. last_card(list)
  630. CardList    list;
  631. {
  632. CardPtr    tmp = CARDNULL;
  633.  
  634.     if ((list == CARDLISTNULL) || (list->cards == CARDNULL))
  635.         return (CARDNULL);
  636.  
  637.     tmp = list->cards;
  638.     while (tmp->next)    {
  639.         tmp = tmp->next;
  640.     }
  641.     return (tmp);
  642. }
  643.  
  644. /*
  645.  * can only move card if there's a run of the same suit underneath it
  646.  */
  647. Bool
  648. can_move(card)
  649. CardPtr    card;
  650. {
  651. CardPtr    tmp;
  652. Rank    last_rank;
  653.  
  654.     if (card->type != Faceup)
  655.         return (False);
  656.     last_rank = card->rank;
  657.     tmp = card->next;
  658.     while (tmp)    {
  659.         if ((tmp->rank != (last_rank - 1)) || (tmp->suit != card->suit))
  660.             return (False);
  661.         last_rank = tmp->rank;
  662.         tmp = tmp->next;
  663.     }
  664.     return (True);
  665. }
  666.  
  667. /*
  668.  * can 'card' go on to 'dest' ?
  669.  */
  670. Bool
  671. can_move_to(card, list)
  672. CardPtr    card;
  673. CardList    list;
  674. {
  675. CardPtr    tmp;
  676.  
  677.     assert (can_move(card));
  678.     tmp = last_card(list);
  679.     if (tmp == CARDNULL)
  680.         return (True);
  681.     return (tmp->rank == (card->rank + 1));
  682. }
  683.  
  684. /*
  685.  * finds the best move for a specific card
  686.  *
  687.  * use the first 'next best' move so we choose them from right to left
  688.  */
  689. CardList
  690. best_card_move(card)
  691. CardPtr    card;
  692. {
  693. CardList    next_best = CARDLISTNULL;
  694. CardList    space = CARDLISTNULL;
  695. CardPtr    tmp;
  696. int    i;
  697.  
  698.     /* iterate through the stacks */
  699.     for (i = 0; i < NUM_STACKS; i++)    {
  700.         /* don't look at our own stack */
  701.         if (stack[i] == card->list)
  702.             continue;
  703.         tmp = last_card(stack[i]);
  704.         if (tmp == CARDNULL)    {    /* spaces are ok */
  705.             if (next_best == CARDLISTNULL)
  706.                 space = stack[i];
  707.             continue;
  708.         }
  709.         /* rank & suit is optimal */
  710.         if (tmp->rank == (card->rank + 1))    {
  711.             if (tmp->suit == card->suit)
  712.                 return (tmp->list);
  713.             /* just rank is the next best */
  714.             if (next_best == CARDLISTNULL)
  715.                 next_best = tmp->list;
  716.         }
  717.     }
  718.     if (next_best == CARDLISTNULL)
  719.         next_best = space;
  720.  
  721.     return (next_best);
  722. }
  723.  
  724. /*
  725.  * performs the best move for an entire sub-list
  726.  */
  727. void
  728. best_list_move(list, first_card)
  729. CardList    list;
  730. CardPtr        first_card;
  731. {
  732. CardPtr    tmp, tmp2;
  733. CardList    best = CARDLISTNULL;
  734.  
  735.     if (first_card != CARDNULL)    {
  736.         tmp = first_card;
  737.     } else    {
  738.         tmp = list->cards;
  739.         if (tmp == CARDNULL)    {
  740.             show_message("Empty list");
  741.             spider_bell(dpy, 0);
  742.             return;
  743.         }
  744.     }
  745.  
  746.     /*
  747.      * iterate through stack.  for each card that can move,
  748.      * try to find one.  return as soon as we find one
  749.      */
  750.     while (tmp)    {
  751.         if (can_move(tmp))    {
  752.             /*
  753.              * special case full suits
  754.              */
  755.             if (tmp->rank == King)    {
  756.                 tmp2 = last_card(list);
  757.                 if (tmp2->rank == Ace)    {
  758.                     move_to_pile(tmp);
  759.                     return;
  760.                 }
  761.             }
  762.             best = best_card_move(tmp);
  763.             if (best)    {
  764.                 move_to_list(tmp, best, True);
  765.             } else    {
  766.                 card_message("Nowhere to move the", tmp);
  767.                 spider_bell(dpy, 0);
  768.             }
  769.             return;
  770.         }
  771.         tmp = tmp->next;
  772.     }
  773. }
  774.  
  775. void
  776. move_to_pile(card)
  777. CardPtr    card;
  778. {
  779. int    i;
  780.  
  781.     for (i = 0; i < NUM_PILES; i++)    {
  782.         if (piles[i]->cards == CARDNULL)
  783.             break;
  784.     }
  785.     assert(i < NUM_PILES);
  786.  
  787.     move_to_list(card, piles[i], True);
  788. }
  789.  
  790.  
  791. /*
  792.  * is card thru lastcard King - Ace?
  793.  */
  794. static Bool
  795. is_sequence(card)
  796. CardPtr    card;
  797. {
  798. CardPtr    tmp;
  799.  
  800.     if (card->rank != King)
  801.         return (False);
  802.     tmp = card;
  803.     while (tmp->next)    {
  804.         if (!(tmp->next && (tmp->suit == tmp->next->suit) &&
  805.             (tmp->rank == (tmp->next->rank + 1))))
  806.             return (False);
  807.         tmp = tmp->next;
  808.     }
  809.     if (tmp->rank == Ace)
  810.         return (True);
  811.     else
  812.         return (False);
  813. }
  814.  
  815. /*
  816.  * Compute a somewhat arbitrary evaluation function for the position:
  817.  *    2 point per card sitting atop next higher card in same suit
  818.  *   10 per card turned face up
  819.  *   15 extra for each column where all cards have been revealed
  820.  *   50 per completed suit removed (note this costs 12*2 for cards in seq)
  821.  * If all columns are either empty or contain completed suits, then those
  822.  * suits also count 50 (including the 24 for the 12 cards that are atop
  823.  * higher cards), plus an extra 2 for each suit after the first three.
  824.  * Thus the only way to get 1000 points is to win with all eight suits
  825.  * still in the tableau.
  826.  */
  827.  
  828. int
  829. compute_score()
  830. {
  831. int    score = 0;
  832. int    i;
  833. CardPtr    tmp;
  834. int    num_piles = 0;
  835.  
  836.     if (deal_number == 0)
  837.         return (0);
  838.  
  839.     score = 44 * 10;        /* score if all cards flipped */
  840.     for (i = 0; i < NUM_PILES; i++)    {
  841.         if (piles[i]->cards)
  842.             score += 50;
  843.     }
  844.  
  845.     for (i = 0; i < NUM_STACKS; i++)    {
  846.         if (stack[i]->cards)    {
  847.             if (stack[i]->cards->type == Faceup)    {
  848.                 score += 15;
  849.                 if (is_sequence(stack[i]->cards))    {
  850.                     score += 50;
  851.                     num_piles++;
  852.                     if (num_piles > 3)    {
  853.                         score += 2;
  854.                     }
  855.                     continue;
  856.                 }
  857.             }
  858.         } else    {
  859.             score += 15;
  860.         }
  861.  
  862.         tmp = stack[i]->cards;
  863.         while (tmp)    {
  864.             if (tmp->type == Faceup)    {
  865.                 if (tmp->prev)    {
  866.                     if ((tmp->prev->type == Faceup) &&
  867.                         (tmp->rank == (tmp->prev->rank - 1))
  868.                         && (tmp->suit == tmp->prev->suit))
  869.                         score += 2;
  870.                 }
  871.             } else    {
  872.                 score -= 10;    /* still Facedown */
  873.             }
  874.             tmp = tmp->next;
  875.         }
  876.     }
  877.  
  878.     return (score);
  879. }
  880.  
  881. /*
  882.  * display which suits have all their cards visible
  883.  */
  884. show_full_suits()
  885. {
  886. char    showing[NUM_RANKS][NUM_SUITS];
  887. Bool    all[NUM_SUITS];
  888. int    num = 0;
  889. int    i, j;
  890. CardPtr    tmp;
  891. char    buf[128];
  892.  
  893.     for (i = 0; i < NUM_RANKS; i++)
  894.         for (j = 0; j < NUM_SUITS; j++)
  895.             showing[i][j] = 0;
  896.  
  897.     for (i = 0; i < NUM_STACKS; i++)    {
  898.         tmp = stack[i]->cards;
  899.         while (tmp)    {
  900.             if (tmp->type == Faceup)    {
  901.                 showing[tmp->rank][tmp->suit]++;
  902.             }
  903.             tmp = tmp->next;
  904.         }
  905.     }
  906.     for (j = 0; j < NUM_SUITS; j++)    {
  907.         all[j] = True;
  908.         for (i = 0; i < NUM_RANKS; i++)    {
  909.             if (showing[i][j] == 0)    {
  910.                 all[j] = False;
  911.                 break;
  912.             }
  913.         }
  914.         if (all[j])
  915.             num++;
  916.     }
  917.     if (num == 0)    {
  918.         show_message("No suit has all 13 cards showing.");
  919.     } else    {
  920.         (void) strcpy(buf, 
  921.             "Sufficient cards visible to form complete set of ");
  922.         for (j = 0; j < NUM_SUITS; j++)    {
  923.             if (all[j])    {
  924.                 (void)strcat(buf, suit_name((Suit) j));
  925.                 if (--num)    {
  926.                     (void)strcat(buf, ", ");
  927.                 } else    {
  928.                     (void)strcat(buf, ".");
  929.                 }
  930.             }
  931.         }
  932.         show_message(buf);
  933.     }
  934. }
  935.  
  936. /*
  937.  * print cards in list
  938.  */
  939. expand(list)
  940. CardList    list;
  941. {
  942. CardPtr    tmp, last;
  943. char    buf[512], buf2[10];
  944. Bool    sequence = False;
  945.  
  946.  
  947.     tmp = list->cards;
  948.     if (tmp == CARDNULL)    {
  949.         show_message("Empty column.");
  950.         return;
  951.     }
  952.     (void)strcpy(buf, "Column contains:");
  953.     last = CARDNULL;
  954.     while (tmp)    {
  955.         if (tmp->type != Faceup)    {
  956.             tmp = tmp->next;
  957.             continue;
  958.         }
  959.         if (last && last->suit == tmp->suit && 
  960.             (last->rank == tmp->rank + 1))        {
  961.             if (!sequence)    {
  962.                 sequence = True;
  963.             }
  964.         } else    {
  965.             if (sequence)    {
  966.                 (void)sprintf(buf2, "-%s%c %s%c", 
  967.                     rnk_name(last->rank),
  968.                     tolower(*suit_name(last->suit)),
  969.                     rnk_name(tmp->rank),
  970.                     tolower(*suit_name(tmp->suit)));
  971.                 sequence = False;
  972.             } else    {
  973.                 (void)sprintf(buf2, " %s%c",rnk_name(tmp->rank),
  974.                     tolower(*suit_name(tmp->suit)));
  975.             }
  976.             (void)strcat(buf, buf2);
  977.         }
  978.         last = tmp;
  979.         tmp = tmp->next;
  980.     }
  981.     /* handle dangling sequences */
  982.     if (sequence)    {
  983.         (void)sprintf(buf2, "-%s%c", rnk_name(last->rank),
  984.             tolower(*suit_name(last->suit)));
  985.         (void)strcat(buf, buf2);
  986.     }
  987.     show_message(buf);
  988. }
  989.  
  990. static int
  991. col_locate(list, suit, rank, checksuit)
  992. CardList    list;
  993. Suit    suit;
  994. Rank    rank;
  995. Bool    checksuit;
  996. {
  997. CardPtr    tmp;
  998. int    count = 0;
  999.  
  1000.     tmp = list->cards;
  1001.     for (tmp = list->cards; tmp; tmp = tmp->next)    {
  1002.         if (tmp->type != Faceup)
  1003.             continue;
  1004.         /* we have a find if we asked for a suit and found it
  1005.          * OR if we don't have a suit and are looking for a free
  1006.          * card
  1007.          */
  1008.         if (tmp->rank == rank &&
  1009.             ((checksuit && tmp->suit == suit) ||
  1010.             (!checksuit && 
  1011.                 (!tmp->next ||    /* end of stack */
  1012.                 (tmp->next &&     /* free */
  1013.                     tmp->next->rank != (tmp->rank - 1))))))
  1014.             count++;
  1015.     }
  1016.     return    count;
  1017. }
  1018.  
  1019. void
  1020. locate(str)
  1021. char    *str;
  1022. {
  1023. int    i, num;
  1024. Suit    suit;
  1025. Rank    rank;
  1026. char    buf[512], buf2[256], times[32];
  1027. Bool    found = False, checksuit = False;
  1028.  
  1029.     if (!str)
  1030.         return;
  1031.     /*
  1032.      * assume that the string is well formed (probably stupid
  1033.      * assumption) and treat accordingly
  1034.      */
  1035.     for (i = 0; i < strlen(str); i++)    {
  1036.         switch(str[i])    {
  1037.         case    'D':
  1038.         case    'd':
  1039.             suit = Diamond;
  1040.             checksuit = True;
  1041.             break;
  1042.         case    'S':
  1043.         case    's':
  1044.             suit = Spade;
  1045.             checksuit = True;
  1046.             break;
  1047.         case    'H':
  1048.         case    'h':
  1049.             suit = Heart;
  1050.             checksuit = True;
  1051.             break;
  1052.         case    'C':
  1053.         case    'c':
  1054.             suit = Club;
  1055.             checksuit = True;
  1056.             break;
  1057.         case    'A':
  1058.         case    'a':
  1059.             rank = Ace;
  1060.             break;
  1061.         case    'T':
  1062.         case    't':
  1063.             rank = Ten;
  1064.             break;
  1065.         case    'J':
  1066.         case    'j':
  1067.             rank = Jack;
  1068.             break;
  1069.         case    'Q':
  1070.         case    'q':
  1071.             rank = Queen;
  1072.             break;
  1073.         case    'K':
  1074.         case    'k':
  1075.             rank = King;
  1076.             break;
  1077.         default:
  1078.             rank = atoi(str) - 1;
  1079.             if (rank < Deuce || rank > Ten)    {
  1080.                 (void)sprintf(buf, 
  1081.                     "Invalid card specification %s", str);
  1082.                 show_message(buf);
  1083.                 return;
  1084.             }
  1085.             break;
  1086.         }
  1087.     }
  1088.  
  1089.     if (checksuit)
  1090.         (void)sprintf(buf, "%s of %s ", 
  1091.             rank_name(rank), suit_name(suit));
  1092.     else
  1093.         (void)sprintf(buf, "Free %s ", rank_name(rank));
  1094.     for (i = 0; i < NUM_STACKS; i++)    {
  1095.         if (num = col_locate(stack[i], suit, rank, checksuit))    {
  1096.             if (found)    {
  1097.                 (void)strcat(buf, ", ");
  1098.             }
  1099.             found = True;
  1100.             if (num == 1)    {
  1101.                 (void)strcpy(times, "once");
  1102.             } else if (num == 2)    {
  1103.                 (void)strcpy(times, "twice");
  1104.             } else    {
  1105.                 (void)sprintf(times, "%d times", num);
  1106.             }
  1107.  
  1108.             (void)sprintf(buf2, "occurs in column %d %s ", i + 1,
  1109.                         times);
  1110.             (void)strcat(buf, buf2);
  1111.         }
  1112.     }
  1113.  
  1114.     if (!found)
  1115.         (void)strcat(buf, "is not visible");
  1116.     show_message(buf);
  1117. }
  1118.  
  1119. /*
  1120.  * routines to give advice about best move.
  1121.  *
  1122.  * doing a really good job here may be impossible -- this is just a
  1123.  * rough attempt
  1124.  */
  1125.  
  1126. static void
  1127. advise_pile_move(list)
  1128. CardList    list;
  1129. {
  1130. char    buf[128];
  1131.  
  1132.     (void) sprintf(buf, "Remove King through Ace in pile %d", 
  1133.         STACK_INDEX(list->place) + 1);
  1134.     show_message(buf);
  1135. }
  1136.  
  1137. static void
  1138. advise_move(card, from, to)
  1139. CardPtr        card;
  1140. CardList    from, to;
  1141. {
  1142. char    buf[128];
  1143.  
  1144.     if (to->cards == CARDNULL)    {
  1145.         (void) sprintf(buf, "Move %s of %s from stack %d to space in stack %d",
  1146.             rank_name(card->rank), suit_name(card->suit),
  1147.             STACK_INDEX(from->place) + 1, 
  1148.             STACK_INDEX(to->place) + 1);
  1149.     } else    {
  1150.         (void) sprintf(buf, "Move %s of %s from stack %d to %s of %s on stack %d",
  1151.             rank_name(card->rank), suit_name(card->suit),
  1152.             STACK_INDEX(from->place) + 1, 
  1153.             rank_name(last_card(to)->rank), suit_name(last_card(to)->suit),
  1154.             STACK_INDEX(to->place) + 1);
  1155.     }
  1156.     show_message(buf);
  1157. }
  1158.  
  1159. /*
  1160.  * calculate the relative worth of a move
  1161.  *
  1162.  * this is by no means an optimal algorithm, since there's no lookahead,
  1163.  * but it should be good enough to get a beginner started
  1164.  */
  1165. /*
  1166.  * value is:
  1167.  *    head of sublist rank + 100    (best to move the high cards first)
  1168.  *    + number of cards            (move as many as possible)
  1169.  *    + 200 if show a new card        (dig out cards)
  1170.  *    + 400 if show a new space        (dig out cards)
  1171.  *    + 800 if same suit        (same suits is preferable)
  1172.  *
  1173.  * the constants are arbitrary values large enough not to be reached
  1174.  * by the rank or count modifiers
  1175.  */
  1176. #define    RANK_MOVE    100
  1177. #define    NEW_CARD_MOVE    200
  1178. #define    SPACE_MOVE    400
  1179. #define    SAME_SUIT_MOVE    800
  1180.  
  1181. /* ARGSUSED */
  1182. static int
  1183. value_move(card, from, to)
  1184. CardPtr        card;
  1185. CardList    from, to;
  1186. {
  1187. int    value;;
  1188.  
  1189.     value = card->rank + RANK_MOVE;      /* higher cards are worth more */
  1190.  
  1191.     if (!card->prev)    {
  1192.         value += SPACE_MOVE;
  1193.     } else if (card->prev->type == Facedown)    {
  1194.         value += NEW_CARD_MOVE;
  1195.     }
  1196.     /* avoid moving to a space */
  1197.     if (last_card(to) == CARDNULL)    {
  1198.         /* don't space hop */
  1199.         if (card->prev == CARDNULL)    {
  1200.             value = 0;
  1201.         } else    {
  1202.             value /= 2;
  1203.         }
  1204.     /* same suit is worth a lot more */
  1205.     } else if (card->suit == last_card(to)->suit)    {
  1206.         value += SAME_SUIT_MOVE;
  1207.     /* avoid jumping back & forth from two equal moves */
  1208.     } else if (card->prev && card->prev->type == Faceup &&
  1209.         (card->prev->rank == (card->rank + 1)))    {
  1210.         value = 0;
  1211.     }
  1212.     return (value);
  1213. }
  1214.  
  1215. /*
  1216.  * finds the 'best' move and displays it
  1217.  */
  1218. void
  1219. advise_best_move()
  1220. {
  1221. CardPtr        tmp, tmp2, bestcard;
  1222. CardList    move = CARDLISTNULL,
  1223.         bestfrom = CARDLISTNULL,
  1224.         bestto = CARDLISTNULL;
  1225. int        best_value = 0, val;
  1226. CardList    list;
  1227. int        i;
  1228.  
  1229.     for (i = 0; i < NUM_STACKS; i++)    {
  1230.         list = stack[i];
  1231.         tmp = list->cards;
  1232.         if (tmp == CARDNULL)    {
  1233.             continue;
  1234.         }
  1235.  
  1236.         /*
  1237.          * iterate through stack.  for each card that can move,
  1238.          * calculate the move value
  1239.          */
  1240.         while (tmp)    {
  1241.             if (can_move(tmp))    {
  1242.                 /*
  1243.                  * special case full suits
  1244.                  */
  1245.                 if (tmp->rank == King)    {
  1246.                     tmp2 = last_card(list);
  1247.                     if (tmp2->rank == Ace)    {
  1248.                         advise_pile_move(list);
  1249.                         return;
  1250.                     }
  1251.                 }
  1252.                 move = best_card_move(tmp);
  1253.                 if (move)    {
  1254.                     val = value_move(tmp, list, move);
  1255.                     if (val > best_value)    {
  1256.                         bestfrom = list;
  1257.                         bestto = move;
  1258.                         bestcard = tmp;
  1259.                         best_value = val;
  1260.                     }
  1261.                 }
  1262.                 break;    /* finished with this stack */
  1263.             }
  1264.             tmp = tmp->next;
  1265.         }
  1266.     }
  1267.     if (bestfrom)    {
  1268.         advise_move(bestcard, bestfrom, bestto);
  1269.     } else    {
  1270.         if (deck->cards == CARDNULL)    {
  1271.             show_message("Its all over.");
  1272.         } else    {
  1273.             show_message("Deal the next hand.");
  1274.         }
  1275.     }
  1276. }
  1277.  
  1278. /*
  1279.  * fix up the inter-card spacing when resource value "squish" changes.
  1280.  */
  1281. void
  1282. fix_up_card_spacing()
  1283. {
  1284.     int i, maxy;
  1285.     CardPtr tmp, last;
  1286.     CardList list;
  1287.  
  1288.     for (i = 0; i < NUM_STACKS; i++) {
  1289.         list = stack[i];
  1290.         tmp = list->cards;
  1291.         last = last_card(list);
  1292.         maxy = last->y;
  1293.         while(tmp) {
  1294.             fix_coords(tmp, list, False);
  1295.             tmp = tmp->next;
  1296.         }
  1297.         if (maxy != last->y) {
  1298.             show_list(list, list->cards);
  1299.         }
  1300.     }
  1301. }
  1302.