#include "stdio.h" #include "stdlib.h" #include "string.h" #include "stdlib.h" #include "time.h" #include int bSwitch = 0; // Switch == 1; No Switch == 0 int bAlter = 1; // Alternate each simulation between Keep & Switch int bRedir = 0; // output redirected: 0=no, 1=yes int bNoAKS = 0; // 1 = 1st arg is nbr simulations, not a,k,s int door[100] = {0,0,0};// The Doors (0,1,2,...) int choice = 0; // door initially chosen int show[100] = {0,0,0};// door(s) shown int final = 0; // final door after offer to switch int keepitW = 0; // # wins when keepit int keepitL = 0; // # losses when keepit int switchW = 0; // # wins when switch int switchL = 0; // # losses when switch int total = 0; // running total of simulations done int keepittotal = 0; // running total of simulations done with keepit int switchtotal = 0; // running total of simulations done with switch int loop = 2000; // # times to run simulation int halfloop; // loop/2 int n; // loop countdown counter fpos_t pos; // used for detecting output redirection char * winner; // string identifying winning move char det[] = "%c %c %c %d %d %c %c "; // used only if output redirected char fmt[] = "%4d, Keep: %4d=Win, %4d=Lose, Win%%=%4.1f%%. \ Switch: %4d=Win, %4d=Lose, Win%%=%4.1f%%. %s %d > %c"; int nbrdoors = 3; int nbr2open = 1; int getrand(int i) // return a random number modulo i { int r; r = rand(); return r%i; } int main(argc, argv) int argc; char *argv[]; { int i, j, k; // misc counters float kpc, spc; // percents for keep and switch srand(time(NULL)); // set starting point for generating pseudorandom #s // cmdline arg for help? if (argc > 1 && (*argv[1] == '/' || *argv[1] == '-')) // ignore / and - strcpy(argv[1], &argv[1][1]); if (argc > 1 && *argv[1] == '?') { printf("This program runs simulations of the Monty Hall Paradox,\n"); printf("for info, see https://en.wikipedia.org/wiki/Monty_Hall_problem\n"); printf("Half of the simulations are Keep 1st choice, half are Switch.\n"); printf("Output is a running tally of Wins and Loses for both Keep and Switch.\n\n"); printf("Usage: %s {a|k|s|?} {#simulations}\n", argv[0]); printf("\twhere a = alternate between keep & switch each time (default)\n"); printf("\t k = run all keep simulations 1st, then all switch\n"); printf("\t s = run all switch simulations 1st, then all keep\n"); printf("\t ? = print this message and exit.\n"); printf("\twhere #simulations >= 200 and <= 10 million (default=2000)\n"); printf("\t with half Keep original choice and half Switch choice.\n"); printf("\tNote: { } are optional args and | means choose only one.\n"); printf("Examples:\n"); printf(" C:>%s -> alternate keep & switch each of 2000 times\n", argv[0]); printf(" C:>%s k -> 1000 keep followed by 1000 switch\n", argv[0]); printf(" C:>%s s 20000 -> 10000 switch followed by 10000 keep\n", argv[0]); printf(" C:>%s 2000000 -> alternate keep & switch 2 million times\n", argv[0]); printf("Program also works with more than 3 doors\n"); printf("Usage: %s {a|k|s|?} [#simulations] [#doors] {#show}\n", argv[0]); printf("\twhere [ ] = required, 3 <= #doors <= 100, 1 <= #show <= #doors-2\n"); printf("Examples:\n"); printf(" C:>%s a 2000 4 2 -> 1000 each keep/switch, 4 doors, show 2\n", argv[0]); printf(" C:>%s 9000 9 -> 4500 each keep/switch, 9 doors, show 1\n\n", argv[0]); printf("If output is redirected to a file, fewer running tallies are displayed,\n"); printf("and if only 3 doors, the file contains additional info.\n"); printf("(However redirecting to nul produces no output at all.)\n"); exit(0); } // cmdline arg to determine alternate or all keep 1st or all switch 1st if (argc > 1) { if (*argv[1] == 's') { bSwitch = 1; // do switch fist bAlter = 0; } else if (*argv[1] == 'k') { bSwitch = 0; // do keep first bAlter = 0; } else if (isdigit(*argv[1])) // catch case where only # of loops given { loop = atoi(argv[1]); // requested number of simulations to run bNoAKS = 1; // no k,s,a given } } // alternate with each simulation (default) if neither 's' or 'k' given // cmdline arg to set number of simulations to run (default is 2000) if (!bNoAKS && argc > 2 && isdigit(*argv[2])) { loop = atoi(argv[2]); // requested number of simulations to run } n = 3 - bNoAKS; if (argc > n && isdigit(*argv[n])) { nbrdoors = atoi(argv[n]); // requested number of doors if (nbrdoors > 100) // make sure 3 <= # doors <= 100 nbrdoors = 100; else if (nbrdoors < 3) nbrdoors = 3; } n = 4 - bNoAKS; if (argc > n && isdigit(*argv[n])) { nbr2open = atoi(argv[n]); // requested number of doors to open if (nbr2open > nbrdoors-2) // make sure 1 <= # to open <= # doors - 2 nbr2open = nbrdoors-2; else if (nbr2open < 1) nbr2open = 1; } halfloop = loop/2; // needed to know when to switch keep/switch loop = halfloop*2; // force even number of loops if (loop < 200) // make sure # is large enough to be significant loop = 200; else if (loop > 10000000) // prevent huge number of unnecessary loops loop = 10000000; if (!_isatty(_fileno(stdout))) // detect if stdout has been redirected { bRedir = 1; // yes - redirected output if (nbrdoors == 3) // 3 doors gets special extra output header printf("© = car; • = goat; 1st digit = choice; 2nd digit = show; 3rd digit = switch\n"); } if (argc > 3-bNoAKS) // if # doors given, output # of sims, doors, shows { printf("%d simulations, %d doors, %d to be opened\n", loop, nbrdoors, nbr2open); if (bRedir) // if redirected output, also print to stderr fprintf(stderr, "%d simulations, %d doors, %d to be opened\n", loop, nbrdoors, nbr2open); } // MAIN LOOP for (n=loop; n--; ) { for (i=nbrdoors; --i >= 0; ) // clear all doors & shows { door[i] = show[i] = 0; } i = getrand(nbrdoors); // get i as door# for car door[i] = 1; // set door[i] as car choice = getrand(nbrdoors); // choose door i = getrand(2); // setup for opening a door with goat k = nbr2open; if (i) // start search for goat door to show from top { for (j=nbrdoors; --j >= 0; ) { if (!door[j] && j != choice) // goat & not-choice? { show[j] = 1; // yes = show if (!--k) break; } } } else // search for goat door to show from bottom { for (j=-1; ++j < nbrdoors; ) { if (!door[j] && j != choice) // goat & not-choice? { show[j] = 1; // yes = show if (!--k) break; } } } if (!bSwitch) // if not switching, choice is final final = choice; else // else final is door not choice & not shown { for (j=-1; ++j < nbrdoors; ) { if (j != choice && !show[j]) { final = j; break; } } } if (door[final]) // final choice door have car? { if (!bSwitch) // yes, tally keepitW++; else switchW++; } else // final choice door has goat { if (!bSwitch) // yes, tally keepitL++; else switchL++; } if (bSwitch) // increment switch total if switching ++switchtotal; else // increment keep total if not switching ++keepittotal; if (++total == halfloop) // incr total & chk to switch keep/switch bSwitch ^= 1; // yes 1/2-way done, toggle switch flag else if (bAlter) // alternate each run between keep & switch? bSwitch ^= 1; // yes, then always toggle switch flag // print intermediate results if (keepitW < switchW) winner = "Switch"; else if (keepitW > switchW) winner = "Keep"; else winner = "Tie"; kpc = keepittotal ? keepitW*(float)100/keepittotal : 0; spc = switchtotal ? switchW*(float)100/switchtotal : 0; if (bRedir && nbrdoors==3) // if redirecting and are only 3 doors, { // print details before print running tally char c[4]; sprintf(c, "%d", final+1); // convert final into a char for print for (j=-1; ++j < nbrdoors; ) { if (show[j]) break; } printf(det, door[0] ? '©' : '•', door[1] ? '©' : '•', door[2] ? '©' : '•', choice+1, j+1, choice != final ? c[0] : ' ', door[final] ? 'W' : 'L'); } // print running tally printf(fmt, total, keepitW, keepitL, kpc, switchW, switchL, spc, winner, abs(switchW-keepitW), '\r'); // if redirect, print current tally to stderr every 65,535 simulations if (bRedir && (total & 0xFFFF) == 0) fprintf(stderr, fmt, total, keepitW, keepitL, kpc, switchW, switchL, spc, winner, abs(switchW-keepitW), '\r'); } // end of main loop // print final results kpc = keepitW*(float)200/total; spc = switchW*(float)200/total; printf(fmt, total, keepitW, keepitL, kpc, switchW, switchL, spc, winner, abs(switchW-keepitW), '\n'); if (bRedir) // if redirect, print final tally to stderr { fprintf(stderr, "\rOutput was redirected. Final numbers are: \n"); fprintf(stderr, fmt, total, keepitW, keepitL, kpc, switchW, switchL, spc, winner, abs(switchW-keepitW), '\n'); } }