/************************************************/
/* ECE-1011 Spring 2003                         */
/* Section:......... 0                          */
/* Assignment:...... 5                          */
/* Programmer:...... BAHN, William L.           */
/* File Contents:... SOURCE CODE                */
/* Filename:........ s50_key                    */
/* Due Date:........ 10 MAR 03                  */
/* E-mail Address:.. wbahn@eas.uccs.edu         */
/************************************************/

/*****************************************************************************/
/*************************** MONTY HALL SIMULATOR ****************************/
/*****************************************************************************/

/*============== STANDARD LIBRARY INCLUDE FILES =============================*/

#include <stdio.h>  /* printf(), scanf(), fprintf(), fscanf() */
#include <stdlib.h> /* srand(), rand() */
#include <limits.h> /* LONG_MAX */

/*============== PROGRAMMER DEFINED CONSTANTS ===============================*/

/*****************************************************************************/
/* Version and Author Control                                                */
/*****************************************************************************/

#define PROGRAMTITLE     ("Monty Hall Simulator")
#define VERSION          (5)
#define REVISION         (1)
#define PROGRAMMER       ("BAHN, William")
#define PROGRAMMER_EMAIL ("wbahn@eas.uccs.edu")
#define LASTMODDATE      ("17 FEB 2003")

/*****************************************************************************/
/* Programmer Defined Constants                                              */
/*****************************************************************************/

#define TRUE  (1==1)
#define FALSE (!TRUE)
#define BLANKLINE printf("\n")

/*****************************************************************************/
/* Function Prototypes                                                       */
/*****************************************************************************/

void PrintHeader(void);
int rand_int(int min, int max);
long int GetNumberOfGamesToPlay(void);
int PlayMontyHall(int WillSwitch);
void DisplayResults(long int games, long int Switched,
						  long int SwitchedAndWon, long int StayedAndWon);
double rand_dbl(double min, double max);

/*****************************************************************************/
/* MAIN FUNCTION                                                             */
/*****************************************************************************/

int main(void)
{
	long int game, games;
	int WillSwitch, Winner;
	long int Switched, SwitchedAndWon, StayedAndWon;

	PrintHeader();
	games = GetNumberOfGamesToPlay();
	Switched = SwitchedAndWon = StayedAndWon = 0;

	if(games < 1) /* Manual Play */
	{
		while(PlayMontyHall(-1));
		BLANKLINE;
		printf("Thank you for playing!\n");
		return(-1);
	}

	for(game = 0; game < games; game++)
	{
		WillSwitch = rand_int(0,1);
		Winner = PlayMontyHall(WillSwitch);

		if(WillSwitch)
		{
			Switched++;
			if(Winner)
				SwitchedAndWon++;
		}
		else
		{
			if(Winner)
				StayedAndWon++;
		}
	}

	DisplayResults(games, Switched, SwitchedAndWon, StayedAndWon);

	return(0);
}

/*****************************************************************************/
/* SUPPORT FUNCTIONS                                                         */
/*****************************************************************************/

void PrintHeader(void)
{
	printf("===============================================================\n");
	printf("%s Version %i.%i\n", PROGRAMTITLE, VERSION, REVISION);
	printf("Programmer: %s\n", PROGRAMMER);
	printf("Date of Last Mod: %s\n", LASTMODDATE);
	printf("===============================================================\n");
	BLANKLINE;
	return;
}

int rand_int(int min, int max)
{
	/* "Hand Example" code : always returns truncated average of min & max */
	return( rand()%( (max-min) + 1 ) + min );
}

long int GetNumberOfGamesToPlay(void)
{
	long int games;
	unsigned int seed;

	printf("NUMBER OF GAMES\n");
	printf("A zero or negative number will invoke manual play.\n");
	printf("A number greater than zero will invoke automatic simulation.\n");
	printf("The maximum number of games is %li\n", LONG_MAX);
	printf("NOTE: Values greater than this invoke undefined behavior!\n");
	BLANKLINE;
	printf("Enter the number of games you wish played: ");
	scanf("%li", &games);
	BLANKLINE;
	printf("Enter the Random Number Seed: (0 to %u) ", UINT_MAX);
	scanf("%ui", &seed);
	srand(seed);

	/* "Hand Example" code : always returns 10,000 */
	return(games);
}

int PlayMontyHall(int WillSwitch)  /* Autoplay and Manual Play Version */
{
	int res;
	int autoplay;

	int PrizeDoor, UserDoor, OpenDoor, OtherDoor;
	/* Pick the Prize Door at Random */
	PrizeDoor = rand_int(1, 3);

	autoplay = (-1 != WillSwitch);

	/* Pick the User Door at Random */
	if(autoplay) /* AutoPlay */
	{
		UserDoor = rand_int(1, 3);
	}
	else /* Manual Play */
	{
		BLANKLINE;
		printf("Which Door would you like? (1 to 3)");
		scanf("%i", &UserDoor);
	}

	/* Open a non-Prize, non-User door at Random */
	do
	{
		OpenDoor = rand_int(1, 3);
	} while ( (OpenDoor == PrizeDoor) || (OpenDoor == UserDoor) );


	/* Set OtherDoor based on knowledge that it is non-User and not open */
	do
	{
		OtherDoor = rand_int(1, 3);
	} while ( (OtherDoor == OpenDoor) || (OtherDoor == UserDoor) );

	if(!autoplay) /* Manual Play */
	{
		BLANKLINE;
		printf("Door %i has a Goat.\n", OpenDoor);
		printf("You can keep door %i or switch to door %i.\n",
				  UserDoor, OtherDoor);
		BLANKLINE;
		printf("Would you like to switch? (Y/N (default is N) ): ");
		while('\n' == (res = getchar()) );
		switch(res)
		{
			case 'Y':
			case 'y': WillSwitch = TRUE; break;
			default : WillSwitch = FALSE; break;
		}
	}

	/* Act upon decision to switch doors */
	if(WillSwitch)
		UserDoor = OtherDoor;

	/* Return the Win status */

	if(!autoplay)
	{
		BLANKLINE;
		if(UserDoor == PrizeDoor)
		{
			printf("Congratulations! Door %i has a brand new CAR!\n,", UserDoor);
		}
		else
		{
			printf("So Sorry. But Door %i has a brand new GOAT!\n", UserDoor);
		}
		BLANKLINE;
	}

	if(autoplay) /* AutoPlay */
	{
		return( UserDoor == PrizeDoor );
	}
	else /* Manual Play */
	{
		printf("Would you like to play again? (Y/N (default is N) ): ");
		while('\n' == (res = getchar()) );
		switch(res)
		{
			case 'Y':
			case 'y': return(TRUE);
			default : return(FALSE);
		}
	}

}

void DisplayResults(long int games, long int Switched,
						  long int SwitchedAndWon, long int StayedAndWon)
{
	#define PASSCODE (31011)

	int passcode;

	BLANKLINE;
	printf("MONTY HALL RESULTS\n");
	printf("To see actual results, enter the passcode: ");
	scanf("%i", &passcode);

	BLANKLINE;
	if(PASSCODE == passcode)
	{
		printf("*** ACTUAL RESULTS ***\n");
	}
	else
	{
		printf("*** RANDOM RESULTS (so as not to reveal actual odds) ***\n");
		Switched = rand_dbl(0.0, (double) games);
		SwitchedAndWon = rand_dbl(0.0, (double) Switched);
		StayedAndWon = rand_dbl(0.0, (double) (games - Switched));
	}

	BLANKLINE;
	printf("DATA SUMMARY\n");
	printf("Total number of games:... \%li\n", games);
	printf("Times switched:.......... \%li\n", Switched);
	printf("Times switched and won:.. \%li\n", SwitchedAndWon);
	printf("Times stayed and won:.... \%li\n", StayedAndWon);
	BLANKLINE;
	printf("COMPUTED PROBABILITIES\n");
	printf("Probability of winning if always switch:.. %.2f%%\n",
			  100.0 * ((double) SwitchedAndWon / (double) Switched) );
	printf("Probability of winning if always stay:.... %.2f%%\n",
			  100.0 * ((double) StayedAndWon / (double) (games - Switched)) );

	return;
}

double rand_dbl(double min, double max)
{
	return ( ((double) rand()/(double) RAND_MAX)*(max-min) + min );
}