#include #include #include static int aRolls[4][36][2]; /* cdecl is your friend :-) */ /* randomise an array of dice rolls. If it's an initial position, * ensure that array[0..29][0..1] doesn't have a double in it */ static void Randomize (int iTurn, int fInitial) { int i, j, swap; int save; for (i = 0; i < 36; ++i) { swap = random () % 36; for (j = 0; j < 2; ++j) { save = aRolls[iTurn][swap][j]; aRolls[iTurn][swap][j] = aRolls[iTurn][i][j]; aRolls[iTurn][i][j] = save; } } if (!fInitial) return; /* move all the doubles to the end */ for (i = 0, j = 30; i < 30; ++i) { while (aRolls[iTurn][i][0] == aRolls[iTurn][i][1]) { /* swap one of the last rolls to here, then check again */ save = aRolls[iTurn][j][0]; aRolls[iTurn][j][0] = aRolls[iTurn][i][0]; aRolls[iTurn][i][0] = save; save = aRolls[iTurn][j][1]; aRolls[iTurn][j][1] = aRolls[iTurn][i][1]; aRolls[iTurn][i][1] = save; ++j; } } } /* * return a roll. On calls during the first game, an array of rolls * is built for each turn. The array for opening rolls will be used * cyclicly forever. For the first 1080/1296 rolls, the second roll * will cycle through aRolls[2]. For the next 1080/1296 rolls, the * second roll will cycle through the same pattern rotated by one roll */ static int limits[2][4] = { { 36, 36 * 36, 36 * 36 * 36, 36 * 36 * 36 * 36 }, { 30, 36 * 36, 36 * 36 * 36, 36 * 36 * 36 * 36 } }; void QuasiRandomDice( int iTurn, int iGame, int fInitial, int *anDice) { int i; int j; int turn = (iTurn < 4) ? iTurn : 3; int limit = limits[fInitial][turn]; if (iTurn < 4) { if (iGame == 0) { /* iniitalise the array on the first game, first time through */ for (i = 0; i < 6; i++) { for (j = 0; j < 6; j++) { aRolls[iTurn][i * 6 + j][0] = i + 1; aRolls[iTurn][i * 6 + j][1] = j + 1; } } Randomize ( iTurn, fInitial && (iTurn == 0) ); } } if (turn == 0) { anDice[ 0 ] = aRolls[turn][iGame % limit][0]; anDice[ 1 ] = aRolls[0][iGame % limit][1]; return; } /* when we've done everything for lower number of turns, rotate * the dice for this one */ if ((iTurn < 4) && (iGame != 0) && ((iGame % limits[0][turn]) == 0)) { Randomize ( iTurn, 0 ); } if (iTurn < 4) { anDice[ 0 ] = aRolls[turn][(iGame + iGame / limit) % 36][0]; anDice[ 1 ] = aRolls[turn][(iGame + iGame / limit) % 36][1]; return; } /* we only deal with the first four rolls - hand out random(ish) dice */ anDice[ 0 ] = 1 + random () % 6; anDice[ 1 ] = 1 + random () % 6; } static void usage (char * program) { fprintf (stderr, "Usage: %s <0|1>\n" " trials = 1..4 to test 1..4 plies of full rollouts\n" " other values are exact counts\n" " optional flag 0/1 for Initial position\n", program); exit (1); } int main (int argc, char **argv) { int trials = 1296; int i, t; int iGame, iTurn; int fInitial = 0; int anDice[2]; switch (argc) { case 3: /* set fInitial from command line */ sscanf (argv[2], "%d", &fInitial); if ((fInitial < 0) || (fInitial > 1)) { usage (argv[0]); } /* fall through */ case 2: /* get number of full rollouts or no. of games */ sscanf (argv[1], "%d", &trials); if (trials < 1) { usage (argv[0]); } if (trials < 5) { t = 1; for (i = 0; i < trials; ++i) { t *= (fInitial && (i == 0)) ? 30 : 36; } trials = t; } break; case 1: break; default: usage (argv[0]); } srandom (1); while (1) { /* work out what the first four rolls of a game will be */ for (iTurn = 0; iTurn < 4; ++iTurn) { QuasiRandomDice( iTurn, iGame, fInitial, anDice); /* ensure printout shows low, high */ if (anDice[0] > anDice[1]) { i = anDice[1]; anDice[1] = anDice[0]; anDice[0] = i; } /* make it easy to grep out all the nth moves from the results */ printf ("%6d %6d %d%d\n", iTurn, iGame, anDice[0], anDice[1]); } ++iGame; if (--trials <= 0) break; } return 0; }