#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 door[3] = {0,0,0}; // The Doors (0,1,2) int choice = 0; // door initially chosen int show = 0; // door 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 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; // misc counters float kpc, spc; // percents for keep and switch srand(time(NULL)); // set starting point for generating pseudorandom #s if (!_isatty(_fileno(stdout))) // detect if stdout has been redirected { bRedir = 1; printf("© = car; • = goat; 1st digit = choice; 2nd digit = show; 3rd digit = switch\n"); } // 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("\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\n"); printf("Examples:\n"); printf(" C:>montyhall -> alternate keep & switch each of 2000 times\n"); printf(" C:>montyhall k -> 1000 keep followed by 1000 switch\n"); printf(" C:>montyhall s 20000 -> 10000 switch followed by 10000 keep\n"); printf(" C:>montyhall 2000000 -> alternate keep & switch 2 million times\n"); printf(" C:>montyhall ? -> print this message and exit.\n\n"); printf("If output is redirected to a file, the file contains additional info\n"); printf("and fewer running tallies are displayed.\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 on # of loops given { loop = atoi(argv[1]); // requested number of simulations to run } } // alternate with each simulation (default) if neither 's' or 'k' given // cmdline arg to set number of simulations to run (default is 2000) if (argc > 2 && isdigit(*argv[2])) { loop = atoi(argv[2]); // requested number of simulations to run } 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; // MAIN LOOP for (n=loop; n--; ) { for (i=3; --i >= 0; ) // clear all doors door[i] = 0; i = getrand(3); // get i as door# for car door[i] = 1; // set door[i] as car choice = getrand(3); // choose door i = getrand(2); // setup for opening a door with goat if (i) // start search for goat door to show from top { for (j=3; --j >= 0; ) { if (!door[j] && j != choice) // goat & not-choice? { show = j; // yes = show break; } } } else // search for goat door to show from bottom { for (j=-1; ++j < 3; ) { if (!door[j] && j != choice) // goat & not-choice? { show = j; // yes = show break; } } } if (!bSwitch) // if not switching, choice is final final = choice; else // else final is door not choice & not shown { for (j=-1; ++j < 3; ) { if (j != choice && j != show) { 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) // if redirecting, print details before print running tally { char c[4]; sprintf(c, "%d", final+1); // convert final into a char for print printf(det, door[0] ? '©' : '•', door[1] ? '©' : '•', door[2] ? '©' : '•', choice+1, show+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'); } }