Multi-game multiplayer arcade gaming system meant for the red X when playing Super Tic-Tac-Toe.
Dependencies: uLCD_4DGL_SE PinDetect SDFileSystem mbed wave_player
Diff: Simon.h
- Revision:
- 2:d35fde2d82cd
diff -r 2a7e2f5aeda4 -r d35fde2d82cd Simon.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Simon.h Fri Dec 04 23:03:08 2015 +0000 @@ -0,0 +1,994 @@ +/****************************************************** + * This header program declares all the functions and + * variables used by one of the players in Simon. + ******************************************************/ + + +#define E3 "/sd/wavfiles/trumpet_E3.wav" +#define A3 "/sd/wavfiles/trumpet_A3.wav" +#define C4 "/sd/wavfiles/trumpet_Cs.wav" +#define E4 "/sd/wavfiles/trumpet_E4.wav" +#define BUZZER "/sd/wavfiles/BUZZER.wav" +#define DING "/sd/wavfiles/DING.wav" +#define BOMB "/sd/wavfiles/bomb.wav" +#define WIN "/sd/win.wav" +#define EASY 1 +#define NORMAL 2 +#define HEROIC 3 +#define LEGENDARY 4 +#define MAXLENGTH 7 + + +// Simon Says class +class Simon { + public: + // Simon Says constructor + Simon(AnalogIn &noise, DigitalOut &reset, PinDetect &button1, PinDetect &button2, PinDetect &button3, PinDetect &button4, SDFileSystem &sd, Serial &XBee, uLCD_4DGL &uLCD, + wave_player &waver) : noise(noise), reset(reset), button1(button1), button2(button2), button3(button3), button4(button4), sd(sd), XBee(XBee), uLCD(uLCD), waver(waver) { + // Maximize the uLCD baud rate + uLCD.baudrate(MAXBAUDRATE); + + // Set up interrupts + button1.mode(PullUp); + button2.mode(PullUp); + button3.mode(PullUp); + button4.mode(PullUp); + wait(0.1); + button1.attach_deasserted(this, &Simon::button1Hit); + button2.attach_deasserted(this, &Simon::button2Hit); + button3.attach_deasserted(this, &Simon::button3Hit); + button4.attach_deasserted(this, &Simon::button4Hit); + wait(0.1); + button1.setSampleFrequency(); + button2.setSampleFrequency(); + button3.setSampleFrequency(); + button4.setSampleFrequency(); + wait(0.1); + + // Set up XBee + reset = 0; + wait(0.001); + reset = 1; + wait(0.001); + + oneHit = false; + twoHit = false; + threeHit = false; + fourHit = false; + + resetSequence(sequence, MAXLENGTH); + resetSequence(playerSequence, MAXLENGTH); + + otherPlayerWin = false; + } + + // Simulate the entire game + void playSimon() { + displayInstructions(); + selectDifficulty(); + countdown(); + playGame(); + gameOver(); + } + + + private: + AnalogIn &noise; + DigitalOut &reset; + PinDetect &button1; + PinDetect &button2; + PinDetect &button3; + PinDetect &button4; + SDFileSystem &sd; + Serial &XBee; + uLCD_4DGL &uLCD; + wave_player &waver; + volatile bool oneHit; + volatile bool twoHit; + volatile bool threeHit; + volatile bool fourHit; + int difficulty; + int sequence[MAXLENGTH]; + int playerSequence[MAXLENGTH]; + bool otherPlayerWin; + + // Color the background of one of the four corner + void drawBack(int position, int color) { + int x11, x12, x21, x22, y11, y12, y21, y22; + + switch (position) { + case 3: + x11 = 64; + x12 = 127; + x21 = 85; + x22 = 127; + y11 = 85; + y12 = 127; + y21 = 64; + y22 = 84; + break; + case 2: + x11 = 0; + x12 = 63; + x21 = 0; + x22 = 42; + y11 = 85; + y12 = 127; + y21 = 64; + y22 = 84; + break; + case 1: + x11 = 0; + x12 = 63; + x21 = 0; + x22 = 42; + y11 = 0; + y12 = 42; + y21 = 43; + y22 = 63; + break; + default: + x11 = 64; + x12 = 127; + x21 = 85; + x22 = 127; + y11 = 0; + y12 = 42; + y21 = 43; + y22 = 63; + } + + uLCD.filled_rectangle(x11, y11, x12, y12, color); + uLCD.filled_rectangle(x21, y21, x22, y22, color); + } + + // Color the foreground of one of the four corners + void drawFore(int position, int color) { + int x11, x12, x21, x22, y11, y12, y21, y22; + + switch (position) { + case 3: + x11 = 68; + x12 = 123; + x21 = 89; + x22 = 123; + y11 = 89; + y12 = 123; + y21 = 68; + y22 = 89; + break; + case 2: + x11 = 4; + x12 = 59; + x21 = 4; + x22 = 38; + y11 = 89; + y12 = 123; + y21 = 68; + y22 = 89; + break; + case 1: + x11 = 4; + x12 = 59; + x21 = 4; + x22 = 38; + y11 = 4; + y12 = 38; + y21 = 39; + y22 = 59; + break; + default: + x11 = 68; + x12 = 123; + x21 = 89; + x22 = 123; + y11 = 4; + y12 = 38; + y21 = 39; + y22 = 59; + } + + uLCD.filled_rectangle(x11, y11, x12, y12, color); + uLCD.filled_rectangle(x21, y21, x22, y22, color); + } + + // Print a number in the middle of the screen + void drawNum(int i) { + uLCD.text_width(3); + uLCD.text_height(3); + uLCD.color(BLACK); + uLCD.locate(2, 2); + uLCD.printf("%2D", i); + } + + // Create a random sequence + void createSequence(int *seq, int length) { + // Seed using noise from analog pin + srand((int)(noise * 50000 / 43)); + + for (int i = 0; i < length; i++) { + seq[i] = rand() % 4; + } + + for (int i = length; i < MAXLENGTH; i++) { + seq[i] = -1; + } + } + + // Reset the hits to false + void resetHits() { + oneHit = false; + twoHit = false; + threeHit = false; + fourHit = false; + } + + // Determine if all hits are false + bool noHits() { + return ((oneHit == false) && (twoHit == false) && (threeHit == false) && (fourHit == false)); + } + + // Wait for player input to go to next page + void nextPage() { + resetHits(); + + while (noHits() == true) { + } + + uLCD.cls(); + resetHits(); + } + + // Push button 1 interrupt routine + void button1Hit() { + oneHit = true; + } + + // Push button 2 interrupt routine + void button2Hit() { + twoHit = true; + } + + // Push button 3 interrupt routine + void button3Hit() { + threeHit = true; + } + + // Push button 4 interrupt routine + void button4Hit() { + fourHit = true; + } + + // Determine whether the player wants to view instructions + bool viewInstructions() { + bool viewInstructions = false; + + resetHits(); + + // Wait for pb1 or pb2 to be pressed + while ((oneHit == false) && (twoHit == false)) { + wait(1); + + // View instructions + if (oneHit == true) { + uLCD.cls(); + viewInstructions = true; + // Skip instructions + } else if (twoHit == true) { + uLCD.cls(); + viewInstructions = false; + } else { + resetHits(); + } + } + + return viewInstructions; + } + + // Play the sequence according to the difficulty + void playSequence(int *sequence) { + // Interval between sequence elements + float interval; + + // Set interval based on difficulty + if (difficulty == EASY) { + interval = 1.5f; + } else { + interval = 1.0f; + } + + // On Easy or Normal difficulty + if (difficulty == EASY || difficulty == NORMAL) { + int i = 0; + + // Loop through the sequence + while (i < MAXLENGTH && sequence[i] != -1) { + // Display position, color, and play sound at corresponding intervals + if (sequence[i] == 0) { + drawFore(0, RED); + playSound(A3); + wait(interval - 0.25); + drawBack(0, WHITE); + wait(0.25); + } else if (sequence[i] == 1) { + drawFore(1, GREEN); + playSound(E3); + wait(interval - 0.25); + drawBack(1, WHITE); + wait(0.25); + } else if (sequence[i] == 2) { + drawFore(2, YELLOW); + playSound(C4); + wait(interval - 0.25); + drawBack(2, WHITE); + wait(0.25); + } else { + drawFore(3, BLUE); + playSound(E4); + wait(interval - 0.25); + drawBack(3, WHITE); + wait(0.25); + } + + i++; + } + // On Heroic difficulty + } else if (difficulty == HEROIC) { + int i = 0; + + // Loop through the sequence + while (i < MAXLENGTH && sequence[i] != -1) { + // Display color with random position and sound at 1.0-second intervals + if (sequence[i] == 0) { + int position = rand() % 4; + int sound = rand() % 4; + drawFore(position, RED); + + if (sound == 0) { + playSound(E3); + } else if (sound == 1) { + playSound(A3); + } else if (sound == 2) { + playSound(C4); + } else { + playSound(E4); + } + + wait(interval - 0.25); + drawBack(position, WHITE); + wait(0.25); + } else if (sequence[i] == 1) { + int position = rand() % 4; + int sound = rand() % 4; + drawFore(position, GREEN); + + if (sound == 0) { + playSound(E3); + } else if (sound == 1) { + playSound(A3); + } else if (sound == 2) { + playSound(C4); + } else { + playSound(E4); + } + + wait(interval - 0.25); + drawBack(position, WHITE); + wait(0.25); + } else if (sequence[i] == 2) { + int position = rand() % 4; + int sound = rand() % 4; + drawFore(position, YELLOW); + + if (sound == 0) { + playSound(E3); + } else if (sound == 1) { + playSound(A3); + } else if (sound == 2) { + playSound(C4); + } else { + playSound(E4); + } + + wait(interval - 0.25); + drawBack(position, WHITE); + wait(0.25); + } else { + int position = rand() % 4; + int sound = rand() % 4; + drawFore(position, BLUE); + + if (sound == 0) { + playSound(E3); + } else if (sound == 1) { + playSound(A3); + } else if (sound == 2) { + playSound(C4); + } else { + playSound(E4); + } + + wait(interval - 0.25); + drawBack(position, WHITE); + wait(0.25); + } + + i++; + } + // On Legendary difficulty + } else { + int i = 0; + + // Loop through the sequence + while (i < MAXLENGTH && sequence[i] != -1) { + // Play sound with random color and position at 1.0-second intervals + if (sequence[i] == 0) { + int position = rand() % 4; + int color = rand() % 4; + + if (color == 0) { + drawFore(position, RED); + } else if (color == 1) { + drawFore(position, GREEN); + } else if (color == 2) { + drawFore(position, YELLOW); + } else { + drawFore(position, BLUE); + } + + playSound(A3); + wait(interval - 0.25); + drawBack(position, WHITE); + wait(0.25); + } else if (sequence[i] == 1) { + int position = rand() % 4; + int color = rand() % 4; + + if (color == 0) { + drawFore(position, RED); + } else if (color == 1) { + drawFore(position, GREEN); + } else if (color == 2) { + drawFore(position, YELLOW); + } else { + drawFore(position, BLUE); + } + + playSound(E3); + wait(interval - 0.25); + drawBack(position, WHITE); + wait(0.25); + } else if (sequence[i] == 2) { + int position = rand() % 4; + int color = rand() % 4; + + if (color == 0) { + drawFore(position, RED); + } else if (color == 1) { + drawFore(position, GREEN); + } else if (color == 2) { + drawFore(position, YELLOW); + } else { + drawFore(position, BLUE); + } + + playSound(C4); + wait(interval - 0.25); + drawBack(position, WHITE); + wait(0.25); + } else { + int position = rand() % 4; + int color = rand() % 4; + + if (color == 0) { + drawFore(position, RED); + } else if (color == 1) { + drawFore(position, GREEN); + } else if (color == 2) { + drawFore(position, YELLOW); + } else { + drawFore(position, BLUE); + } + + playSound(E4); + wait(interval - 0.25); + drawBack(position, WHITE); + wait(0.25); + } + + i++; + } + } + } + + // Play a sound file + void playSound(char *wav) { + // Open sound file + FILE *wave_file; + wave_file = fopen(wav, "r"); + + // Play wav file + waver.play(wave_file); + + // Close wav file + fclose(wave_file); + } + + // Reset the values in the sequence + void resetSequence(int *sequence, int length) { + for (int i = 0; i < length; i++) { + sequence[i] = -1; + } + } + + // Display instructions + void displayInstructions() { + uLCD.printf("Hello, and welcometo a game of\nmultiplayer Simon."); + uLCD.printf("First player to "); + uLCD.printf("reach %d points ", MAXLENGTH); + uLCD.printf("wins!\n\n"); + uLCD.printf("Press pb1 to view instructions or\npb2 to skip to\ndifficulty select-ion."); + + // If player chooses to view instructions + if (viewInstructions() == true) { + // Gameplay instructions + uLCD.printf("Sequences will be-gin with only one element. The numb-er of elements\n"); + uLCD.printf("increases by one\nupon earning a po-int, and vise ver-sa. "); + uLCD.printf("Remember, you must correctly getALL the values in a "); + uLCD.printf("sequence to earna point.\n\n"); + uLCD.printf("Press any button\nto continue."); + + nextPage(); + + uLCD.printf("Each push button\nhas its own uniqueposition, color,\nand sound.\n\n"); + uLCD.printf("Press any button\nto continue."); + + nextPage(); + + // Push button 1 + uLCD.printf("pb1: top right,\nred, note A3\n\n"); + uLCD.printf("Press pb1 for a\ndemonstration."); + + while (oneHit == false) { + } + + uLCD.background_color(WHITE); + uLCD.cls(); + wait(0.5); + + for (int i = 0; i < 5; i++) { + drawFore(0, RED); + playSound(A3); + wait(1); + drawBack(0, WHITE); + wait(0.5); + } + + uLCD.background_color(BLACK); + uLCD.cls(); + uLCD.printf("pb1: top right,\nred, note A3\n\n"); + uLCD.printf("Press any button\nto continue."); + + nextPage(); + + // Push button 2 + uLCD.printf("pb2: top left, gr-een, note E3\n\n"); + uLCD.printf("Press pb2 for a\ndemonstration."); + + while (twoHit == false) { + } + + uLCD.background_color(WHITE); + uLCD.cls(); + wait(0.5); + + for (int i = 0; i < 5; i++) { + drawFore(1, GREEN); + playSound(E3); + wait(1); + drawBack(1, WHITE); + wait(0.5); + } + + uLCD.background_color(BLACK); + uLCD.cls(); + uLCD.printf("pb2: top left, gr-een, note E3\n\n"); + uLCD.printf("Press any button\nto continue."); + + nextPage(); + + // Push button 3 + uLCD.printf("pb3: bottom left,\nyellow, note C4\n\n"); + uLCD.printf("Press pb3 for a\ndemonstration."); + + while (threeHit == false) { + } + + uLCD.background_color(WHITE); + uLCD.cls(); + wait(0.5); + + for (int i = 0; i < 5; i++) { + drawFore(2, YELLOW); + playSound(C4); + wait(1); + drawBack(2, WHITE); + wait(0.5); + } + + uLCD.background_color(BLACK); + uLCD.cls(); + uLCD.printf("pb3: bottom left,\nyellow, note C4\n\n"); + uLCD.printf("Press any button\nto continue."); + + nextPage(); + + // Push button 4 + uLCD.printf("pb4: bottom right,blue, note E4\n\n"); + uLCD.printf("Press pb4 for a\ndemonstration."); + + while (fourHit == false) { + } + + uLCD.background_color(WHITE); + uLCD.cls(); + wait(0.5); + + for (int i = 0; i < 5; i++) { + drawFore(3, BLUE); + playSound(E4); + wait(1); + drawBack(3, WHITE); + wait(0.5); + } + + uLCD.background_color(BLACK); + uLCD.cls(); + uLCD.printf("pb4: bottom right,blue, note E4\n\n"); + uLCD.printf("Press any button\nto continue."); + + nextPage(); + + uLCD.printf("There are 4 diffi-culties to choose from:\n\n"); + uLCD.printf("Easy, Normal,\nHeroic, and\nLegendary.\n\n"); + uLCD.printf("Press any button\nto continue."); + + nextPage(); + + // Different difficulties + uLCD.printf("Easy difficulty:\n\nThe timing betweenthe values of a\n"); + uLCD.printf("sequence is kept\nat constant 1.5-\nsecond intervals.\n\n"); + uLCD.printf("Press any button\nto continue."); + + nextPage(); + + uLCD.printf("Normal difficulty:\nThe timing betweenthe values of a\n"); + uLCD.printf("sequence is kept\nat constant 1.0-\nsecond intervals.\n\n"); + uLCD.printf("Press any button\nto continue."); + + nextPage(); + + uLCD.printf("Heroic difficulty:\nYou must match thepush button to the"); + uLCD.printf("right COLOR that\nis displayed at a random position\nwith a "); + uLCD.printf("random sou-nd. Timing betweenvalues is 1.0 sec-onds.\n\n"); + uLCD.printf("Press any button\nto continue."); + + nextPage(); + + uLCD.printf("Legendary\ndifficulty:\n\nYou must match thepush button to the"); + uLCD.printf("right SOUND that\nis displayed at a random position\nwith a "); + uLCD.printf("random col-or. Timing betweenvalues is 1.0 sec-onds.\n\n"); + uLCD.printf("Press any button\nto continue."); + + nextPage(); + } + } + + // Select difficulty + void selectDifficulty() { + difficultySelection: + uLCD.cls(); + + uLCD.printf("Select difficulty:\npb1: Easy\npb2: Normal\npb3: Heroic\npb4: Legendary"); + + resetHits(); + + while (noHits() == true) { + wait(1); + + if (oneHit == true) { + difficulty = EASY; + } else if (twoHit == true) { + difficulty = NORMAL; + } else if (threeHit == true) { + difficulty = HEROIC; + } else if (fourHit == true) { + difficulty = LEGENDARY; + } else { + resetHits(); + } + } + + XBee.putc(difficulty); + + char otherDifficulty = (char)(-1); + bool print = true; + + while (otherDifficulty == (char)(-1)) { + if (XBee.readable() == true) { + otherDifficulty = XBee.getc(); + print = false; + } + + if (print == true) { + uLCD.cls(); + uLCD.printf("Waiting for other player..."); + print = false; + } + } + + uLCD.cls(); + + if (otherDifficulty != difficulty) { + uLCD.cls(); + uLCD.printf("The other player "); + uLCD.printf("selected another "); + uLCD.printf("difficulty. Please"); + uLCD.printf("select again. "); + wait(3); + uLCD.cls(); + goto difficultySelection; + } + + uLCD.cls(); + + if (difficulty == EASY) { + uLCD.printf("You are playing onEasy difficulty.\n\n"); + } else if (difficulty == NORMAL) { + uLCD.printf("You are playing onNormal difficulty.\n"); + } else if (difficulty == HEROIC) { + uLCD.printf("You are playing onHeroic difficulty.\n"); + } else { + uLCD.printf("You are playing onLegendary\ndifficulty.\n\n"); + } + + uLCD.printf("Starting the\ngame..."); + wait(1.5); + } + + // Countdown to start the game + void countdown() { + uLCD.filled_rectangle(0, 0, 127, 127, WHITE); + uLCD.textbackground_color(WHITE); + uLCD.background_color(WHITE); + uLCD.cls(); + + for (int i = 3; i > 0; i--) { + drawNum(i); + wait(1); + } + } + + // Play the game + void playGame() { + // Initialize the score to be 0 + int score = 0; + + // Loop through the game + do { + // Display score + drawNum(score); + // Create a sequence + createSequence(sequence, score + 1); + // Play sequence + playSequence(sequence); + + resetHits(); + + // Loop through the player sequence + for (int i = 0; i < score + 1; i++) { + while (noHits() == true) { + } + + // Track player inputs + if (oneHit == true) { + playerSequence[i] = 0; + + // On Easy difficulty + if (difficulty == EASY) { + // Display position, color, and play sound + drawFore(0, RED); + playSound(A3); + drawBack(0, WHITE); + // On Normal difficulty + } else if (difficulty == NORMAL) { + // Display position, color, and play sound + drawFore(0, RED); + playSound(A3); + drawBack(0, WHITE); + // On Heroic difficulty + } else if (difficulty == HEROIC) { + // Display color + drawFore(0, RED); + drawFore(1, RED); + drawFore(2, RED); + drawFore(3, RED); + wait(0.5); + drawBack(0, WHITE); + drawBack(1, WHITE); + drawBack(2, WHITE); + drawBack(3, WHITE); + // On Legendary difficulty + } else { + // Play sound + playSound(A3); + } + } else if (twoHit == true) { + playerSequence[i] = 1; + + // On Easy difficulty + if (difficulty == EASY) { + // Display position, color, and play sound + drawFore(1, GREEN); + playSound(E3); + drawBack(1, WHITE); + // On Normal difficulty + } else if (difficulty == NORMAL) { + // Display position, color, and play sound + drawFore(1, GREEN); + playSound(E3); + drawBack(1, WHITE); + // On Heroic difficulty + } else if (difficulty == HEROIC) { + // Display color + drawFore(0, GREEN); + drawFore(1, GREEN); + drawFore(2, GREEN); + drawFore(3, GREEN); + wait(0.5); + drawBack(0, WHITE); + drawBack(1, WHITE); + drawBack(2, WHITE); + drawBack(3, WHITE); + // On Legendary difficulty + } else { + // Play sound + playSound(E3); + } + } else if (threeHit == true) { + playerSequence[i] = 2; + + // On Easy difficulty + if (difficulty == EASY) { + // Display position, color, and play sound + drawFore(2, YELLOW); + playSound(C4); + drawBack(2, WHITE); + // On Normal difficulty + } else if (difficulty == NORMAL) { + // Display position, color, and play sound + drawFore(2, YELLOW); + playSound(C4); + drawBack(2, WHITE); + // On Heroic difficulty + } else if (difficulty == HEROIC) { + drawFore(0, YELLOW); + drawFore(1, YELLOW); + drawFore(2, YELLOW); + drawFore(3, YELLOW); + wait(0.5); + drawBack(0, WHITE); + drawBack(1, WHITE); + drawBack(2, WHITE); + drawBack(3, WHITE); + // On Legendary difficulty + } else { + // Play sound + playSound(C4); + //wait(1); + } + } else if (fourHit == true) { + playerSequence[i] = 3; + + // On Easy difficulty + if (difficulty == EASY) { + // Display position, color, and play sound + drawFore(3, BLUE); + playSound(E4); + drawBack(3, WHITE); + // On Normal difficulty + } else if (difficulty == NORMAL) { + // Display position, color, and play sound + drawFore(3, BLUE); + playSound(E4); + drawBack(3, WHITE); + // On Heroic difficulty + } else if (difficulty == HEROIC) { + // Display color + drawFore(0, BLUE); + drawFore(1, BLUE); + drawFore(2, BLUE); + drawFore(3, BLUE); + wait(0.5); + drawBack(0, WHITE); + drawBack(1, WHITE); + drawBack(2, WHITE); + drawBack(3, WHITE); + // On Legendary difficulty + } else { + // Play sound + playSound(E4); + } + } + + resetHits(); + } + + // Determine whether the sequences match + bool correct = true; + + for (int i = 0; i < score + 1; i++) { + if (sequence[i] != playerSequence[i]) { + correct = false; + } + } + + // Play sound + if (correct == true) { + playSound(DING); + } else { + + playSound(BUZZER); + } + + // Check if the other player has won + if (XBee.readable() == true) { + otherPlayerWin = XBee.getc(); + } + + // If the other player has won, end the game + if (otherPlayerWin == true) { + goto endGame; + } + + // Update the score + if (correct == true) { + score++; + } else { + if (score > 0) { + score--; + } + } + + // Reset sequences + resetSequence(sequence, MAXLENGTH); + resetSequence(playerSequence, MAXLENGTH); + } while (score < MAXLENGTH); + + endGame: + uLCD.pixel(68, 68, WHITE); + } + + // Game over + void gameOver() { + XBee.putc(true); + + uLCD.cls(); + uLCD.text_width(1); + uLCD.text_height(1); + uLCD.textbackground_color(BLACK); + uLCD.filled_rectangle(0, 0, 127, 127, BLACK); + uLCD.background_color(BLACK); + uLCD.color(GREEN); + uLCD.locate(0, 0); + + if (otherPlayerWin == false) { + uLCD.printf("You win!"); + playSound(WIN); + } else { + uLCD.printf("The other player\n"); + uLCD.printf("wins."); + playSound(BOMB); + } + } +}; \ No newline at end of file