Subject: bin/9651: unbalanced and inefficient draw algorithm in fish(6)
To: None <gnats-bugs@gnats.netbsd.org>
From: None <John.P.Darrow@wheaton.edu>
List: netbsd-bugs
Date: 03/21/2000 16:09:12
>Number: 9651
>Category: bin
>Synopsis: unbalanced and inefficient draw algorithm in fish(6)
>Confidential: no
>Severity: non-critical
>Priority: low
>Responsible: bin-bug-people (Utility Bug People)
>State: open
>Class: change-request
>Submitter-Id: net
>Arrival-Date: Tue Mar 21 16:09:01 2000
>Last-Modified:
>Originator: John Darrow
>Organization:
This was on my own time after hours, my employer had nothing to
do with this :)
>Release: all
>Environment:
System: NetBSD jdarrowpiii.wheaton.edu 1.4V NetBSD 1.4V (JDARROW) #0: Tue Mar 21 15:04:28 CST 2000 jdarrow@jdarrowpiii.wheaton.edu:/var/src/sys/arch/i386/compile/JDARROW i386
>Description:
The card drawing algorithm in fish(6) is unbalanced and
inefficient. It picks a random rank, and then returns that rank
if there are any cards of that rank left in the deck. This means
that, for example, if there are three 3's left, but only one 6,
the routine has an equal chance of drawing either 3 or 6, rather than
the "ideal card deck" 75% to 25% probability. (It also may take a
number of random guesses before it gets either 3 or 6, thus the
inefficiency part...)
>How-To-Repeat:
Get bored while waiting for a compile to complete, play fish for
a while. Decide to look at code for explanation of "The computer
cheats only rarely." (see fish(6)). Notice card drawing routine
problems.
>Fix:
This fix replaces the old routines with a standard pre-shuffled
deck, using an equal-probability single-draw shuffle.
--- /var/src/games/fish/fish.c Thu Sep 23 13:18:26 1999
+++ /var/src/games/fishy/fish.c Tue Mar 21 18:05:48 2000
@@ -65,6 +65,7 @@
#define RANKS 13
#define HANDSIZE 7
#define CARDS 4
+#define TOTCARDS RANKS * CARDS
#define USER 1
#define COMPUTER 0
@@ -77,8 +78,9 @@
#define PRC(card) (void)printf(" %s", cards[card])
int promode;
-int asked[RANKS], comphand[RANKS], deck[RANKS];
+int asked[RANKS], comphand[RANKS], deck[TOTCARDS];
int userasked[RANKS], userhand[RANKS];
+int curcard = TOTCARDS;
void chkwinner __P((int, const int *));
int compmove __P((void));
@@ -170,7 +172,7 @@
continue;
if (buf[0] == '\n') {
(void)printf("%d cards in my hand, %d in the pool.\n",
- countcards(comphand), countcards(deck));
+ countcards(comphand), curcard);
(void)printf("My books:");
(void)countbooks(comphand);
continue;
@@ -270,9 +272,7 @@
{
int card;
- while (deck[card = nrandom(RANKS)] == 0);
- ++hand[card];
- --deck[card];
+ ++hand[card = deck[--curcard]];
if (player == USER || hand[card] == CARDS) {
printplayer(player);
(void)printf("drew %s", cards[card]);
@@ -423,19 +423,21 @@
void
init()
{
- int i, rank;
+ int i, j, temp;
- for (i = 0; i < RANKS; ++i)
- deck[i] = CARDS;
- for (i = 0; i < HANDSIZE; ++i) {
- while (!deck[rank = nrandom(RANKS)]);
- ++userhand[rank];
- --deck[rank];
+ for (i = 0; i < TOTCARDS; ++i)
+ deck[i] = i % RANKS;
+ for (i = 0; i < TOTCARDS - 1; ++i) {
+ j = nrandom(TOTCARDS-i);
+ if (j == 0)
+ continue;
+ temp = deck[i];
+ deck[i] = deck[i+j];
+ deck[i+j] = temp;
}
for (i = 0; i < HANDSIZE; ++i) {
- while (!deck[rank = nrandom(RANKS)]);
- ++comphand[rank];
- --deck[rank];
+ ++userhand[deck[--curcard]];
+ ++comphand[deck[--curcard]];
}
}
>Audit-Trail:
>Unformatted: