#include #include #include #include #include #include #include #include using namespace std; //----------------------------A FANTASTICAL LOTTERY GAME BY THE AMAZING MIGUEL------------------------------ // -------------------------------------------------------------------------------------------------- // ------------------------COMES WITH FUNCTIONS AS STANDARD-------------------------- // -------------------------------------------------------- // ------------------------ /* This is a simple lottery game by Michael Brandon. It is made to demonstrate the use of arrays and functions. Key features include: -The ability to choose 1-10 lines per ticket -Dynamically allocating the memory for array storing the user's ticket, and deleting that array from memory before creating a new one when changing the length -The option of re-using the same numbers or creating a new ticket. Re-using does not delete the array and the player cannot re-use a ticket if their wallet does not contain enough money for that many lines. -Input goes to string first, then checks if it can convert into the integer variable it is needed for. This prevents the program breaking into an infinite loop if the user accidentally types a character into an integer. -Array checking for both the ticket (per line) and the balls (including the bonus ball), that prevent any duplicate numbers from happening when they should not, and that they are generated between specific values, defined by a single global variable, and as mentioned above, prevents characters from being input, and prevents the user or the machine creating a value greater or lower than the amount allowed, referencing a global variables that mean I can generate numbers between 1-49 as intended, or 1-500. These values are also used when requesting input from the player, so changing the range of valid numbers still outputs correct information to the player. -Bubble sort applied to each line on the players ticket, meaning that the player's numbers print in ascending order per line. -Very few global variables, and only ONE that is ever affected by the running of the program, makes it much easier to debug, and easy to edit the value of the globals to make the game easier or harder. -Sleep funtion at certain places to make it easier to follow the progress of the game and also to add tension. The ball generator also uses the random function to pause a random amount within a certain range to increase inpredictability. All pauses reference a single global variable, meaning I can scale or entierly remove all pauses in the game by editing a single value. -Compare function that compares the 6 numbers on each line with the random numbers and the bonus ball, and assigns a score to a score array, as long as the number of lines the player is playing with. 10 points are won for a normal match, plus 1 point for matching a bonus ball. So a line with two matches would score 20, and four number plus a bonus ball would score 41. These scores are simply read by a number of if statements, and adds the winnings, if any, together, and tells the user how much they won, before adding the winnings into their wallet. */ //chickity-check my globals yo const int BetLow (1); //minimum guess and ball value const int BetHigh (49); //maximum guess and ball value const char Pound = 156; //to use pound symbol in cout unsigned int Wallet (10); //Global wallet amount, only affected after user prints a whole ticket (removes £1 for each line) and when collecting winnings, if any // _________________________________________ const int Payout2 (1); //2 balls | const int Payout3 (10); //3 balls | const int Payout4 (100); //4 balls | const int Payout4B (500); //4 balls and bonus |===P-p-pick up your p-prizes!! const int Payout5 (2500); //5 balls | (this does not follow official const int Payout5B (190000); //5 balls and bonus | Lottery prizes, as you would const int Payout6 (4000000); //JACKPOT DING DING DING __| never win a thing otherwise!) const float pause (1000); //default time to pause, can be adjusted per pause using operators, default 1 second bool running = true; //flag used to end program //----------------------------------------ENTER NAME-------------------------------------------- string EnterName() { string input; cout << "Please enter your name:\n"; cin.clear(); cin >> input; return (input); } //----------------------------------------CHOOSE NUMBER OF LINES-------------------------------- int Ticket() { int Lines = 0; //set number of lines to default of 0 upon entering this function int flag = 1; //break loop when unflagged do //loop breaks when number is found to be valid and unchecks the flag { cout << "\n\nHow many lines would you like to play with? (1-10)\n"; string input = ""; cin.sync();//does nothing >< cin >> input; stringstream myStream(input); if(myStream >> Lines) { if(Lines < 1 || Lines > 10) //feedback to player if they pick less than 1 or more than 10 lines { cout << "Must be between 1 and 10!\n\n"; } else if(Lines > Wallet && Wallet > 1) //feedback if player cannot afford this many lines { cout << "You do not have enough money for this many lines! You can afford up to " << Wallet << " lines!\n\n"; } else if(Lines > Wallet && Wallet == 1) //as above, correcting pluralisation for just £1 { cout << "You do not have enough money for this many lines! You can only afford " << Wallet << " line!\n\n"; } else { flag = 0; } } else { cout << "Must be a valid number between 1 and 10!\n\n"; } } while ((Lines < 1 || Lines > 10 || Lines > Wallet) && (flag = 1)); return Lines; } //----------------------------------------CHOOSE SIX NUMBERS PER LINE, BUBBLE SORT, AND PRINT--- int Input(const int Lines, int **Guess) { cout << "\n\nPlease choose your lucky numbers: (" << BetLow << "-" << BetHigh << ")\n"; Sleep(pause / 2); for (int Line = 0; Line < Lines; Line++)//loop per line { cout << "Line " << Line + 1 << " of " << Lines << ":\n"; for(int n = 0; n < 6; n++)//loop per number on a line { bool duplicate = false;//flag for duplicates, will re-request input until this stays false do { string input = "0"; cout << n + 1 << ")\t"; cin >> input; //cin goes to input string first stringstream myStream(input); //puts input string into myStream of type stringstream if (myStream >> Guess[Line][n]) //if stringstream detects that myStream can go into the array as an int type variable... { //then loop continues as normal if (Guess[Line][n] < BetLow) //can't bet below 1 { cout <<"Too low, try again! (" << BetLow << "-" << BetHigh << ")\n\n"; Sleep(pause / 2); } else if (Guess[Line][n] > BetHigh) //can't bet over 49 { cout << "Too high, try again! (" << BetLow << "-" << BetHigh << ")\n\n"; Sleep(pause / 2); } if(n > 0)//checking for dupluicates, does not need to occur on first value { duplicate = false;//first set flag to false for(int count = 0; count < n; count++)//for each number on this line, upto the number before THIS one... { if(Guess[Line][n] == Guess[Line][count])//if This number matches checked number... { duplicate = true;//flag for re-entry is set to true cout << "You already have this number, please try again!\n\n"; Sleep(pause / 2); } } } } else //else, stringstream CAN'T put myStream into the array... { cout << "\nInvalid number, please try again\n\n";//when invalid, number will not be between the required values, so loop for this number will not break Sleep(pause / 2); } } while((Guess[Line][n] < BetLow || Guess[Line][n] > BetHigh) || (duplicate == true)); } } //--------------------------------BUBBLE SORT CODE------------------------------------- for(int Line = 0; Line < Lines; Line++)//for each line { bool swap = true;//flag, for detecting if a swap occured each iteration do { swap = false; //sets flag to false so loop only runs once, or until no swaps are detected. for (int sort = 0; sort < 5; sort++) { if(Guess[Line][sort] > Guess[Line][sort+1]) //if this number is greater than the next { int temp; temp = Guess[Line][sort+1]; //swap elements using temp data storage Guess[Line][sort+1] = Guess[Line][sort]; Guess[Line][sort] = temp; swap = true; //indicates that a swap occurred. } } } while(swap); } //------print ticket------- cout << "\n\nYou picked:\n"; Sleep(pause / 4); for (int Line = 0; Line < Lines; Line++) { for(int n = 0; n < 6; n++) { cout << "\t-" << Guess[Line][n] << "-"; } cout << endl; } Sleep(pause * 2); } //----------------------------------------RANDOM NUMBER GENERATOR------------------------------- void Generate(int Ball[], int &BonusBall) { Sleep(pause * 1); cout << "Lets get those balls rolling...\n\n\t"; srand ( time(NULL) );//sets random seed based on time bool duplicate = false;//flag for duplicates, provides same function as when used in Input //-----generate 6 random balls------ for(int n = 0; n < 6; n++) { Sleep(pause * (rand() % 2 + 1.5));//pause a random amount of time do { Ball[n] = rand() % BetHigh + BetLow; duplicate = false; if(n > 0)//check for duplicates except one first ball { for(int count = 0; count < n; count++) { if(Ball[n] == Ball[count]) { duplicate = true; } } } } while((Ball[n] < BetLow || Ball[n] > BetHigh) || (duplicate == true)); cout << "*" << Ball[n] << "*\t"; } do { BonusBall = rand() % BetHigh + BetLow;//generate bonus ball duplicate = false; for(int n = 0; n < 6; n++)//check bonus does not match any of the other balls { if(Ball[n] == BonusBall) { duplicate = true; } } } while(duplicate == true); Sleep(pause / 1.75); cout << "\n\t\t\t\tAnd the bonus is.....\t"; Sleep(pause * (rand() % 5 + 2));//longer random pause before printing bonus ball cout << "*" << BonusBall << "*\n\n"; } //----------------------------------------COMPARE RANDOM BALLS WITH GUESSES PER LINE------------ void Compare(int Lines, int **Guess, int Ball[], int BonusBall, int Matches[]) { for(int Line = 0; Line < Lines; Line++) { Matches[Line] = 0; //resets score per line to avoid winning on a line that you won on last round for(int n = 0; n < 6; n++) { if(Guess[Line][n] == BonusBall) { Matches[Line] = Matches[Line] + 1;//matching bonus ball scores 1 point } for(int b = 0; b < 6; b++) { if(Guess[Line][n] == Ball[b]) { Matches[Line] = Matches[Line] + 10;//matching regular ball scores 10 points } } } /* if(Matches[Line] > 0) //can print score for each winning line, useful for debugging but user doesnt know what the score means... { cout << "\nYou scored " << Matches[Line] << " on line " << Line + 1 << " of " << Lines << "!"; }*/ } } //----------------------------------------PAYOUT------------------------------------------------ void Payout(int Lines, int *Matches) { int Winnings = 0;//default winnings to 0 for(int Line = 0; Line < Lines; Line++)//score for each line { //score will be of double digit format, ie two balls will score 20, and four balls and bonus ball will score 41 if(Matches[Line] > 0) { if(Matches[Line] == 20 || Matches [Line] == 21)//2 matches (or 2 and bonus) { Winnings = Winnings + Payout2; } else if(Matches[Line] == 30 || Matches [Line] == 31)//3 matches (or 3 and bonus) { Winnings = Winnings + Payout3; } else if(Matches[Line] == 40)//4 matches { Winnings = Winnings + Payout4; } else if(Matches[Line] == 41)//4 matches and bonus ball { Winnings = Winnings + Payout4B; } else if(Matches[Line] == 50)//5 matches { Winnings = Winnings + Payout5; } else if(Matches[Line] == 51)//5 matches and bonus ball { Winnings = Winnings + Payout5B; } else if(Matches[Line] == 60)//6 matches == JACKPOT WINNAAAHHH { Winnings = Winnings + Payout6; } } } Sleep(pause * 1.5); if(Winnings != 0) { cout << "\n\nYou have won " << Pound << Winnings << "!! Congratulations!!\n\n"; Wallet = Wallet + Winnings; Sleep(pause * 2); cout << "You now have " << Pound << Wallet << " in your wallet to play with!\n\n"; } else if(Winnings == 0 && Wallet > 0) { cout << "\nSorry, you have not won this time.\n\n"; Sleep(pause * 2); cout << "You still have " << Pound << Wallet << " left in your wallet to play with.\n\n"; Sleep(pause); } } //----------------------------------------MAIN (LOOP FROM NUMBER OF LINES TO PAYOUT)------------------------------------------------------------------------- int main () { SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ), 11); //set text colour string Name = EnterName(); //start game by asking for player's name(calls EnterName and sets local Name variable to the value returned by the function) Sleep(pause / 2); cout << "\nWelcome, " << Name << "!\n\tYou have " << Pound << Wallet << " in your wallet to play with!\n\n"; Sleep(pause * 1.5); do //------------------------------------MAIN GAME LOOP--------------------------------------------- { int Lines = Ticket(); //calls function for player to choose how many lines they want on this ticket //Lines takes value returned from Ticket function, and is then passed to the following functions to //the line length and therefore how each function will operate. int **Guess = new int*[Lines]; //declares the 2D array in heap memory for(int i = 0; i < Lines; i++) //sets the size of the array based on user input Lines { Guess[i] = new int[6]; } Input(Lines, Guess);//calls the Input function so the user can set values, 6 numbers per number of lines int *Matches = new int[Lines];//declares array for winning score per line bool repeat = false;//declares and then sets repeat flag to false string input;//declares local input string, all cin data goes into this, then is checked if it can go into the int variable that needs it do//loop this if the user wants to re-use the same ticket { Wallet = Wallet - Lines; //subtract £1 for each line played Sleep(pause / 2); cout << "\nYou have " << Pound << Wallet << " left in your wallet.\n\n"; int Ball[6] = {0};//declare balls array and set to 0 int BonusBall = 0;//declare bonusball variable if(repeat == true) // Reprint ticket it repeat is detected { Sleep(pause); cout << "\nYour numbers are still:\n"; for (int Line = 0; Line < Lines; Line++) { for(int n = 0; n < 6; n++) { cout << "\t-" << Guess[Line][n] << "-"; } cout << endl; } Sleep(pause * 2); } Generate(Ball, BonusBall); //call the random ball generator to set values to Ball array and BonusBall Compare(Lines, Guess, Ball, BonusBall, Matches); //call the Compare function to check for matches and set score per line Payout(Lines, Matches);//call the Payout function to check score per line and total the winnings as needed. if(Wallet > 0 && Wallet >= Lines)//asks if player wants to reuse the same ticket, IF they can afford it { Sleep(pause * 1.5); bool valid = true; do { cout << "Would you like to play again with the same numbers? (Y/N)\n"; input = ""; cin >> input; if(input == "yes" || input == "Yes" || input == "y" || input == "Y" || input == "true" || input == "True" || input == "1") { repeat = true; valid = true;//accept answer, break loop, re using the same ticket } else if(input == "no" || input == "No" || input == "n" || input == "N" || input == "false" || input == "False" || input == "0") { repeat = false; valid = true;//accept answer, break loop without using same ticket } else { cout << "\nPlease answer with a yes or no, Y or N, true or false, or 1 or 0.\n\n"; valid = false; //do not accept invalid answers Sleep(pause); } } while(valid == false); } } while((repeat == true && Wallet > 0) && (Wallet > Lines)); delete Guess; //clear Guess array from memory if changing ticket size, to avoid memory leak delete Matches; //clear Matches array from memory if changing ticket size, to avoid memory leak //end game when out of money-------------- if(Wallet <= 0) { running = false; Sleep(pause / 2); cout << "\n\n\nYou ran out of money. Thanks for playing!\n\n"; Sleep(pause * 2); } } while(running==true); return 0; } /* I hope you enjoy playing my game and that you find my code interesting and informative. I believe I have written a very high standard of program, that is well structured, uses functions effectively, demonstrates knowledge of stack and heap memory and when and how to appropriately use them, as well as keeping in mind the actual mechanics of gameplay, such as the use of pauses to improve readability and excitement. I believe my code is now completely bug free, which took relatively little testing, as my functions made it extremely easy to find where and when something was broken. The only issue I have with my program, is that I cannot PREVENT a user inputting data into the cin input buffer and as such, whilst the game is printing the ticket, the player can input data and press enter during the pasues, and it will input into the next request for input, before the player even knows about it. The only way I can find to prevent this requires disabling ALL input, which, if I forget to ENABLE input, then the user cannot use their computer again short of using ctrl-alt-delete, or else simply take their keyboard away or tieing the user's hands behind their back, none of which are appropriate solutions. I have learned a great deal, considering that only a week ago, I only knew the basic fundamentals of declaring variables, performing equations and comparisons, and using input/output of information, as well as a limited understanding of loops. I look forward to learning more in the future, including visual programming, as well as applying my new knowledge and experience within scripting for pre existing game engines. -Michael Brandon */