17
\$\begingroup\$

Here is a snakes and ladders game I made using an Arduino using a serial terminal, a set of addressable LED's to create a physical game board, a 7 segment display, and a piezoelectric to create sound.

I'd love to get some feed back on this regarding what I did right, what I did wrong, and any improvements that can be made to this game.

#include "FastLED.h"

#define NUM_LEDS 100

#define DATA_PIN 9

CRGB leds[NUM_LEDS];

//Assign correct pin values to corresponding variables
int piezoPin = 10;
int segmentOne = 7;
int segmentTwo = 2;
int segmentThree = 8;
int segmentFour = 4;
int segmentFive = 6;
int segmentSix = 3;
int segmentSeven = 5;

int boardArray[101]; // array of numbers   index = value, depending on the value of the index determains what is in that square of the board

int snakeArray[7][1]; // array of 8 snakes, with a start and end value  --- index starts from 0, 7 == 8
int ladderArray[7][1];  // array of 8 ladders, with a start and end value --- index starts from 0, 7 == 8

//Player Start Positions, the board array start from 0, we want to start from one, so set to 1.
int playerOnePosition = 1;
int playerTwoPosition = 1;

//variables needed to figure out which snake or ladder the player landed on, 10 is out of range and can be used as a null value
int ladderLandedOn = 10;
int snakeLandedOn = 10;

int turn = 1; // curren't player
boolean gamefinish; //boolean to setmode gam
int winner = 0; // game winner
int userInput;  // int variable to store the users input
int gameMode;   //variable to store the selected game mode

boolean gameStarted = false; // variable to store the game status, if false the game needs to wait for a game selection


void setup() {
  randomSeed(analogRead(0)); // each loop randomise the seed, stops repetative number generation between games when the arduino isn't being reset

  Serial.begin(38400); //Start the Serial Monitor
  //Set the pin modes.
  pinMode(piezoPin, OUTPUT);
  pinMode(segmentOne, OUTPUT);
  pinMode(segmentTwo, OUTPUT);
  pinMode(segmentThree, OUTPUT);
  pinMode(segmentFour, OUTPUT);
  pinMode(segmentFive, OUTPUT);
  pinMode(segmentSix, OUTPUT);
  pinMode(segmentSeven, OUTPUT);


  //For each index of array assign value of index, index 0 = (int)0 index 54 = (int)56 . . .
  for (int i = 0; i < 101; i++) {
    boardArray[i] = i;
  }

  //create 8 random snakes and ladders positions, starting from 0, so while n is less than 8, where n is 7 we have looped 8 times

  FastLED.addLeds<NEOPIXEL, DATA_PIN>(leds, NUM_LEDS);

  for(int i = 0; i < NUM_LEDS ;i++){
    leds[i] = CRGB::Black;
  }
  FastLED.show();
}


void loop() {
  randomSeed(analogRead(0)); // each loop randomise the seed, stops repetative number generation between games when the arduino isn't being reset
  (gameStarted == false ? gameInit() : voidFunction());  // if the game has not started run function game init(), else game has started, just do something random as i cant have a null value here
  (gameMode == 1 ? modeComputerVsComputer() : (gameMode == 2 ? modeSinglePlayer() : (gameMode == 3 ? modeMultiplayer() : loop())));  // ternary if statment, becuase ternary if statments are sexy. run the function that corresponds to the game mode, if there isnt one run the loop again
}

void voidFunction(){
}

void boardGen(){
  for (int i = 0; i < 101; i++) {
    boardArray[i] = i;
  }

  for (int n = 0; n < 8; n++) {
    int snakeStart = random(11, 100); // pick a random value to place the start of the snake above the first row on the board.
    int snakeFinish = random(3, snakeStart);  // pick a location to place the tail of the snake, this can be on the bottom row, but can not be above the snake head
    int ladderStart = random(3, 90); // pick a random value to place the start of the ladder between 3 and 98
    int ladderFinish = random(ladderStart + 5, 99); // pick the ladded finish position, between the ladder start + 5, this stops the creation of pointless 1 square ladders, and 98

    snakeArray[n][0] = snakeStart;    //Each loop store the start and end positions
    snakeArray[n][1] = snakeFinish;   //Each loop store the start and end positions
    boardArray[snakeStart] = 103;     //within the array of positions 1-100, place a snake there, snakes are represnted by an int of value 103

    ladderArray[n][0] = ladderStart;  //Each loop store the start and end positions
    ladderArray[n][1] = ladderFinish; //Each loop store the start and end positions
    boardArray[ladderStart] = 104;    //within the array of positions 1-100, place a ladder there, ladders are represnted by an int of value 104
  }
}

//The gameInit function displays the menu options and waits for a users input

void blinkRandomFade(){
  int hue = 0;
  int brightness = 0;
  for(int b = 0; b < 255; b++ ){
    for(int i = 0; i < NUM_LEDS;i++){
      leds[i] = CHSV(random(0,255),255,brightness);
    }
    FastLED.show();
    hue++;
    brightness++;
  }
  brightness = 255;
  for(int b = 0; b < 255; b++ ){
    for(int i = 0; i < NUM_LEDS;i++){
      leds[i] = CHSV(random(0,255),255,brightness);
    }
    FastLED.show();
    brightness--;
  }
}

void resetLights(){
  for(int i = 0; i < NUM_LEDS ;i++){
    leds[i] = CRGB::Black;
  }
  FastLED.show();
}


void gameInit() {
  showMainMenu(); //Show the menu
  boardGen();
  gameMode = getUserInput();  //set GameMode to the output of getUserInput which is an int, so entering a 1 will set game mode to 1
  if (gameMode > 0 && gameMode < 4) gameStarted = true; // if the gameMode is between 1-3 then set gameStarted to true, if not then it wont change and next loop gameInit will be ran again

}

//The getUserInput function waits for user input and then outputs the int value
int getUserInput() {
  int userInput;  //init the int userInput
  Serial.flush(); //flush all previous received and transmitted data
  while (!Serial.available()){
    if(gameStarted == false){
      blinkRandomFade();
    }
  };  // while there is nothing in the buffer, hold the program.
  userInput = Serial.parseInt(); // once there is something in the buffer the while will close and userInput will be assinged to the int entered
  return userInput; //Return the int value
}


//The showMainMenu function displays the main menu.
void showMainMenu() {
  Serial.println("----------------------");
  Serial.println(" | Main Menu! | ");
  Serial.println("----------------------");
  Serial.println();
  Serial.println("Please Select a Game mode!");
  Serial.println();
  Serial.println("Enter 1 for - Demo Mode - Computer Vs Computer");
  Serial.println("Enter 2 for - Single Player Vs Computer");
  Serial.println("Enter 3 for - Multiplayer");
}

//ShowEndGameMenu function displays the menu after a winner has been declared
void showEndGameMenu() {
  Serial.println("Enter 1 to Replay");
  Serial.println("Enter 2 to go to the main menu");
}

void modeSinglePlayer() {
  // run the check to see if any player has won the game.
  winnerCheck();
  // if player one has won.
  if (winner == 1) {
    //re run the random blink/fade function
    blinkRandomFade();
    //display who won in the console
    Serial.println("The winner is Player 1");
    //Show the end game menu
    showEndGameMenu();
    //Wait for user input 1 for restarting 2 for going back to the
    userInput = getUserInput();
    // if the user inputs 1 restart the game
    if (userInput == 1) {
      //Regenerate the board layout
      boardGen();
      //blank all the lights
      resetLights();
      //Set game started to true
      gameStarted = true;
    }
    //if the player entered 2
    else {
      //set game starte to false
      gameStarted = false;
    }

    //reset the winners/ positions/ and turns
    winner = 0;
    playerOnePosition = 1;
    playerTwoPosition = 1;
    turn = 1;
  }
  else if ( winner == 2) {
    blinkRandomFade();
    Serial.println("The winner is Player 2");
    showEndGameMenu();
    userInput = getUserInput();
    if (userInput == 1) {
      boardGen();
      resetLights();
      gameStarted = true;
    }
    else {
      gameStarted = false;
    }
    winner = 0;
    playerOnePosition = 1;
    playerTwoPosition = 1;
    turn = 1;
  }
  else {
    //draw the player turn display
    Serial.println("----------------------");
    Serial.print(" | Player ");
    Serial.print(turn);
    Serial.println("'s turn! |");
    Serial.println("----------------------");


    Serial.println("Please Select a number of rolls between 1-3");
    int numOfRolls;

    if (turn == 1) {
      //wait for the user to enter how many rolls they want
      numOfRolls = getUserInput();
      if (numOfRolls > 3) {
        //if they enter a value greater than 3 set it to 3
        numOfRolls = 3;
      }
      else if (numOfRolls < 1) {
        //if they enter a value less than 1 set it to 1
        numOfRolls = 1;
      }
    }
    else {
      numOfRolls = random(1, 4);
    }

    Serial.print("You selected ");
    Serial.println(numOfRolls);
    Serial.println();
    boolean reroll = false;
    int diceRoll = rollDice(numOfRolls);

    Serial.println("rolling Dice");
    //    delay(1000);
    Serial.print("player ");
    Serial.print(turn);
    Serial.print(" rolled a ");
    Serial.println(diceRoll);
    delay(500);

    //if the dice was a 6 then reroll
    if (diceRoll == 6) {
      Serial.println("You landed on a 6 and get to reroll!");
      playSound(3,1);
      reroll = true;
    }

  //move the player based on whos turn it is and the dice roll
    movePlayer(turn, diceRoll);
  //display player status
    displayPlayerStatus();

  //display the boards
    printBoard();

  //if player player got a 6 do nothing.
    if (reroll != true) {
      //if the player was 1 change to 2
      if (turn == 1) {
        turn = 2;
      }
      // the player was 2 change to 1
      else {
        turn = 1;
      }
    }
  }
}

void modeMultiplayer() {
  winnerCheck();
  if (winner == 1) {
    blinkRandomFade();
    Serial.println("The winner is Player 1");
    showEndGameMenu();
    userInput = getUserInput();
    if (userInput == 1) {
      boardGen();
      resetLights();
      gameStarted = true;
    }
    else {
      gameStarted = false;
    }
    winner = 0;
    playerOnePosition = 1;
    playerTwoPosition = 1;
    turn = 1;
  }
  else if ( winner == 2) {
    blinkRandomFade();
    Serial.println("The winner is Player 2");
    showEndGameMenu();
    userInput = getUserInput();
    if (userInput == 1) {
      boardGen();
      resetLights();
      gameStarted = true;
    }
    else {
      gameStarted = false;
    }
    winner = 0;
    playerOnePosition = 1;
    playerTwoPosition = 1;
    turn = 1;
  }
  else {

    Serial.println("----------------------");
    Serial.print(" | Player ");
    Serial.print(turn);
    Serial.println("'s turn! |");
    Serial.println("----------------------");

    Serial.println("Please Select a number of rolls between 1-3");
    int numOfRolls;

    numOfRolls = getUserInput();
    if (numOfRolls > 3) {
      numOfRolls = 3;
    }
    else if (numOfRolls < 1) {
      numOfRolls = 1;
    }

    Serial.print("You selected ");
    Serial.println(numOfRolls);
    Serial.println();
    boolean reroll = false;
    int diceRoll = rollDice(numOfRolls);

    Serial.println("rolling Dice");
    Serial.print("player ");
    Serial.print(turn);
    Serial.print(" rolled a ");
    Serial.println(diceRoll);
    delay(500);

    if (diceRoll == 6) {
      Serial.println("You landed on a 6 and get to reroll!");
      playSound(3,1);
      reroll = true;
    }

    movePlayer(turn, diceRoll);

    displayPlayerStatus();

    printBoard();

    if (reroll != true) {
      if (turn == 1) {
        turn = 2;
      }
      else {
        turn = 1;
      }
    }
  }
}

void modeComputerVsComputer() {
  winnerCheck();
  if (winner == 1) {
    Serial.println("The winner is Player 1");
    showEndGameMenu();
    userInput = getUserInput();
    if (userInput == 1) {
      resetLights();
      boardGen();
      gameStarted = true;
    }
    else {
      gameStarted = false;
    }
    winner = 0;
    playerOnePosition = 1;
    playerTwoPosition = 1;
    turn = 1;
  }
  else if ( winner == 2) {
    Serial.println("The winner is Player 2");
    showEndGameMenu();
    userInput = getUserInput();
    if (userInput == 1) {
      boardGen();
      resetLights();
      gameStarted = true;
    }
    else {
      gameStarted = false;
    }
    winner = 0;
    playerOnePosition = 1;
    playerTwoPosition = 1;
    turn = 1;
  }
  else {
    Serial.println("----------------------");
    Serial.print(" | Player ");
    Serial.print(turn);
    Serial.println("'s turn! |");
    Serial.println("----------------------");

    Serial.println("Please Select a number of rolls between 1-3");
    int numOfRolls = random(1, 4);


    Serial.print("You selected ");
    Serial.println(numOfRolls);
    Serial.println();
    boolean reroll = false;
    int diceRoll = rollDice(numOfRolls);

    Serial.println("rolling Dice");
    Serial.print("player ");
    Serial.print(turn);
    Serial.print(" rolled a ");
    Serial.println(diceRoll);
    delay(500);

    if (diceRoll == 6) {
      playSound(3,1);
      Serial.println("You landed on a 6 and get to reroll!");
      reroll = true;
    }

    movePlayer(turn, diceRoll);

    displayPlayerStatus();

    printBoard();

    if (reroll != true) {
      if (turn == 1) {
        turn = 2;
      }
      else {
        turn = 1;
      }
    }
    delay(2000);
  }
}

//The printboard function displays the snakes and ladders game boad with all the snakes, ladders, players and square numbers
void printBoard() {
  int rowStartValue = 101; // the value at the start of each row, the first row would be 91, going up to 100
  Serial.println(); // create a 1 line gap between what ever else has been printed
  Serial.println("----------------------------------------------------"); // make the top of the board pretty
  for (int r = 0; r < 10; r++) { //for each row, we have 10
    for (int x = rowStartValue - 10; x < rowStartValue; x++ ) {  //for each row , get the start value - 10  for the first row(91), then each iteration add 1,
      Serial.print(" | "); // place a pipe at the start of each square
      if (boardArray[x] == 101) { // if boardArray[x] == 101, where 101 is player 1 and boardArray[x] is the position, print an X, X represents Player 1
        Serial.print(" X");
        leds[x-1] = CRGB::Green;
      }
      else if (boardArray[x] == 102) { // if boardArray[x] == 102, where 101 is player 1 and boardArray[x] is the position, print an O, O represents Player 2
        Serial.print(" O");
        leds[x-1] = CRGB::Blue;
      }
      else if (boardArray[x] == 103) { // if boardArray[x] == 103, where 101 is player 1 and boardArray[x] is the position, print an S, S represents a Snake
        Serial.print(" S");
        leds[x-1] = CRGB::Red;
      }
      else if (boardArray[x] == 104) { // if boardArray[x] == 104, where 101 is player 1 and boardArray[x] is the position, print an H, H represents a ladder
        Serial.print(" H");
        leds[x-1] = CRGB::LightBlue;
      }
      else {
        if (x < 10) {
          Serial.print(" ");   // position below 10, so 1-9 are only one character, we need to add a space before the number to keep the format of the board
        }
        Serial.print(boardArray[x]);  //if the current possition on the board is not P1, P2, snake or a ladder, print the square value
        leds[x-1] = CRGB::Black;

      }
      if (x != rowStartValue - 1) {
      }
      else {
        Serial.print(" | ");
      }
    }

    Serial.println(); //Moves to the next line after printing the number 10 at the bottom of the board
    rowStartValue = rowStartValue - 10; // after each row, remove another 10 from start value, for the next row
    Serial.println("----------------------------------------------------"); // make the bottom of the board look pretty
  }
  Serial.println(); // drop another line in afte rthe board has all been rendered
  FastLED.show();
}

//The winnderCheck function checks if a player has won.
void winnerCheck() {
  if (playerOnePosition == 100) { //if player one has reached square 100 then set winner to 1.
    winner = 1;
  }
  else if (playerTwoPosition == 100) { //if player twp  has reached square 100 then set winner to 2.
    winner = 2;
  }
}


//The movePlayer function, moves the player to a new location, movePlayer takes two arguments (int turn, int Moves), turn is the value of which player, ie 1 for player 1, 2 for player 2, and moves is the number of moves to move.
void movePlayer(int turn, int moves) {

  int player; // init a player variable, so we can more easily use it instead of calling specific player variables
  if (turn == 1) {
    player = playerOnePosition;  //if the player is player 1 then set player to the player position variable
  }
  else {
    player = playerTwoPosition;  //else it's player two so set it to player twos position
  }
  if (player + moves <= 100) {  // if the current position plus moves is less than or equal too 100, they are allowed to move. else they have over shot and have to wait again
    for (int i = 0; i < 8; i++) { // for each of the snakes in the game
      if (snakeArray[i][0] == player + moves) { // check to see if there start position is equal to where the player would be if they move.
        snakeLandedOn = i; // if the player would land on a snake, put the index of the snake in to snakeLandedOn, this way we can get the tail position later
      }
    }
    for (int i = 0; i < 8; i++) { // for each ladder in the game
      if (ladderArray[i][0] == player + moves) { //check to see if the start position of the ladder is where the player would be if they move
        ladderLandedOn = i; // if the player would land on the ladder put the index of the ladder in to ladderLandedOn so we can get the ladder data later on
      }
    }
    if (snakeLandedOn != 10) { // if snake landed on != 10, then the player has landed on snake ,10 is the default and mean the player has not landed on a snake
      playSound(1,1);
      Serial.println("You have landed on a snake!"); // Tell the player
      boardArray[player] = player; //set the index in the boardArray of where they player was, to there old position, this resets the value back to it's number,  example if the player was on square 1, and is moving to 10, square 1 will show X but when the player moves we need to set the square 1 back to 1 and remove X
      if (turn == 1) { // check if we are moving player one of player two
        boardArray[snakeArray[snakeLandedOn][1]] = 101; //change the value of the square number to show where the player now is after they slide down the snake
        playerOnePosition = snakeArray[snakeLandedOn][1]; // set the position of the player to there new position
      }
      else {
        boardArray[snakeArray[snakeLandedOn][1]] = 102; //change the value of the square number to show where the player now is after they slide down the snake
        playerTwoPosition = snakeArray[snakeLandedOn][1]; // set the position of the player to there new position
      }
    }
    else if (ladderLandedOn != 10) {
      playSound(2,1);
      Serial.println("You have landed on a ladder!");
      boardArray[player] = player;
      if (turn == 1) {
        boardArray[ladderArray[ladderLandedOn][1]] = 101; //change the value of the square number to show where the player now is after they climb up the ladder
        playerOnePosition = ladderArray[ladderLandedOn][1]; // set the position of the player to there new position
      }
      else {
        boardArray[ladderArray[ladderLandedOn][1]] = 102; //change the value of the square number to show where the player now is after they climb up the ladder
        playerTwoPosition = ladderArray[ladderLandedOn][1]; // set the position of the player to there new position
      }
    }
    else { // if we did not land on a snake or a ladder then we need to move normally
      boardArray[player] = player;  // set the old position back to it's value
      if (turn == 1) { // if player 1
        boardArray[player + moves] = 101; //set the new position to value 101
        playerOnePosition = player + moves; // set the playerTwoPosition to the new position
      }
      else {
        boardArray[player + moves] = 102; //set the new position to value 102
        playerTwoPosition = player + moves; // set the playerTwoPosition to the new position
      }
    }
    snakeLandedOn = 10; //set the sanke landed on back to 10;
    ladderLandedOn = 10; //set the sanke landed on back to 10;
  }
}

//The displayPlayerstatus function displays where both players currently are on the board
void displayPlayerStatus() {
  Serial.println(); // move to the next line down
  Serial.print("Player 1 is currently at "); // print the player and there location
  Serial.println(playerOnePosition);

  Serial.print("Player 2 is currently at "); // print the player and there location
  Serial.println(playerTwoPosition);
}

// The rollDice fucnction generates a random number between 1-6, rollDice accepts one argument int(numOfRolls), which is the amount of times to roll the dice
int rollDice(int numOfRolls) {

  for (int i = 0; i < numOfRolls; i++) {  // for the number of rolls choosen by the player, since we are starting from 0, we need the finish one before the selection, 0 = 1 roll 1 = 2 rolls
    int randomNumber = random(1, 7); // Generate a number between 1-6
    drawRoll(); // draw the random roll to the 7 seg display

    //draw the correct digit for the number landed on
    if (randomNumber == 1) {
      drawOne();
    }
    else if (randomNumber == 2) {
      drawTwo();
    }
    else if (randomNumber == 3) {
      drawThree();
    }
    else if (randomNumber == 4) {
      drawFour();
    }
    else if (randomNumber == 5) {
      drawFive();
    }
    else if (randomNumber == 6) {
      drawSix();
    }
    // if we are on the last roll then return the value of randomNumber
    if (i == numOfRolls - 1) {
      return randomNumber;
    }
  }
}


void blankDisplay() {
  digitalWrite(segmentOne, LOW);
  digitalWrite(segmentTwo, LOW);
  digitalWrite(segmentThree, LOW);
  digitalWrite(segmentFour, LOW);
  digitalWrite(segmentFive, LOW);
  digitalWrite(segmentSix, LOW);
  digitalWrite(segmentSeven, LOW);
}

/*
 5 more functions like this to draw various numbers on the 7 segment cut them out to reduse the size
*/

void drawOne() {
  blankDisplay();
  digitalWrite(segmentTwo, HIGH);
  digitalWrite(segmentFour, HIGH);
}



void drawRoll() {
  for (int i = 0; i < 4; i++) {
    blankDisplay();
    digitalWrite(segmentOne, (random(0, 2)  == 1  ?   HIGH : LOW ));
    digitalWrite(segmentTwo, (random(0, 2)  == 1  ?   HIGH : LOW ));
    digitalWrite(segmentThree, (random(0, 2)  == 1  ?   HIGH : LOW ));
    digitalWrite(segmentFour, (random(0, 2)  == 1  ?   HIGH : LOW ));
    digitalWrite(segmentFive, (random(0, 2)  == 1  ?   HIGH : LOW ));
    digitalWrite(segmentSix, (random(0, 2)  == 1  ?   HIGH : LOW ));
    digitalWrite(segmentSeven, (random(0, 2)  == 1  ?   HIGH : LOW ));
    delay(100);
  }
}


void playSound(int sound, int repeatTimes) {

  for (int i = 1; i <= repeatTimes; i ++) {
    if (sound == 1) {
      tone(piezoPin, 523, 250);
      delay(500);
    }
    else if (sound == 2) {
      tone(piezoPin, 261, 250);
      delay(500);
    }
    else if (sound == 3) {
      tone(piezoPin, 523, 150);
      delay(100);


    }
  }
}
\$\endgroup\$
  • 4
    \$\begingroup\$ Congratulations on being our first June 2016 Community Challenge participant! \$\endgroup\$ – syb0rg Jun 2 '16 at 13:47
  • 2
    \$\begingroup\$ @syb0rg wasn't actually made for that but reading over it i guess it fits within the rules so why not! \$\endgroup\$ – Josh Kirkpatrick Jun 2 '16 at 13:49
  • 4
    \$\begingroup\$ That's an amazing coincidence. \$\endgroup\$ – Raystafarian Jun 2 '16 at 15:06
  • 1
    \$\begingroup\$ bug: snakeArray is [7][1] but you access 7,1 which is out of bounds in 2 ways. You want dimension 8 and 2 instead. \$\endgroup\$ – ratchet freak Jun 2 '16 at 15:24
8
\$\begingroup\$

Arduino specifics

Disclaimer: I've got very little experience with Arduino programming. That said, my understanding is that the code you write essentially sits inside a function like this:

setup();     // User provided function, executed once on startup
while(true) {
    loop();  // User provided function, executed over and over again
}

Assuming I'm correct, then it looks like you have a potential bug in your loop code. At the end of it you have a line that checks the current gameMode and if it's not 1,2 or 3 it calls loop.

(gameMode == 1 ? modeComputerVsComputer() : 
                (gameMode == 2 ? modeSinglePlayer() 
                               : (gameMode == 3 ? modeMultiplayer() 
                                                : loop())));  

You don't need to do this, it's handled automatically for you. By calling loop yourself you're recursing, if you do it enough times, you're going to end up with a stack overflow. My guess is that the Arduino would just reset in this situation and then call setup again. Since you're not playing, you might not even notice it happen.

Your setup contains randomSeed(analogRead(0)). This is also the first line of your loop method. Setup doesn't seem to actually be using the randomiser, so I suspect you don't need to call it from setup, simply call it from loop.

Ternary Operator

I've got nothing against the ternary operator, however some of your choices do nothing but make your code harder to follow. Nested ?s should be avoided. Creating a null function so that you can use the ternary operator is unnecessarily complex.

The method would be easier to follow if you used constants and spread out the logic a bit.

randomSeed(analogRead(0)); 
if (!gameStarted) gameInit();
switch(gameMode)
{
    case GAME_MODE_COMPUTER_VS_COMPUTER:
        modeComputerVsComputer();
        break;
    case GAME_MODE_SINGLE_PLAYER:
        modeSinglePlayer();
        break;
    case GAME_MODE_MULTIPLAYER:
        modeMultiplayer();
        break;
}

Alternately you could setup an array of function pointers and index into it based on the gamemode to get the method to execute.

Repeated Code

There seems to be some repeated code between the different game modes. For example the following is repeated twice in each game mode (once for player 1 win, once for player 2). There is a slight variation in computerVsComputer, where the blinkRandomFade is omitted, it's unclear if this is intentional or not.

blinkRandomFade();
Serial.println("The winner is Player 1");
showEndGameMenu();
userInput = getUserInput();

This could be refactored into a method that takes the winning player number. There are other repeated blocks that again could be refactored into functions to reduce the overall amount of code and make it easier to follow the logic. For example, startGame?:

boardGen();
resetLights();
gameStarted = true;

The Interface

You've done some good centralisation of the interface with some of the board elements drawRoll, playSound centralise the interaction so that you could replace these methods and maintain the core logic of the game. However, your interaction with the Serial interface permeates your entire code. If you centralised this interaction, then it would be easier to remove the dependency (for example to run it on a computer, or if you wanted to use different components in the future).

Consider using function pointers

There are various points in your code where you are calling different methods based on an index like this:

if (randomNumber == 1)
{
    drawOne();
}
else if (randomNumber == 2)
{
    drawTwo();
}
else if (randomNumber == 3)
{
    drawThree();
}
else if (randomNumber == 4)
{
    drawFour();
}
else if (randomNumber == 5)
{
    drawFive();
}
else if (randomNumber == 6)
{
    drawSix();
}

Consider replacing this with function lookup table, that way the invocation is a lot simpler (bounds checking may be required, although not for this case because of the source of the number):

void (*drawNumberMethods[6])() = {drawOne,drawTwo,drawThree,drawFour,drawFive,drawSix};

drawNumberMethods[randomNumber-1]();

Magic Numbers

For the most part, I don't mind having actual numbers in code where they make sense in context. In the die drawing code above, it is easy to follow that the 1 and drawOne are connected as the value of the die. However some of your numbers are less clear, like ladderLandedOn = 10 representing not on a ladder. Where the meaning isn't obvious, avoid using the numbers and consider replacing them with a meaningful constant / #define.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.