/* * war.c - play the childhood card game of "war" once and see how long it * takes to end. * * It pauses every 100 turns. If you don't want pauses, run * yes | ./a.out * * Alan J Rosenthal, 4 November 2001. */ #include #include #include /* * Each player holds up to 52 cards at once (that's all there are). * cardsleft[i] indicates the number of values in the array hand[i]. * * A card value is from 0 to 51 inclusive, being suitcode * 4 + facecode. * Suit codes are clubs=0, hearts=1, spades=2, diamonds=3. * Facecodes are number-2 for 2<=number<=10, i.e. ten=8, and then jack=9, * queen=10, king=11, ace=12. */ int hand[2][52]; int cardsleft[2]; extern void printcard(int card); int main() { int nturns; char line[80]; extern void seed(), deal(), doturn(); seed(); deal(); for (nturns = 0; cardsleft[0] && cardsleft[1]; nturns++) { doturn(); /* every 100 turns, pause */ if (nturns % 100 == 99) if (fgets(line, sizeof line, stdin) == NULL) return 0; } printf("Player %d wins after %d turns.\n", cardsleft[0] == 0, nturns); return 0; } void seed() { int i; /* * Seed the PRNG with a time value -- a fairly lame seed but * hopefully good enough for games. So then call it 20 times * (discarding its value), to spread this minor randomness through * the rest of the bits a little. */ srandom(time((time_t *)NULL)); for (i = 0; i < 20; i++) (void)random(); } void deal() { int i; /* put all the cards in hand[0] (cardsleft[0] set later) */ for (i = 0; i < 51; i++) hand[0][i] = i; /* scramble algorithm from CSC 180 web page */ for (i = 51; i > 0; i--) { int exch = random() % (i + 1); int t = hand[0][i]; hand[0][i] = hand[0][exch]; hand[0][exch] = t; } /* transfer second half to player 1 */ for (i = 0; i < 26; i++) hand[1][i] = hand[0][i + 26]; cardsleft[0] = cardsleft[1] = 26; } void doturn() /* just one turn, but possibly multiple wars etc */ { int i, j, winner; int table[52], tablecount; /* the pile of cards on the table right now */ extern void show(int *c0, int *c1); /* show both players' hands */ for (i = 0; i < 2; i++) { printf("[%d]", i); for (j = 0; j < cardsleft[i]; j++) { putchar(' '); printcard(hand[i][j]); } printf("\n"); } /* put two cards face up; they're the first two cards on the table */ /* show() also prints appropriate output */ show(&table[0], &table[1]); tablecount = 2; /* the number of cards sitting on the table, i.e. not in anyone's hand */ /* perform zero or more wars */ /* the face value is the card mod 13 */ while (table[tablecount-1] % 13 == table[tablecount-2] % 13) { printf("; war!\n"); /* put down three cards each, silently (so don't call show()) */ for (i = 0; i < 3 && cardsleft[0] && cardsleft[1]; i++) { table[tablecount++] = hand[0][--cardsleft[0]]; table[tablecount++] = hand[1][--cardsleft[1]]; } if (cardsleft[0] == 0 || cardsleft[1] == 0) { printf("Not enough cards to complete the war.\n"); return; } /* top card in each hand is turned up non-silently */ show(&table[tablecount], &table[tablecount+1]); tablecount += 2; /* * now we loop around, and those two cards just shown will be the top * two in the table array thus will be compared by the loop card */ } /* at this point, we are done with wars. */ /* set winner to 0 or 1 appropriately: */ winner = (table[tablecount-1] % 13 > table[tablecount-2] % 13); printf("; player %d wins\n", winner); /* move up cards in winner's hand to make space for table cards */ for (i = cardsleft[winner] - 1; i >= 0; i--) hand[winner][i+tablecount] = hand[winner][i]; /* add table cards to winner's hand */ for (i = 0; i < tablecount; i++) hand[winner][i] = table[i]; cardsleft[winner] += tablecount; } /* take out a card from each hand, print them, return them */ void show(int *c0, int *c1) { *c0 = hand[0][--cardsleft[0]]; *c1 = hand[1][--cardsleft[1]]; printf("show: [0] "); printcard(*c0); printf(" and [1] "); printcard(*c1); } /* output the two or three characters to represent one card */ void printcard(int c) { if (c % 13 + 2 > 10) putchar("JQKA"[c % 13 + 2 - 11]); else printf("%d", c % 13 + 2); putchar("CHSD"[c / 13]); }