home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-385-Vol-1of3.iso / x / xcu16.zip / clients / xhearts / cplay.c < prev    next >
C/C++ Source or Header  |  1991-10-03  |  30KB  |  1,256 lines

  1. /*
  2.  * Copyright 1991 Cornell University
  3.  *
  4.  * Permission to use, copy, modify, and distribute this software and its
  5.  * documentation for any purpose and without fee is hereby granted, provided
  6.  * that the above copyright notice appear in all copies and that both that
  7.  * copyright notice and this permission notice appear in supporting
  8.  * documentation, and that the name of Cornell U. not be used in advertising
  9.  * or publicity pertaining to distribution of the software without specific,
  10.  * written prior permission.  Cornell U. makes no representations about the
  11.  * suitability of this software for any purpose.  It is provided "as is"
  12.  * without express or implied warranty.
  13.  *
  14.  * CORNELL UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
  15.  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
  16.  * EVENT SHALL CORNELL UNIVERSITY BE LIABLE FOR ANY SPECIAL, INDIRECT OR
  17.  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
  18.  * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
  19.  * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  20.  * PERFORMANCE OF THIS SOFTWARE.
  21.  *
  22.  * Author:  Gene W. Dykes, Program of Computer Graphics
  23.  *          580 Theory Center, Cornell University, Ithaca, NY 14853
  24.  *          (607) 255-6713   gwd@graphics.cornell.edu
  25.  */
  26.  
  27.  
  28. #include <stdio.h>
  29. #include <X11/Intrinsic.h>
  30. #include "hearts.h"
  31.  
  32. typedef enum
  33.     {
  34.      Shooting
  35.     ,Defending
  36.     ,Minimizing
  37.     } ShootMode ;
  38.  
  39. typedef enum
  40.     {
  41.      Following
  42.     ,Sloughing
  43.     } FollowMode ;
  44.  
  45. typedef enum
  46.     {
  47.      InOpponentHand
  48.     ,InMyHand
  49.     ,Played
  50.     } CardStatus ;
  51.  
  52. typedef enum
  53.     {
  54.      LowestCard,
  55.      HighestCard,
  56.      SecondHighestCard,
  57.      HighestLosingCard,
  58.      LowestWinningCard
  59.      } Choice ;
  60.  
  61. typedef struct
  62.     {
  63.     ShootMode    shoot ;
  64.     FollowMode    follow ;
  65.     CardStatus    card_status[N_SUITS][CARDS_PER_SUIT] ;
  66.     Boolean    i_have_only_points ;
  67.     Boolean    i_have_queen ;
  68.     int        suit_leads[N_TRICKS] ;
  69.     int        lowest_remaining[N_SUITS] ;
  70.     int        lowest_remaining_in_other_hands[N_SUITS] ;
  71.     int        highest_remaining_in_other_hands[N_SUITS] ;
  72.     int        number_remaining_in_other_hands[N_SUITS] ;
  73.     } PlayStatus ;
  74.  
  75. static PlayStatus _status[4], *status ;
  76.  
  77. #define Card(i,j)    (ph->suit[i][j])
  78. #define Rank(i,j)    (info->deck[Card(i,j)].rank)
  79.  
  80. #define IndexOfLowestInSuit(i)    (ph->n_in_suit[i]-1)
  81. #define IndexOfHighestInSuit    (0)
  82. #define IndexOfSecondHighestInSuit    (1)
  83. #define LowestInSuit(i)        (Rank(i, IndexOfLowestInSuit(i)))
  84.  
  85. #define SuitOfTrick(i,j)    (info->deck[history->trick[i].card[j]].suit)
  86. #define TrickPlayer(i,j)    (history->trick[i].leader + j >= N_PLAYERS ? \
  87.                  history->trick[i].leader + j - N_PLAYERS : \
  88.                  history->trick[i].leader + j)
  89.  
  90. long data[3] ;
  91. static void play_this_card () ;
  92. int IndexOfChoice () ;
  93.  
  94. void
  95. play_program (ph, player_index)
  96.     PvtHistory *ph ;
  97.     int player_index ;
  98. {
  99. int discard_val[N_DISCARDS] ;
  100. int discard_suit[N_DISCARDS] ;
  101. int discard_rank[N_DISCARDS] ;
  102. int discard_card[N_DISCARDS] ;
  103. int real_rank[N_DISCARDS] ;
  104. int n_in_suit[N_SUITS] ;
  105. int d, i, j, k ;
  106. int defensive_heart_thrown = False ;
  107. static void find_the_initial_queen () ;
  108. static void find_the_current_queen () ;
  109. static void determine_initial_defense_potential () ;
  110. static void determine_current_defense_potential () ;
  111. static void find_trick_stats () ;
  112.  
  113. data[0] = player_index ;
  114. status = &_status[player_index] ;
  115.  
  116. show_hand (player_index) ;
  117.  
  118. /*
  119.  * Initialize a few things before playing to the first trick
  120.  */
  121.  
  122. if (CurrentTrick == 0)
  123.     {
  124.     find_the_initial_queen (ph, player_index) ;
  125.     determine_initial_defense_potential (ph, player_index) ;
  126.  
  127.     /*
  128.      * Check for first lead of hand ( must lead 2 of clubs )
  129.      */
  130.  
  131.     if (snap->n_played_to_trick == 0)
  132.     {
  133.     data[1] = SUIT_CLUBS ;
  134.     data[2] = ph->n_in_suit[SUIT_CLUBS] - 1 ;
  135.     card_picked (NULL, data, NULL) ;
  136.     return ;
  137.     }
  138.     }
  139.  
  140. /*
  141.  * Find some data before playing to any trick
  142.  */
  143.  
  144. find_trick_stats (ph, player_index) ;
  145. find_the_current_queen (ph, player_index) ;
  146. determine_current_defense_potential (ph, player_index) ;
  147.  
  148. /*
  149.  * If we are leading
  150.  * (Need to check for points broken.  If not, we cannot lead a point unless
  151.  *  that is all that is left.)
  152.  */
  153.  
  154. if (snap->n_played_to_trick == 0)
  155.     {
  156.     if (status->shoot == Shooting)
  157.     {
  158.     }
  159.     else
  160.     if (status->shoot == Defending)
  161.     {
  162.     status->shoot = Minimizing ;
  163.     }
  164.  
  165.     if (status->shoot == Minimizing)
  166.     {
  167.     int spade_differential ;
  168.     /* Good leads are :
  169.      *    queen of spades if only one high spade outstanding
  170.      *    jack of spades or lower
  171.      *    highest diamond if suit not lead yet
  172.      *      remaining diamond of a doubleton if suit lead once
  173.      *      remaining club of a doubleton if suit lead once
  174.      *    lowest remaining card of any suit
  175.      *    low card if likely someone will play higher
  176.      */
  177.     /* Bad leads are :
  178.      *    The Queen of spades
  179.      *    Ace or King of spades if queen still out
  180.      *    any spade if short in spades and hold Q, K, or A
  181.      *    High cards in oft-lead suits
  182.      */
  183.     /* If no good leads, choose from non-bad leads :
  184.      *    lowest club unless guaranteed to lose
  185.      *    lowest diamond unless guaranteed to lose
  186.      *    lowest heart unless guaranteed to lose
  187.      *    lowest spade
  188.      */
  189.     /*
  190.      * If still nothing selected, I'm hosed so choose :
  191.      *    lowest club, diamond, heart, spade
  192.      */
  193.  
  194.     /**
  195.      ** Looking For a GOOD Lead
  196.      **/
  197.  
  198. if (logerr)
  199. fprintf (logerr, "%d == 1 && %d && %d > %d && (%d || %d)\n",
  200. status->number_remaining_in_other_hands[SUIT_SPADES],
  201. status->i_have_queen,
  202. status->highest_remaining_in_other_hands[SUIT_SPADES],RANK_QUEEN,
  203. info->points_broken, status->i_have_only_points) ;
  204. fflush (logerr) ;
  205.     if (
  206.             (
  207.         status->i_have_queen &&
  208.         status->number_remaining_in_other_hands[SUIT_SPADES] == 1 &&
  209.         status->highest_remaining_in_other_hands[SUIT_SPADES] > RANK_QUEEN
  210.         &&
  211.         (info->points_broken || status->i_have_only_points)
  212.         )
  213.        )
  214.         {
  215.         int j ;
  216. #ifndef NO_LOGGING
  217. if (logerr)
  218. fprintf (logerr, "Playing a guaranteed spade queen\n") ;
  219. #endif
  220.         for (j=0;  j < ph->n_in_suit[SUIT_SPADES];  j++)
  221.         {
  222.         if (Rank(SUIT_SPADES,j) == RANK_QUEEN)
  223.             {
  224.             play_this_card (SUIT_SPADES, j) ;
  225.             return ;
  226.             }
  227.         }
  228.         }
  229.  
  230.     /*
  231.      * We'll look for a low spade to lead.
  232.      * If there are spades outstanding, spade lead okay.
  233.      * If I have the Ace, King, or Queen, I must have at least 5 spades
  234.      * or more than there are left in other hands.
  235.      */
  236.     spade_differential = ph->n_in_suit[SUIT_SPADES] -
  237.           status->number_remaining_in_other_hands[SUIT_SPADES] ;
  238.     if (
  239.         ph->n_in_suit[SUIT_SPADES] &&
  240.         status->number_remaining_in_other_hands[SUIT_SPADES] &&
  241.         (
  242.          (
  243.          Rank(SUIT_SPADES,IndexOfHighestInSuit) < RANK_QUEEN
  244.          )
  245.          ||
  246.          ph->n_in_suit[SUIT_SPADES] >= 6
  247.          ||
  248.          spade_differential > 0
  249.         )
  250.            )
  251.         {
  252.         for (i=0;  i < ph->n_in_suit[SUIT_SPADES];  i++)
  253.         {
  254.         /* TODO : don't do this if hearts are dropping! */
  255.  
  256.         if (Rank(SUIT_SPADES,i) <= RANK_JACK &&
  257.             Rank(SUIT_SPADES,i) <
  258.             status->highest_remaining_in_other_hands[SUIT_SPADES])
  259.             {
  260.             /* Play the highest spade less than the queen */
  261.             /* But don't do it if I have an unprotected A or K */
  262. #ifndef NO_LOGGING
  263. if (logerr)
  264. fprintf (logerr, "Playing a low spade\n") ;
  265. #endif
  266.             play_this_card (SUIT_SPADES, i) ;
  267.             return ;
  268.             }
  269.         }
  270.         }
  271. #ifndef NO_LOGGING
  272. if (logerr)
  273. fprintf (logerr, "No low spade to play\n") ;
  274. #endif
  275.  
  276.     /*
  277.      * Now look to see if I have a singleton diamond or one left
  278.      * of a doubleton diamond
  279.      */
  280.     if (status->suit_leads[SUIT_DIAMONDS] == 0)
  281.         {
  282.         if (ph->n_in_suit[SUIT_DIAMONDS] < 5 &&
  283.         ph->n_in_suit[SUIT_DIAMONDS] > 0)
  284.         {
  285. #ifndef NO_LOGGING
  286. if (logerr)
  287. fprintf (logerr, "Playing a high diamond\n") ;
  288. #endif
  289.         play_this_card (SUIT_DIAMONDS, IndexOfHighestInSuit) ;
  290.         return ;
  291.         }
  292.         }
  293.     else
  294.     if (status->suit_leads[SUIT_DIAMONDS] == 1)
  295.         {
  296.         if (ph->n_in_suit[SUIT_DIAMONDS] == 1)
  297.         {
  298. #ifndef NO_LOGGING
  299. if (logerr)
  300. fprintf (logerr, "Playing last diamond of a doubleton\n") ;
  301. #endif
  302.         play_this_card (SUIT_DIAMONDS, 0) ;
  303.         return ;
  304.         }
  305.         }
  306. #ifndef NO_LOGGING
  307. if (logerr)
  308. fprintf (logerr, "Not first round of diamonds or I don't have any\n") ;
  309. #endif
  310.  
  311.     /*
  312.      * Now look to see if I have the remaining card of a club doubleton
  313.      */
  314.     if (status->suit_leads[SUIT_CLUBS] == 1)
  315.         {
  316.         if (ph->n_in_suit[SUIT_CLUBS] == 1)
  317.         {
  318. #ifndef NO_LOGGING
  319. if (logerr)
  320. fprintf (logerr, "Playing last club of a doubleton\n") ;
  321. #endif
  322.         play_this_card (SUIT_CLUBS, 0) ;
  323.         return ;
  324.         }
  325.         }
  326. #ifndef NO_LOGGING
  327. if (logerr)
  328. fprintf (logerr, "Not second round of clubs or I don't have one left\n") ;
  329. #endif
  330.  
  331.     /*
  332.      * Now look to see if any of my lowest cards are the lowest remaining
  333.      * (With at least one other out there!)
  334.      * Do it in the order clubs, diamonds, hearts, spades
  335.      */
  336.     for (i=N_SUITS-1;  i >= 0;  i--)
  337.         {
  338.         int card, rank ;
  339.         if (ph->n_in_suit[i] == 0)
  340.         continue ;
  341.  
  342.         if (
  343.         LowestInSuit(i) == status->lowest_remaining[i] &&
  344.         status->number_remaining_in_other_hands[i] > 0 &&
  345.         (i != SUIT_HEARTS || info->points_broken)
  346.            )
  347.         {
  348.         if (i != SUIT_SPADES || !status->i_have_queen)
  349.             {
  350. #ifndef NO_LOGGING
  351. if (logerr)
  352. fprintf (logerr, "Playing lowest remaining card of suit %d\n", i) ;
  353. #endif
  354.             play_this_card (i, IndexOfLowestInSuit(i)) ;
  355.             return ;
  356.             }
  357.         }
  358.         }
  359. #ifndef NO_LOGGING
  360. if (logerr)
  361. fprintf (logerr, "No lowest remaining cards in my hand\n") ;
  362. #endif
  363.  
  364.     /*
  365.      * Lead a relatively low card (likely someone will play higher)
  366.      * To determine likelihood,
  367.      *  1) check the number of cards remaining in other hands that beat
  368.      *     my lowest.
  369.      *  2) check the number of hands (-1) that followed suit the last time
  370.      *  3) if (2) is greater than (1), it's a fair bet
  371.      */
  372.     for (i=0;  i < N_SUITS;  i++)
  373.         {
  374.         int my_lowest ;
  375.         int cards_under_me ;
  376.         int followed_suit ;
  377.  
  378.         /* Continue if I have no cards in this suit */
  379.         if (ph->n_in_suit[i] == 0)
  380.         continue ;
  381.  
  382.         /* Continue if opponents have no cards in this suit */
  383.         if (status->number_remaining_in_other_hands[i] == 0)
  384.         continue ;
  385.  
  386.         /* Continue if my worst is better than opponent's best */
  387.         if (LowestInSuit(i) > status->highest_remaining_in_other_hands[i])
  388.         continue ;
  389.  
  390.         /* continue if I can't lead a heart */
  391.         if (i == SUIT_HEARTS &&
  392.         !info->points_broken &&
  393.         !status->i_have_only_points)
  394.         continue ;
  395.  
  396.         my_lowest = LowestInSuit(i) ;
  397.         cards_under_me = 0 ;
  398.  
  399.         for (j=my_lowest-1;  j >= 0;  j--)
  400.         {
  401.         if (status->card_status[i][j] != Played)
  402.             cards_under_me++ ;
  403.         }
  404.  
  405.         for (j=CurrentTrick-1;  j >= 0;  j--)
  406.         {
  407.         if (SuitOfTrick(j,0) == i)
  408.             break ;
  409.         }
  410.         if (j < 0)
  411.         {
  412.         followed_suit = 3 ;
  413.         }
  414.         else
  415.         {
  416.         followed_suit = 0 ;
  417.         for (k=0;  k < N_PLAYERS;  k++)
  418.             {
  419.             if (TrickPlayer(j,k) == player_index)
  420.             continue ;
  421.             if (SuitOfTrick(j,k) == SuitOfTrick(j,0))
  422.             followed_suit++ ;
  423.             }
  424.         }
  425. #ifndef NO_LOGGING
  426. if (logerr)
  427. fprintf (logerr, "cards_under_me, followed_suit: %d\n",
  428. cards_under_me, followed_suit) ;
  429. #endif
  430.         if (followed_suit > cards_under_me)
  431.         {
  432. #ifndef NO_LOGGING
  433. if (logerr)
  434. fprintf (logerr, "Playing reasonably low card\n") ;
  435. #endif
  436.         play_this_card (i, IndexOfLowestInSuit(i)) ;
  437.         return ;
  438.         }
  439.         }
  440. #ifndef NO_LOGGING
  441. if (logerr)
  442. fprintf (logerr, "No reasonably low card to play\n") ;
  443. #endif
  444.  
  445.     /**
  446.      ** Try to Avoid a BAD Lead
  447.      **/
  448.     /* Bad leads are :
  449.      *    The Queen of spades
  450.      *    Ace or King of spades if queen still out
  451.      *    any spade if short in spades and hold Q, K, or A
  452.      *    High cards in oft-lead suits
  453.      */
  454.     /* TODO:
  455.     if (IHave(SUIT_SPADES, RANK_QUEEN))
  456.         MarkBad(SUIT_SPADES, RANK_QUEEN) ;
  457.     if (IHave(SUIT_SPADES, RANK_KING) && !info->queen_played)
  458.         MarkBad(SUIT_SPADES, RANK_KING) ;
  459.     if (IHave(SUIT_SPADES, RANK_ACE) && !info->queen_played)
  460.         MarkBad(SUIT_SPADES, RANK_ACE) ;
  461.     */
  462.  
  463.     /**
  464.      ** Try to select something non-bad
  465.      **/
  466.     /* If no good leads, choose from non-bad leads :
  467.      *    lowest club unless guaranteed to lose
  468.      *    lowest diamond unless guaranteed to lose
  469.      *    lowest heart unless guaranteed to lose
  470.      *    lowest spade
  471.      */
  472.     /*
  473.      * Now look to see if any of my lowest cards have some higher ones out
  474.      * Do it in the order clubs, diamonds, hearts, spades
  475.      */
  476.     for (i=N_SUITS-1;  i >= 0;  i--)
  477.         {
  478.         int card, rank ;
  479.         if (ph->n_in_suit[i] == 0) /* continue if none in this suit */
  480.         continue ;
  481.  
  482.         if (i == SUIT_HEARTS &&    /* continue if I can't lead a heart */
  483.         !info->points_broken &&
  484.         !status->i_have_only_points)
  485.         continue ;
  486.  
  487.         for (j=CARDS_PER_SUIT-1;  j > LowestInSuit(i);  j--)
  488.         {
  489.         /* if there is a higher card out, I can lead it */
  490.         /* Todo : rate each suit according to likelihood,
  491.            e.g., with only one person following suit, it can
  492.            be determined if he can beat me... */
  493.         if (status->card_status[i][j] == InOpponentHand)
  494.             {
  495. #ifndef NO_LOGGING
  496. if (logerr)
  497. fprintf (logerr, "Playing a card that has a chance\n") ;
  498. #endif
  499.             play_this_card (i, IndexOfLowestInSuit(i)) ;
  500.             return ;
  501.             }
  502.         }
  503.         }
  504. #ifndef NO_LOGGING
  505. if (logerr)
  506. fprintf (logerr, "I'm Hosed!\n") ;
  507. #endif
  508.     /*
  509.      * Well, I have to lead something...
  510.      * Do it in the order clubs, diamonds, hearts, spades
  511.      */
  512.     for (i=N_SUITS-1;  i >= 0;  i--)
  513.         {
  514.         int card, rank ;
  515.         if (ph->n_in_suit[i] == 0) /* continue if none in this suit */
  516.         continue ;
  517.  
  518.         if (i == SUIT_HEARTS &&    /* continue if I can't lead a heart */
  519.         !info->points_broken &&
  520.         !status->i_have_only_points)
  521.         continue ;
  522.  
  523.         /* Playing highest avoids playing queen from AKQ */
  524.         play_this_card (i, IndexOfHighestInSuit) ;
  525.         }
  526.     }
  527.     }
  528.  
  529. /*
  530.  * Else we are following
  531.  */
  532.  
  533. else
  534.     {
  535.     if (status->follow == Following)
  536.     {
  537.     if (ph->n_in_suit[SuitLead] == 1)
  538.         {
  539. #ifndef NO_LOGGING
  540. if (logerr)
  541. fprintf (logerr, "Playing my only one in the suit lead (%d)\n", SuitLead) ;
  542. #endif
  543.         play_this_card (SuitLead, IndexOfHighestInSuit) ;
  544.         return ;
  545.         }
  546.  
  547.     if (status->shoot == Shooting)
  548.         {
  549.         }
  550.     else
  551.     if (status->shoot == Defending)
  552.         {
  553.         /* try to take hearts dropped in a trick
  554.          * ignore for now:
  555.          *     shooter is already guaranteed to lose this trick
  556.          *     possibility that swallowing queen is sometimes a good idea
  557.          */
  558.         if (HeartsInThisTrick && !QueenInThisTrick)
  559.         {
  560.         int sole_winner_lost = 0 ;
  561. #ifndef NO_LOGGING
  562. if (logerr)
  563. fprintf (logerr, "Defensively trying to take a point\n") ;
  564. #endif
  565.             /*
  566.          * What I want here is to check if the guy who has the points
  567.          * will not win this trick.  True if he has played and he
  568.          * has already played a card smaller than the trick taking rank.
  569.          */
  570.  
  571.         for (i=0;  i < snap->n_played_to_trick;  i++)
  572.             {
  573.             if (
  574.             (TrickPlayer(CurrentTrick,i) == info->sole_point_holder)
  575.             &&
  576.             (info->sole_point_holder != TrickWinner)
  577.                )
  578.             {
  579.             sole_winner_lost = 1 ;
  580.             break ;
  581.             }
  582.             }
  583.  
  584.         if (sole_winner_lost)
  585.             ;
  586.         else
  587.         if (SuitLead != SUIT_SPADES ||
  588.             Rank(SuitLead,IndexOfHighestInSuit) < RANK_QUEEN)
  589.             {
  590.             if (Rank(SuitLead,IndexOfHighestInSuit) <
  591.             info->trick_taking_rank &&
  592.                 ph->n_in_suit[SuitLead] > 1)
  593.             {
  594.             play_this_card (SuitLead,
  595.                     IndexOfSecondHighestInSuit) ;
  596.             }
  597.             else
  598.             {
  599.             play_this_card (SuitLead,
  600.                     IndexOfHighestInSuit) ;
  601.             }
  602.             return ;
  603.             }
  604.         }
  605.         /*
  606.          * If I can't do any of these, just minimize
  607.          */
  608.         status->shoot = Minimizing; 
  609.         }
  610.  
  611.     if (status->shoot == Minimizing)
  612.         {
  613.         Choice choice ;
  614.         /*
  615.          * if spades lead and I can lose the queen, play it
  616.          * if first round for diamonds or clubs, play the highest
  617.          * if fourth player, play highest if
  618.          *    no points in trick
  619.          *    no queen, and only one opponent has points, and he might win
  620.          *    else, play highestLosing
  621.          *    (TODO:will want to adjust if I don't want the lead)
  622.          * if spades, play the highest under the queen
  623.          * if must play higher, play lowestWinning
  624.          * else, play highestLosing
  625.          */
  626.         if (SuitLead == SUIT_SPADES && status->i_have_queen &&
  627.         info->trick_taking_rank > RANK_QUEEN)
  628.         {
  629.         for (i=0;  i < 3;  i++)
  630.             {
  631.             if (Rank(SUIT_SPADES, i) == RANK_QUEEN)
  632.             {
  633.             play_this_card (SUIT_SPADES, i) ;
  634.             return ;
  635.             }
  636.             }
  637.         }
  638.         if (status->suit_leads[SuitLead] == 1 &&
  639.         (SuitLead == SUIT_CLUBS || SuitLead == SUIT_DIAMONDS) &&
  640.         info->n_hearts_played[CurrentTrick] == 0 &&
  641.         (!info->queen_played ||
  642.          info->queen_played_trick != CurrentTrick))
  643.         {
  644.         /*
  645.          * TODO : Always play low if guaranteed that I have
  646.          * gobs of low cards.  Why take any chance at all?
  647.          * (For example, 4D is lead.  I have 2,3,5,x,x...
  648.          *  Playing the 2 still leaves me with 2 safe low cards.)
  649.          */
  650. #ifndef NO_LOGGING
  651. if (logerr)
  652. fprintf (logerr, "Playing High Club or Diamond\n") ;
  653. #endif
  654.         choice = HighestCard ;
  655.         }
  656.         else
  657.         if (snap->n_played_to_trick == 3)
  658.         {
  659. #define IMustWinThisTrick (Rank(SuitLead,IndexOfLowestInSuit(SuitLead)) > \
  660.                info->trick_taking_rank)
  661.         if (IMustWinThisTrick ||
  662.            (info->n_hearts_played[CurrentTrick] == 0 &&
  663.             (!info->queen_played ||
  664.              info->queen_played_trick != CurrentTrick)))
  665.             {
  666. #ifndef NO_LOGGING
  667. if (logerr)
  668. fprintf (logerr, "Playing High in Last position\n") ;
  669. #endif
  670.             if (SuitLead == SUIT_SPADES &&
  671.             Rank(SUIT_SPADES,0) == RANK_QUEEN &&
  672.             RANK_QUEEN > info->trick_taking_rank)
  673.             {
  674.             choice = SecondHighestCard ;
  675.             }
  676.             else
  677.             {
  678.             choice = HighestCard ;
  679.             }
  680.             }
  681.         else
  682.             {
  683. #ifndef NO_LOGGING
  684. if (logerr)
  685. fprintf (logerr, "Playing Low in Last position\n") ;
  686. #endif
  687.             choice = HighestLosingCard ;
  688.             }
  689.         }
  690.         else
  691.         if (SuitLead == SUIT_SPADES)
  692.         {
  693.         for (i=0;  i < ph->n_in_suit[SUIT_SPADES];  i++)
  694.             {
  695.             if (Rank(SUIT_SPADES,i) < RANK_QUEEN)
  696.             break ;
  697.             }
  698.         if (i < ph->n_in_suit[SUIT_SPADES])
  699.             {
  700. #ifndef NO_LOGGING
  701. if (logerr)
  702. fprintf (logerr, "Playing high spade under the queen\n") ;
  703. #endif
  704.             play_this_card (SUIT_SPADES, i) ;
  705.             return ;
  706.             }
  707.         else
  708.             {
  709. #ifndef NO_LOGGING
  710. if (logerr)
  711. fprintf (logerr, "Playing high spade\n") ;
  712. #endif
  713.             play_this_card (SUIT_SPADES, 0) ;
  714.             return ;
  715.             }
  716.         }
  717.         else
  718.         {
  719. #ifndef NO_LOGGING
  720. if (logerr)
  721. fprintf (logerr, "Playing highest loser\n") ;
  722. #endif
  723.         choice = HighestLosingCard ;
  724.         }
  725.  
  726.         play_this_card (SuitLead, IndexOfChoice(ph,SuitLead,choice)) ;
  727.         return ;
  728.         }
  729.     }
  730.     else
  731.     if (status->follow == Sloughing)
  732.     {
  733.     Boolean defending = False ;
  734.     /*
  735.      * Need to check for first trick and points breakable.
  736.      * If not breakable, we can't drop a point (unless nothing but points!)
  737.      */
  738.     if (status->shoot == Shooting)
  739.         {
  740.         }
  741.     else
  742.     if (status->shoot == Defending)
  743.         {
  744.         defending = True ;
  745.         status->shoot = Minimizing; 
  746.         }
  747.  
  748.     if (status->shoot == Minimizing)
  749.         {
  750.         float rank_factor, length_factor, suit_factor ;
  751.         float worst_factor, card_factor ;
  752.         int card_i, card_j ;
  753.         /*
  754.          * Good sloughs are:
  755.          *    The queen of spades
  756.          *  Thinly defended A,K of spades (see following rule)
  757.          *  High cards in suits with no low cards (short suits first)
  758.          *  Short suits
  759.          *  Hearts
  760.          */
  761. if (logerr) fprintf (logerr, "defending: %d\n", defending) ;
  762.         if (status->card_status[SUIT_SPADES][RANK_QUEEN] == InMyHand)
  763.         {
  764.         if (CurrentTrick > 0 || history->points_on_first_trick)
  765.             {
  766. #ifndef NO_LOGGING
  767. if (logerr)
  768. fprintf (logerr, "Sloughing the Queen of Spades\n") ;
  769. #endif
  770.             for (i=0;  i < ph->n_in_suit[SUIT_SPADES];  i++)
  771.             {
  772.             if (Rank(SUIT_SPADES,i) == RANK_QUEEN)
  773.                 {
  774.                 play_this_card (SUIT_SPADES, i) ;
  775.                 return ;
  776.                 }
  777.             }
  778.             }
  779.         }
  780. #ifndef NO_LOGGING
  781. if (logerr)
  782. fprintf (logerr, "No queen to slough\n") ;
  783. #endif
  784.  
  785.         worst_factor = -1.0 ;
  786.         for (i=0;  i < N_SUITS;  i++)
  787.         {
  788.         if (i == SUIT_HEARTS &&
  789.             CurrentTrick==0 &&
  790.             !history->points_on_first_trick &&
  791.             !status->i_have_only_points)
  792.             continue ;
  793.         for (j=0;  j < ph->n_in_suit[i];  j++)
  794.             {
  795.             float defense_factor = 1.0 ;
  796.             int high_out, low_out ;
  797.             /*
  798.              * Compute the defense_factor
  799.              */
  800.             /*
  801.              * Do not drop a protected heart honor
  802.              */
  803.             if (i == SUIT_HEARTS && j == 0 && defending)
  804.             {
  805.             /*
  806.              * Find out how many are still out that can beat
  807.              * my highest heart
  808.              */
  809.             int n_able_to_beat = 0 ;
  810.             for (k=Rank(i,j)+1;  k < CARDS_PER_SUIT;  k++)
  811.                 if (status->card_status[i][k] == InOpponentHand)
  812.                 n_able_to_beat++ ;
  813. #ifndef NO_LOGGING
  814. if (logerr)
  815. fprintf (logerr, "There are %d hearts out that can beat my highest heart\n",
  816. n_able_to_beat) ;
  817. #endif
  818.             /*
  819.              * If I have that many "protectors", I won't drop
  820.              * my highest heart
  821.              */
  822.             if (ph->n_in_suit[i] > n_able_to_beat)
  823.                 defense_factor = 0.0 ;
  824.             }
  825.             /*
  826.              * (Ignore for now:)
  827.              * Do not drop ANY well-protected honor
  828.              */
  829.  
  830.             /*
  831.              * Compute the suit_factor
  832.              */
  833.             if (i == SUIT_SPADES)
  834.             {
  835.             if (Rank(i,j) == RANK_ACE || Rank(i,j) == RANK_KING)
  836.                 suit_factor = 1.0 ;
  837.             else
  838.                 suit_factor = 0.0 ;
  839.             }
  840.             else
  841.             if (i == SUIT_HEARTS)
  842.             {
  843.             suit_factor = 0.8 ;
  844.             }
  845.             else
  846.             suit_factor = 0.6 ;
  847.  
  848.             /*
  849.              * Compute the rank_factor
  850.              * (all cards which are higher than all of the opponents'
  851.              * cards are 1.0, all cards which are lower are 0.1, and
  852.              * those in between are scaled accordingly
  853.              */
  854.             if (status->number_remaining_in_other_hands[i] > 0)
  855.             {
  856.             if (Rank(i,j) >
  857.                 status->highest_remaining_in_other_hands[i])
  858.                 {
  859.                 rank_factor = 1.0 ;
  860.                 }
  861.             else
  862.             if (Rank(i,j) <
  863.                 status->lowest_remaining_in_other_hands[i])
  864.                 {
  865.                 rank_factor = 0.05 ;
  866.                 }
  867.             else
  868.                 {
  869.                 rank_factor = ((float)Rank(i,j) -
  870.                  status->lowest_remaining_in_other_hands[i]) /
  871.                  ((float)status->highest_remaining_in_other_hands[i]
  872.                   - status->lowest_remaining_in_other_hands[i]) ;
  873.                 }
  874.             }
  875.             else
  876.             {
  877.             rank_factor = 0.0 ;
  878.             }
  879.             /*
  880.              * Compute the length_factor
  881.              * Singletons are 1.0
  882.              * Doubletons are 0.5
  883.              * Tripletons are 0.25, etc.
  884.              */
  885.             length_factor = 1.0 ;
  886.             for (k=2;  k < ph->n_in_suit[i];  k++)
  887.             length_factor /= 2.0 ;
  888.             card_factor = suit_factor * rank_factor *
  889.                   length_factor * defense_factor ;
  890. #ifndef NO_LOGGING
  891. if (logerr)
  892. fprintf (logerr, "card_factor : %5.3f = %4.2f * %4.2f * %4.2f * %4.2f\n",
  893. card_factor, suit_factor, rank_factor, length_factor, defense_factor) ;
  894. #endif
  895.             if (card_factor > worst_factor)
  896.             {
  897.             worst_factor = card_factor ;
  898.             card_i = i ;
  899.             card_j = j ;
  900.             }
  901.             }
  902.         }
  903.         play_this_card (card_i, card_j) ;
  904.         return ;
  905.         }
  906.     }
  907.     }
  908.  
  909. return ;
  910. }
  911.  
  912. static void
  913. find_the_initial_queen (ph, player_index)
  914.     PvtHistory *ph ;
  915.     int player_index ;
  916. {
  917. /* in hand from where vs. passed to whom vs. unknown */
  918. return ;
  919. }
  920.  
  921. static void
  922. find_the_current_queen (ph, player_index)
  923.     PvtHistory *ph ;
  924.     int player_index ;
  925. {
  926. /* queen in hand, ahead, behind, or unknown position in current trick */
  927. return ;
  928. }
  929.  
  930. static void
  931. determine_initial_defense_potential (ph, player_index)
  932.     PvtHistory *ph ;
  933.     int player_index ;
  934. {
  935. /*
  936.  * if we have a protected heart honor we are defending
  937.  */
  938. /*
  939.  * if currently shooting, find out if we still are
  940.  *    if not still shooting, find out if we need to be defending
  941.  * if currently defending, find out if we still are
  942.  * if currently minimizing, we just return
  943.  */
  944. status->shoot = Defending ;
  945. return ;
  946. }
  947.  
  948. static void
  949. determine_current_defense_potential (ph, player_index)
  950.     PvtHistory *ph ;
  951.     int player_index ;
  952. {
  953. int i ;
  954. /*
  955.  * if hearts are split we no longer need to defend
  956.  */
  957. int n_have_points_in_hand = 0 ;
  958. for (i=0;  i < N_PLAYERS;  i++)
  959.     {
  960.     if (info->n_points_taken[i])
  961.     {
  962.     info->sole_point_holder = i ;
  963.     n_have_points_in_hand++ ;
  964.     }
  965.     }
  966. if (n_have_points_in_hand > 1)
  967.     status->shoot = Minimizing ;
  968. else
  969.     status->shoot = Defending ;
  970. if (logerr) fprintf (logerr, "status->shoot = %d\n", status->shoot) ;
  971. return ;
  972. }
  973.  
  974. static void
  975. find_trick_stats (ph, player_index)
  976.     PvtHistory *ph ;
  977.     int player_index ;
  978. {
  979. int i,j,k ;
  980. /*
  981.  * how many cards in this suit have been played
  982.  * how many times this suit has been led
  983.  * whether we are following or sloughing
  984.  */
  985. /*
  986.  * (Do it from scratch every time)
  987.  * Set every card to "in opponent's hand"
  988.  * Set cards dealt to me "in my hand"
  989.  * Set cards passed by me "in opponent's hand"
  990.  * Set cards passed to me "in my hand"
  991.  * Set cards played "played"
  992.  */
  993.  
  994. for (i=0;  i < N_SUITS;  i++)
  995.     {
  996.     status->suit_leads[i] = 0 ;
  997.     for (j=0;  j < CARDS_PER_SUIT;  j++)
  998.     {
  999.     status->card_status[i][j] = InOpponentHand ;
  1000.     }
  1001.     }
  1002.  
  1003. for (i=0;  i < CARDS_PER_PLAYER;  i++)
  1004.     {
  1005.     int card, suit, rank ;
  1006.     card = ph->cards_dealt[i] ;
  1007.     suit = info->deck[card].suit ;
  1008.     rank = info->deck[card].rank ;
  1009.     status->card_status[suit][rank] = InMyHand ;
  1010.     }
  1011.  
  1012. if (snap->current_pass != KeepPass)
  1013.     {
  1014.     for (i=0;  i < N_DISCARDS;  i++)
  1015.     {
  1016.     int card, suit, rank ;
  1017.     card = ph->cards_passed[i] ;
  1018.     suit = info->deck[card].suit ;
  1019.     rank = info->deck[card].rank ;
  1020.     status->card_status[suit][rank] = InOpponentHand ;
  1021.     card = ph->cards_received[i] ;
  1022.     suit = info->deck[card].suit ;
  1023.     rank = info->deck[card].rank ;
  1024.     status->card_status[suit][rank] = InMyHand ;
  1025.     }
  1026.     }
  1027.  
  1028.  
  1029. for (i=0;  i <= CurrentTrick;  i++)
  1030.     {
  1031.     for (j=0;  j < N_PLAYERS;  j++)
  1032.     {
  1033.     int card, suit, rank ;
  1034.     if (i == CurrentTrick && j >= snap->n_played_to_trick)
  1035.         continue ;
  1036.     card = history->trick[i].card[j] ;
  1037.     suit = info->deck[card].suit ;
  1038.     rank = info->deck[card].rank ;
  1039.     status->card_status[suit][rank] = Played ;
  1040.     if (j == 0)
  1041.         status->suit_leads[suit]++ ;
  1042.     }
  1043.     }
  1044.  
  1045. for (i=0;  i < N_SUITS;  i++)
  1046.     {
  1047.     for (j=0;  j < CARDS_PER_SUIT;  j++)
  1048.     {
  1049.     if (status->card_status[i][j] != Played)
  1050.         {
  1051.         status->lowest_remaining[i] = j ;
  1052.         break ;
  1053.         }
  1054.     }
  1055.     }
  1056.  
  1057. for (i=0;  i < N_SUITS;  i++)
  1058.     {
  1059.     status->number_remaining_in_other_hands[i] = 0 ;
  1060.     for (j=0;  j < CARDS_PER_SUIT;  j++)
  1061.     {
  1062.     if (status->card_status[i][j] == InOpponentHand)
  1063.         {
  1064.         status->number_remaining_in_other_hands[i]++ ;
  1065.         }
  1066.     }
  1067.     }
  1068.  
  1069. for (i=0;  i < N_SUITS;  i++)
  1070.     {
  1071.     status->lowest_remaining_in_other_hands[i] = -1 ;
  1072.     for (j=0;  j < CARDS_PER_SUIT;  j++)
  1073.     {
  1074.     if (status->card_status[i][j] == InOpponentHand)
  1075.         {
  1076.         status->lowest_remaining_in_other_hands[i] = j ;
  1077.         break ;
  1078.         }
  1079.     }
  1080.     }
  1081.  
  1082. for (i=0;  i < N_SUITS;  i++)
  1083.     {
  1084.     status->highest_remaining_in_other_hands[i] = -1 ;
  1085.     for (j=CARDS_PER_SUIT-1;  j >= 0;  j--)
  1086.     {
  1087.     if (status->card_status[i][j] == InOpponentHand)
  1088.         {
  1089.         status->highest_remaining_in_other_hands[i] = j ;
  1090.         break ;
  1091.         }
  1092.     }
  1093.     }
  1094.  
  1095. /*
  1096.  * See if I have the queen
  1097.  */
  1098.  
  1099. status->i_have_queen = False ;
  1100.  
  1101. for (j=0;  j < ph->n_in_suit[SUIT_SPADES];  j++)
  1102.     {
  1103.     if (Rank(SUIT_SPADES,j) == RANK_QUEEN)
  1104.     {
  1105.     status->i_have_queen = True ;
  1106.     break ;
  1107.     }
  1108.     }
  1109.  
  1110. /*
  1111.  * See if I have only points in my hand
  1112.  */
  1113.  
  1114. status->i_have_only_points = True ;
  1115.  
  1116. for (i=0;  i < N_SUITS;  i++)
  1117.     {
  1118.     for (j=0;  j < ph->n_in_suit[i];  j++)
  1119.     {
  1120.     if (i != SUIT_HEARTS && (i != SUIT_SPADES || Rank(i,j) != RANK_QUEEN))
  1121.         {
  1122.         status->i_have_only_points = False ;
  1123.         break ;
  1124.         }
  1125.     }
  1126.     if (j < ph->n_in_suit[i])
  1127.     break ;
  1128.     }
  1129.  
  1130. /*
  1131.  * See whether I am following or sloughing
  1132.  */
  1133.  
  1134. if (snap->n_played_to_trick)
  1135.     {
  1136.     status->follow = ph->n_in_suit[SuitLead] ? Following : Sloughing ;
  1137.     }
  1138.  
  1139. show_stats (status) ;
  1140. return ;
  1141. }
  1142.  
  1143. static void
  1144. play_this_card (suit, index)
  1145.     int suit ;
  1146.     int index ;
  1147. {
  1148. data[1] = suit ;
  1149. data[2] = index ;
  1150. card_picked (NULL, data, NULL) ;
  1151. return ;
  1152. }
  1153.  
  1154. int
  1155. IndexOfChoice (ph, suit, choice)
  1156.     PvtHistory *ph ;
  1157.     int suit ;
  1158.     Choice choice  ;
  1159. {
  1160. int i ;
  1161. if (choice == HighestCard)
  1162.     {
  1163.     return 0 ;
  1164.     }
  1165. else
  1166. if (choice == SecondHighestCard)
  1167.     {
  1168.     return 1 ;
  1169.     }
  1170. else
  1171. if (choice == HighestLosingCard)
  1172.     {
  1173.     for (i=ph->n_in_suit[suit]-1;  i >= 0;  i--)
  1174.     if (Rank(suit,i) > info->trick_taking_rank)
  1175.         break ;
  1176.     if (i < ph->n_in_suit[suit]-1)
  1177.     {
  1178. #ifndef NO_LOGGING
  1179. if (logerr)
  1180. fprintf (logerr, "Selected Highest Loser\n") ;
  1181. #endif
  1182.     return i+1 ;
  1183.     }
  1184.     else
  1185.     {
  1186. #ifndef NO_LOGGING
  1187. if (logerr)
  1188. fprintf (logerr, "Selected Lowest Winner\n") ;
  1189. #endif
  1190.     return i ;
  1191.     }
  1192.     }
  1193. }
  1194.  
  1195. show_stats (status)
  1196.     PlayStatus *status ;
  1197. {
  1198. int i,j ;
  1199. #ifndef NO_LOGGING
  1200. if (!logerr)
  1201.     return ;
  1202. fprintf (logerr, "\n") ;
  1203. for (i=0;  i < N_SUITS;  i++)
  1204.     {
  1205.     for (j=CARDS_PER_SUIT-1; j >= 0;  j--)
  1206.     {
  1207.     if (status->card_status[i][j] == InOpponentHand)
  1208.         {
  1209.         fprintf (logerr, "o ") ;
  1210.         }
  1211.     else
  1212.     if (status->card_status[i][j] == InMyHand)
  1213.         {
  1214.         fprintf (logerr, "m ") ;
  1215.         }
  1216.     else
  1217.         {
  1218.         fprintf (logerr, ". ") ;
  1219.         }
  1220.     }
  1221.     fprintf (logerr, "  (%s)\n", game->suit[i].name) ;
  1222.     }
  1223.  
  1224. fprintf (logerr, "\n") ;
  1225. fprintf (logerr, "number_remaining:  ") ;
  1226. for (i=0;  i < N_SUITS;  i++)
  1227.     fprintf (logerr, "%3d", status->number_remaining_in_other_hands[i]) ;
  1228. fprintf (logerr, "\n") ;
  1229.  
  1230. fprintf (logerr, "highest_remaining: ") ;
  1231. for (i=0;  i < N_SUITS;  i++)
  1232.     fprintf (logerr, "%3d", status->highest_remaining_in_other_hands[i]) ;
  1233. fprintf (logerr, "\n") ;
  1234.  
  1235. fprintf (logerr, "lowest_remaining:  ") ;
  1236. for (i=0;  i < N_SUITS;  i++)
  1237.     fprintf (logerr, "%3d", status->lowest_remaining_in_other_hands[i]) ;
  1238. fprintf (logerr, "\n") ;
  1239.  
  1240. fprintf (logerr, "suit_leads      :  ") ;
  1241. for (i=0;  i < N_SUITS;  i++)
  1242.     fprintf (logerr, "%3d", status->suit_leads[i]) ;
  1243. fprintf (logerr, "\n") ;
  1244.  
  1245. fprintf (logerr, "CurrentTrick        : %d\n", CurrentTrick) ;
  1246. fprintf (logerr, "queen_played        : %d\n", info->queen_played) ;
  1247. fprintf (logerr, "queen_played_trick    : %d\n", info->queen_played_trick) ;
  1248. fprintf (logerr, "points_broken        : %d\n", info->points_broken) ;
  1249. fprintf (logerr, "i_have_only_points    : %d\n", status->i_have_only_points) ;
  1250. fprintf (logerr, "trick_taking_rank    : %d\n", info->trick_taking_rank) ;
  1251. #endif
  1252.  
  1253. return ;
  1254. }
  1255.  
  1256.