home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_100 / 101_01 / yahtzee.c < prev    next >
Text File  |  1985-11-14  |  12KB  |  385 lines

  1. /* YAHTZEE Dice game            Steve Ward
  2.  * USAGE:
  3.  *
  4.  *    yahtzee [-dn] name1 name2 name3 ...
  5.  * where the namei are player's names, prefixed by = for automated
  6.  * (computer) players.
  7.  *
  8.  *    yahtzee
  9.  * for solitaire.
  10.  *
  11.  * USE special function keys to select dice, roll selected dice, and end
  12.  *  an inning; keypad up/down arrows select where to enter your score.
  13.  *
  14.  * See YAHTZEE.HLP for full instructions.
  15.  *
  16.  * COMPILE and CLINK with CIO.CRL!
  17.  */
  18.  
  19. #define    ROLLX    39        /* Coordinates for light buttons.    */
  20. #define    DONEX    46
  21. #define    PASSX    53
  22. #define    OOPSX    60
  23. #define    OOPSC    'R'
  24. #define    PASSC    'Q'
  25. #define    DONEC    'P'
  26. #define    ROLLC    'J'
  27.  
  28. #define    GOX    45        /* Coordinates for prompt.        */
  29. #define    GOY    22
  30. #define    GAMEY    20
  31.  
  32. #define    SCOREX    30        /* leftmost column for scores        */
  33. #define    DIEY    22
  34. #define    LABLIN    24        /* Line for labels            */
  35. #define    PLAYERS    10        /* Max number of players        */
  36. #define    NONE    127        /* char-size illegal value.        */
  37.  
  38. char Dice[5];
  39. char nplayers;            /* actual number of players.        */
  40. char Potent[13];        /* Potential score...            */
  41. char PotKind, PotSum, PotStr;    /* Filled by Pot            */
  42. char PotMax, PotCnt;
  43.  
  44. struct Player
  45.  { char Scores[13];        /* Scores, or 127 iff none yet.        */
  46.    char Select;            /* Currently selected category.        */
  47.    char Col;            /* Column number, for scores.        */
  48.    char Name[40];        /* Name of player.            */
  49.    int  Total;            /* total score.                */
  50.    int  Games;
  51.  } Who[PLAYERS];
  52.  
  53. /* Initialize a player:                            */
  54.  
  55. iplayer(name, pl)
  56.  char *name;    struct Player *pl;
  57.  {    char i, *fake;    fake = "==0==";
  58.     if ((!name[1]) && (*name == '=')) { name = fake; name[3]++; }
  59.     for (i=0; i<13; i++) pl->Scores[i] = NONE;
  60.     pl->Select = NONE;
  61.     for (i=0; pl->Name[i] = name[i]; i++); }
  62.  
  63. Buzz() { putchar(7); }
  64. MoveTo(x, y) { puts("\033Y"); putchar(y+32); putchar(x+32); }
  65.  
  66. char ShowX, ShowY, *ShowSc; int ShowTot;
  67.  
  68. Show1(n, flag)
  69.  char n, flag;
  70.  {    int val;
  71.     MoveTo(ShowX, ShowY++);
  72.     if (n == 255) val = ShowTot;    else val = ShowSc[n];
  73.     if (!flag) { puts("\033p");    val = Potent[n]; }
  74.     else if (flag == 44) puts("\033p");
  75.     if (val == NONE) puts("  ? ");
  76.     else { printf(" %2d", val); ShowTot += val; }
  77.     if (!flag || (flag == 44)) puts("\033q"); }
  78.  
  79. Show(pl)        /* Show the scores of a player.        */
  80.  char pl;
  81.  {    struct Player *p;    char cc, tot, f, j;
  82.     Pot(pl);
  83.     ShowX = (p = &Who[pl])->Col-1;    ShowY = 1;    ShowTot = 0;
  84.     ShowSc = p->Scores;    cc = 0;        f = p->Select;
  85.     Show1(cc++,f--);    Show1(cc++,f--);    Show1(cc++,f--);
  86.     Show1(cc++,f--);    Show1(cc++,f--);    Show1(cc++,f--);
  87.     tot = ShowTot;    Show1(255,44);    ShowTot = j = tot>=63? 35:0;
  88.     Show1(255,44);
  89.     tot = ShowTot = tot+j;    Show1(255,44);    ShowTot = tot;
  90.     ShowY++;
  91.     Show1(cc++,f--);    Show1(cc++,f--);    Show1(cc++,f--);
  92.     Show1(cc++,f--);    Show1(cc++,f--);    Show1(cc++,f--);
  93.     Show1(cc++,f--);
  94.     p->Total = ShowTot;
  95.     Show1(255,44); }
  96.  
  97. char Straight(die)    /* Gives longest straight starting at die    */
  98.  {    char i, j;
  99.     for (i=1; i<6; i++)
  100.      { die++;
  101.        for (j=0; j<5; j++) if (Dice[j] == die) goto hit;
  102.        break;
  103.    hit:       continue; }
  104.     return i; }
  105.  
  106. char Kind(die)        /* Gives number of dice of count die        */
  107.  {    char count, i;
  108.     for (i=count=0; i<5; i++) if (die == Dice[i]) count++;
  109.     return count; }
  110.  
  111. Pot(pl)        /* Compute potential scores for player.        */
  112.  char pl;
  113.  {    char i,j,k;
  114.     for (i=0; i<13; i++) Potent[i] = 0;
  115.     for (i=0; i<5; i++) if (((j = Dice[i])>0) && (j<7)) Potent[j-1] += j;
  116.     for (PotMax=PotSum=i=PotKind=0; i<5; i++)
  117.      { PotKind |= (1<<(j=Kind(k=Dice[i]))); PotSum += Dice[i];
  118.        if (j>PotMax) { PotMax=j; PotCnt=k; }}
  119.     Potent[12] = PotSum;
  120.     if ((PotKind & 0xC) == 0xC) Potent[8] = 25;
  121.     if (PotKind & 0x38) Potent[6] = PotSum;
  122.     if (PotKind & 0x30) Potent[7] = PotSum;
  123.     if (PotKind & 0x20) Potent[11] = 50;
  124.     for (i=PotStr=0; i<5; i++) if ((j = Straight(Dice[i])) > PotStr)
  125.         PotStr=j;
  126.     if (PotStr >= 4) Potent[9] = 30;
  127.     if (PotStr == 5) Potent[10] = 40; }
  128.  
  129.  
  130. Play(pl)        /* Make a player's move; returns 0 iff OK. */
  131.  char pl;
  132.  {    Pot(pl);
  133.     Who[pl].Scores[Who[pl].Select] = Potent[Who[pl].Select]; }
  134.  
  135. Bd(f)
  136.  char f;
  137.  {    char i, *cc;
  138.     cc = " . ";
  139.     if (f == 1) { puts("\033F"); cc = "iii"; }
  140.     else if (!f) puts("\033q");
  141.     for (i=((80-SCOREX)/3); i--;) puts(cc);
  142.     puts("\033p\033G\n"); }
  143.  
  144. Board()
  145.  {    char i;
  146.     printf("\033H\033J\033p\033G");
  147.     printf(" H89 YAHTZEE 1.1            \033F");
  148.     for (i=48; i--;) putchar('i'); puts("\033G\n");
  149.     printf("        ACES        ADD 1's "); Bd(0);    /* Y = 1 */
  150.     printf("        TWOS        ADD 2's "); Bd(0);
  151.     printf("        THREES      ADD 3's "); Bd(0);
  152.     printf("        FOURS       ADD 4's "); Bd(0);
  153.     printf("        FIVES       ADD 5's "); Bd(0);
  154.     printf("        SIXES       ADD 6's "); Bd(0);
  155.     printf("   Subtotal  .  .  .  .  .  "); Bd(2);        /* Y = 7 */
  156.     printf("   Bonus iff >= 63       35 ");    Bd(2);        /* Y = 8 */
  157.     printf("TOTAL ABOVE   .  .  .  .  . ");    Bd(2);        /* Y = 9 */
  158.     printf("                            \n");
  159.            printf("        3 of a kind     SUM ");    Bd(0);    /* Y = 11 */
  160.     printf("        4 of a kind     SUM ");    Bd(0);
  161.     printf("        Full House       25 ");    Bd(0);
  162.     printf("        4 Straight       30 ");    Bd(0);
  163.     printf("        5 Straight       40 ");    Bd(0);
  164.     printf("        YAHTZEE          50 ");    Bd(0);
  165.     printf("        Chance          SUM ");    Bd(0);
  166.     printf("TOTAL SCORE   .  .  .  .  . ");    Bd(2);
  167.     MoveTo(0, GAMEY);
  168.     printf("GAMES   .  .  .  .  .  .  . "); Bd(1);
  169.     puts("\033p\033F");
  170.     MoveTo(ROLLX, LABLIN);    puts("i ROLL i");
  171.     MoveTo(DONEX, LABLIN);    puts("i DONE i");
  172.     MoveTo(PASSX, LABLIN);    puts("i      i");
  173.     MoveTo(OOPSX, LABLIN);    puts("i OOPS i");
  174.     puts("\033q\033G");
  175.  }
  176.  
  177. #define    TOP    0
  178. #define    MID    8
  179. #define    BOT    16
  180. Die(number, count)
  181.  {    char i, j;
  182.     if (count) puts("\033p\033F");
  183.     for (i=0; i<3; i++)
  184.      { MoveTo(4+(7*number), DIEY+i);
  185.        switch (count+(i<<3))
  186.         {    case TOP: case MID: case BOT:
  187.             case TOP+1: case BOT+1:
  188.             case MID+2:
  189.             case MID+4:    puts("     "); break;
  190.             case TOP+2:
  191.             case TOP+3:    puts("^    "); break;
  192.             case MID+1:
  193.             case MID+3:
  194.             case MID+5:    puts("  ^  "); break;
  195.             case BOT+2:
  196.             case BOT+3:    puts("    ^"); break;
  197.             case TOP+4:    case BOT+4:
  198.             case TOP+5:    case BOT+5:
  199.             case TOP+6:    case MID+6:    case BOT+6:
  200.                     puts("^   ^"); break; }}
  201.     Dice[number] = count;
  202.     puts("\033G\033q"); }
  203.  
  204.  
  205. Roll()
  206.  {    char i;
  207.     for (i=0; i<5; i++) if (!Dice[i]) Die(i, 1+rand()%6); } int    DTime;
  208.  
  209. Go(rolls, player)
  210.  char rolls, player;
  211.  {    char ch, i, save[5];
  212.     Pot(player);
  213.     for (i=0; i<5; i++) Dice[i] = 0;    Roll();
  214.     Who[player].Select = 12;
  215.     if (!Cycle(player, 1)) return 0;
  216.  
  217. Top:    for (i=0; i<5; i++) save[i] = Dice[i];
  218. nsc:    Show(player);
  219.     for (;;)
  220.     { MoveTo(GOX, GOY);
  221.       printf("\033q\033G%s's move: %d rolls left. \033K",
  222.         Who[player].Name, rolls);
  223. esc:      if (Who[player].Name[0] == '=') ch = Auto(player, rolls);
  224.       else ch = getchar();
  225.       switch (ch)
  226.       { case 033:    goto esc;
  227.         case '8':    Cycle(player, -1);    Show(player);    continue;
  228.         case ' ':
  229.         case '2':    Cycle(player, 1);    Show(player);    continue;
  230.         case 'S': case 'T': case 'U': case 'V': case 'W':
  231.              if (!rolls) Buzz();
  232.             else Die(ch - 'S', 0); continue;
  233.         case 0177:
  234.         case OOPSC:    for (i=0; i<5; i++) Die(i, save[i]); continue;
  235.         case ROLLC:    if (rolls>0) { Roll(); rolls--; }
  236.             else Buzz(); goto Top;
  237.         case DONEC:
  238.         case '\r':
  239.         case PASSC:    Play(player);
  240.             Who[player].Select = NONE;    Show(player);
  241.                 return ch;
  242.         default:    putchar(7); continue; }}}
  243.  
  244. /* Make move for a computer player:                */
  245.  
  246. int AutoPar[10];    /* Heuristic parameters -HA#, -HB#, etc.    */
  247.  
  248. char Auto(pl, rolls)
  249.  char pl, rolls;
  250.  {    char gofor, choice, i, j, *sc;
  251.     int value[13], target[6], best, n;
  252.     sc = Who[pl].Scores;
  253.     Pot(pl);
  254.     MoveTo(GOX, GOY+1); printf("Hmmm ... lemme think.\033K",
  255.         value[choice]);
  256.     Delay(DTime);
  257.  
  258.     for (i=0; i<13; i++)
  259.      { if (sc[i] != NONE) value[i] = i-99;
  260.        else    if (i<6) value[i] = 2*(Potent[i]-3*(i+1));/* face counts */
  261.        else if (i==6) value[i] = Potent[i]-20;    /* 3 of a kind */
  262.        else if (i==7) value[i] = Potent[i]-15;    /* 4 of a kind */
  263.        else if (i==9) value[i] = Potent[i]-12;    /* 4 straight  */
  264.        else if (i==10) value[i] = Potent[i]-10;    /* 5 straight  */
  265.        else if (i==12) value[i] = Potent[i]-21-AutoPar[5];    /* CHANCE */
  266.        else value[i] = Potent[i]-10; }
  267.  
  268.     for (i=0; i<6; i++)
  269.      { if (sc[12] == NONE) target[i] = i+i; else target[i] = 0;
  270.        if (sc[i] == NONE) target[i] += i<<2; else target[i] -= 15;
  271.        if ((sc[8] == NONE) && (Kind(i+1) == 3)) target[i] += 6;
  272.        if (sc[11] == NONE) target[i] += 1<<(Kind(i+1));
  273.        target[i] += Kind(i+1)<<3; }
  274.  
  275.     best = -99; gofor = PotCnt; choice = Who[pl].Select;
  276.  
  277.     for (i=0; i<13; i++)
  278.      if (value[i] > best) { best = value[i]; choice = i; }
  279.     Who[pl].Select = choice;
  280.     Show(pl);
  281.  
  282.     if (rolls &&        /* Convert a straight??        */
  283.         (Potent[9] > 0) &&
  284.         (Potent[10] == 0) &&
  285.         (sc[10] == NONE))
  286.      { for (i=0; i<5; i++)    /* Find the useless die.    */
  287.         { j = Dice[i];    Dice[i] = 0;    Pot(pl);    Dice[i] = j;
  288.           if (Potent[9] > 0) { Die(i, 0); goto rollit; }}}
  289.     Pot(pl);
  290.     if ((choice > 7) && (choice < 12)) goto hit; /* End the inning.    */
  291.  
  292.     if (rolls)
  293.      { for (i=0; i<6; i++) if ((n=(target[i]-27-AutoPar[0])) > best)
  294.                 { gofor = i; choice = 255; best=n; }}
  295.  
  296.     if ((choice == 255) || (choice < 8)) goto maxim;/* See if we can help.    */
  297.  
  298. flush:    if (!rolls) goto hit;        /* Least of evils...    */
  299.     for (i=0; i<5; i++) Die(i,0);    /* Re-roll entire hand.    */
  300.     goto rollit;
  301.  
  302. maxim:    if (!rolls) goto hit;        /* Maximize number of chosen dice. */
  303.     for (i=0; i<5; i++)
  304.      if (Dice[i] && (Dice[i] != (gofor+1))) Die(i, 0);
  305. rollit:    MoveTo(GOX, GOY+1); printf("Baby needs shoes ... %d/%d\033K",
  306.         choice, best);
  307.     Delay(DTime>>1);
  308.     return ROLLC;
  309.  
  310. hit:    MoveTo(GOX, GOY+1); printf("I've decided ... %d/%d\033K",
  311.         choice, best);
  312.     Delay(DTime);
  313.     return PASSC;
  314.  }
  315.  
  316. Delay(n)
  317.  {    while (n--) if (kbhit()) { getchar(); break; }}
  318.  
  319. int Cycle(pl, delta)        /* Move a player's Select ... 0 iff done. */
  320.  char pl; int delta;
  321.  {    char *sel, *sc, done;    int ss;
  322.     ss = *(sel = &(Who[pl].Select));    sc = &(Who[pl].Scores);
  323.     done = 14;
  324.     do    { if ((ss += delta) < 0) ss = 12;
  325.           if (ss >= 13) ss = 0; }
  326.     while (--done && (sc[ss] != NONE));
  327.     *sel = ss;
  328.     return done; }
  329.  
  330. Center(text, centx, y, xsize)
  331.  char *text, centx, y, xsize;
  332.  {    char i;
  333.     for (i=0; text[i]; i++);
  334.     if (i > xsize) i = xsize;
  335.     MoveTo(centx - (i>>1), y);
  336.     putchar(' ');
  337.     while (*text && i--) putchar(*text++);
  338.     putchar(' '); }
  339.  
  340. main(argc, argv)
  341.  char **argv;
  342.  {    char i,j,arg,*carg;    int n, *m;
  343.     for (i=0; i<PLAYERS; i++) Who[i].Games = 0;
  344.     for (i=m=0; i<200; i++) n += *m++;
  345.     srand(n);
  346.     for (i=0; i<10; i++) AutoPar[i] = 0;    DTime = 5000;
  347. /*
  348.     TTYMode(30);            /* ^C, FLOW, STRIP, EXPAND */
  349. */
  350.     puts("\033x1\033q\033G\033y7\033x5");
  351.  
  352.     for (arg=1; (arg<argc) && (*(carg = argv[arg]) == '-'); arg++)
  353.      switch (*++carg)
  354.       { case 'R':    srand(atoi(++carg)); continue;
  355.         case 'H':    i = (*++carg)-'A';
  356.             AutoPar[i] = atoi(++carg); continue;
  357.         case 'D':    DTime = atoi(++carg)|1; continue;
  358.         default:    continue;
  359.       }
  360. Again:    nplayers = 0;
  361.     for (i=arg; i<argc; i++) iplayer(argv[i], &Who[nplayers++]);
  362.     if (!nplayers) iplayer("You", &Who[nplayers++]);
  363.     n = (80-SCOREX)/nplayers;
  364.     for (i=SCOREX+(n>>1), j=0; j<nplayers; j++, i += n) Who[j].Col = i;
  365.     Board();
  366.     for (j=0; j<nplayers; j++) Center(Who[j].Name, Who[j].Col, 0, n-1);
  367.     for (i=0; i<nplayers; i++) Show(i);
  368.     for (;;) for (i=0; i<nplayers; i++)
  369.         if (!Go(2, i))
  370.             { for (i=n=0; i<nplayers; i++)
  371.                 if (Who[i].Total > n) n = Who[i].Total;
  372.               for (i=0; i<nplayers; i++)
  373.                 if (Who[i].Total >= n)
  374.                  { MoveTo(Who[i].Col, GAMEY);
  375.                    printf("\033p%3d", ++(Who[i].Games)); }
  376.               MoveTo(GOX, GOY+1);
  377.               for (i=0; i<nplayers; i++)
  378.                 if (Who[i].Total >= n)
  379.                    printf("%s ", Who[i].Name);
  380.               printf("\007WINS! \033q Play again? \033K");
  381.               if (getchar() == 'y') goto Again;
  382.               puts("\033Y6 \033J\033y5\033y1\033q\033G");
  383.               exit(); }
  384.  }
  385.