Weekend Hack: Battleship!

Beautiful long weekend here in Saskatoon! The sun is shining, nice breeze — great weather to work in the garden. So of course, I’m inside coding instead! I decided to make another neopixel matrix game to follow up from the Snake game I made last fall. While working on another project, I noticed that buttons placed on the breadboard lined up nicely with the spacing on the matrix, creating a nice user interface to select individual pixels on the board. That reminded me of the classic game Battleship, so it became my next project.

Unfortunately, I only have one 16×16 matrix, so I had to make it a solo game instead of the typical two player game. Instead of taking turns until one player’s ships are sunk, you play with a set number of misses. When your misses run out, then the game is over. Otherwise, the rules are the same — 5 ships placed randomly on the board, each turn you choose a coordinate, you’re told if it’s a hit or a miss, and you’re told if you’ve sunk a ship.

The hardest part for this project was figuring out how to detect the input from all those buttons. There are only so many pins on the microcontroller. Because I used the Arduino Mega for this project, I could have used 24 of the pins on the Mega, but I decided to see if there was a way to minimize that number, just in case I wanted to extend the project and needed additional free microcontroller pins later. To solve this, I used 3 MCP23008’s; the MCP23008 is an i2c 8 i/o port extender that gives you 8 input or output pins but only uses 2 pins on the microcontroller. The MCP23008 all use the same i2c pins to communicate with the Mega, but you can set a unique address / identifier for each chip by setting the address pins (3, 4, and 5) to binary 0, 1, and 2. On the Frizting diagram below, pins 3, 4, and 5 have different configurations for each MCP23008. Adafruit also has a great MCP23008 library for Arduino IDE.

Fritzing diagram for Battleship (missing the matrix)

It was also tricky to troubleshoot which buttons were causing problems, so I color coded the wiring to make debugging code and hardware a bit easier. I matched the colors in the diagram with the code (RED_BUTTON, ORANGE_BUTTON, etc) so to reduce errors caused by hard coded values. Plus, I think it gives a nice aesthetic.

The code itself is a bit repetitious and could probably use some refactoring, but it’s hopefully self explanatory. I’ll paste the code at the end of this post to save you from scrolling. I posted the code on github and added a video on YouTube:

You sunk my Battleship!

Enjoy! Add a comment with other game suggestions, using the neopixel matrix or not.

#include <Adafruit_MCP23008.h>
#include <Adafruit_NeoPixel.h>

Adafruit_MCP23008 mcp1;
Adafruit_MCP23008 mcp2;
Adafruit_MCP23008 mcp3;

#define NUMBER_ROWS_AND_COLUMNS 12
#define MATRIX_SIZE 16

#define GAME_OVER_MODE 1
#define PLAYING_MODE 0

bool buttonRow[NUMBER_ROWS_AND_COLUMNS];
bool buttonCol[NUMBER_ROWS_AND_COLUMNS];

int lastRowPressed = -1;
int lastColPressed = -1;

int gameMode = PLAYING_MODE;

#define UP_DIRECTION 0
#define DOWN_DIRECTION 1
#define LEFT_DIRECTION 2
#define RIGHT_DIRECTION 3

#define addr1 0
#define addr2 1
#define addr3 2

#define RED_BUTTON 0
#define ORANGE_BUTTON 1
#define YELLOW_BUTTON 2
#define GREEN_BUTTON 3
#define BLUE_BUTTON 4
#define PURPLE_BUTTON 5
#define WHITE_BUTTON 6
#define GRAY_BUTTON 7

#define FIRE_BUTTON_PIN 9
#define MATRIX_PIN 8

uint32_t playerBoard[MATRIX_SIZE][MATRIX_SIZE];
Adafruit_NeoPixel matrix = Adafruit_NeoPixel(MATRIX_SIZE * MATRIX_SIZE, MATRIX_PIN, NEO_GRB + NEO_KHZ800);

uint32_t RED = matrix.Color(255, 0, 0);
uint32_t ORANGE = matrix.Color(255, 165, 0);
uint32_t YELLOW = matrix.Color(255, 255, 0);
uint32_t GREEN = matrix.Color(0, 255, 0);
uint32_t BLUE = matrix.Color(0, 0, 255);
uint32_t WHITE = matrix.Color(255, 255, 255);
uint32_t CLEAR = matrix.Color(0, 0, 0);

unsigned long timeOfLastBlinkToggle = 0;
bool overlaysOn = true;
unsigned long timeSinceGameOverStarted = 0;

struct cell {
  int row;
  int column;
};

cell aircraftCarrier[5];
cell battleship[4];
cell cruiser1[3];
cell cruiser2[3];
cell defender[2];

cell aircraftCarrierRepresentation[5];
cell battleshipRepresentation[4];
cell cruiser1Representation[3];
cell cruiser2Representation[3];
cell defenderRepresentation[2];

cell numberTurnsRepresentation[36];

int aircraftCarrierHits = 0;
int battleshipHits = 0;
int cruiser1Hits = 0;
int cruiser2Hits = 0;
int defenderHits = 0;

int numberTurns = 36;

bool displayedAircraftCarrierSunkMessage = false;
bool displayedBattleshipSunkMessage = false;
bool displayedCruiser1SunkMessage = false;
bool displayedCruiser2SunkMessage = false;
bool displayedDefenderSunkMessage = false;

void setup() {
  Serial.begin(9600);
  pinMode(FIRE_BUTTON_PIN, INPUT_PULLUP);   
  
  mcp1.begin(addr1);
  mcp2.begin(addr2);
  mcp3.begin(addr3);

  for(int i = 0; i < 8; i++) {
    mcp1.pinMode(i, INPUT);
    mcp1.pullUp(i, HIGH);
    mcp2.pinMode(i, INPUT);
    mcp2.pullUp(i, HIGH);
    mcp3.pinMode(i, INPUT);
    mcp3.pullUp(i, HIGH);
  }

  matrix.begin();
  matrix.setBrightness(32);
  matrix.show();

  randomSeed(analogRead(0));

  defineGameParameters();
  startGame();
}

void startGame() {
  resetRowAndColumnSelectionVariables();
  resetPlayerBoard();  
  Serial.println("Let's play Battleship!");
}

void defineGameParameters() {
  for(int i = 0; i < 5; i++) {
    aircraftCarrierRepresentation[i].row = 13;
    aircraftCarrierRepresentation[i].column = i + 1;
  }
  for(int i = 0; i < 4; i++) {
    battleshipRepresentation[i].row = 13;
    battleshipRepresentation[i].column = i + 7;
  }  
  for(int i = 0; i < 3; i++) {
    cruiser1Representation[i].row = 13;
    cruiser1Representation[i].column = i + 12;
    cruiser2Representation[i].row = 15;
    cruiser2Representation[i].column = i + 5;
  }
  for(int i = 0; i < 2; i++) {
    defenderRepresentation[i].row = 15;
    defenderRepresentation[i].column = i + 10;
  }
  for(int i = 0; i <36; i++) {    
    if(i < 12) {
      numberTurnsRepresentation[i].row = i;
      numberTurnsRepresentation[i].column = 13;
    } else if(i < 24) {
      numberTurnsRepresentation[i].row = i - 12;
      numberTurnsRepresentation[i].column = 14;
    } else {
      numberTurnsRepresentation[i].row = i - 24;
      numberTurnsRepresentation[i].column = 15;
    }
  }
}

// the loop function runs over and over again forever
void loop() {
  readInputs();    
  setLastButtonsPressed();  
  if(gameMode == GAME_OVER_MODE) {
    long currentTime = millis();
    if(currentTime - timeSinceGameOverStarted > 10000) {
      startGame();
    }
  } else {
    if(canFire()) {
      if(digitalRead(FIRE_BUTTON_PIN) == LOW) {
        while(digitalRead(FIRE_BUTTON_PIN) == LOW) {
          // wait until the user releases the fire button
        }
        bool isHit = fire();
        if(!isHit) {
          updateNumberTurns();        
        }
        resetRowAndColumnSelectionVariables();      
      }    
    }    
    if(isGameOver()) {
      gameMode = GAME_OVER_MODE;
      timeSinceGameOverStarted = millis();
      if(isWin()) {
        Serial.println("Congratulations, you sunk all my ships!");
      } else {
        Serial.println("Sorry, you lose.  You didn't sink all my ships in time.");
      }    
    }
  }
  updateMatrix();
}
void updateNumberTurns() {
  cell currentNumberTurnRepresentation = numberTurnsRepresentation[36 - numberTurns];
  playerBoard[currentNumberTurnRepresentation.row][currentNumberTurnRepresentation.column] = CLEAR;
  numberTurns = numberTurns - 1;
  Serial.print("You have ");
  Serial.print(numberTurns);
  Serial.println(" misses remaining");    
  Serial.println("");
}
bool isWin() {
  return aircraftCarrierIsSunk() 
     && battleshipIsSunk() 
     && cruiser1IsSunk() 
     && cruiser2IsSunk() 
     && defenderIsSunk();
}

bool isGameOver() {
  return numberTurns == 0 || isWin();  
}

bool rowIsSelected() {
  return lastRowPressed != -1;
}
bool colIsSelected() {
  return lastColPressed != -1;
}

bool canFire() {
  return rowIsSelected() && colIsSelected() && !hasBeenPlayed(lastRowPressed, lastColPressed);
}
bool hasBeenPlayed(int row, int col) {
  return playerBoard[row][col] != CLEAR;
}

void setLastRowButtonPressed() {
  for(int i = 0; i < NUMBER_ROWS_AND_COLUMNS; i++) {
    if(buttonRow[i]) {
      lastRowPressed = i;
    }
  }
}
void setLastColButtonPressed() {
  for(int i = 0; i < NUMBER_ROWS_AND_COLUMNS; i++) {
    if(buttonCol[i]) {
      lastColPressed = i;
    }
  }
}

void setLastButtonsPressed() {
  setLastRowButtonPressed();
  setLastColButtonPressed();
}

void resetRowAndColumnSelectionVariables() {
  for(int i = 0; i < NUMBER_ROWS_AND_COLUMNS; i++) {
    buttonRow[i] = false;
    buttonCol[i] = false;
  }
  lastRowPressed = -1;
  lastColPressed = -1;
  overlaysOn = true;
  timeOfLastBlinkToggle = 0;
}

void fillNumberTurns() {
  for(int i = 0; i < 36; i++) {
    playerBoard[numberTurnsRepresentation[i].row][numberTurnsRepresentation[i].column] = BLUE;
  }
}

void resetPlayerBoard() {
  for(int i = 0; i < MATRIX_SIZE; i++) {
    for(int j = 0; j < MATRIX_SIZE; j++) {
      playerBoard[i][j] = CLEAR;
    }
  }
  numberTurns = 36;
  fillNumberTurns();
  gameMode = PLAYING_MODE;
  
  aircraftCarrierHits = 0;
  battleshipHits = 0;
  cruiser1Hits = 0;
  cruiser2Hits = 0;
  defenderHits = 0;
  
  displayedAircraftCarrierSunkMessage = false;
  displayedBattleshipSunkMessage = false;
  displayedCruiser1SunkMessage = false;
  displayedCruiser2SunkMessage = false;
  displayedDefenderSunkMessage = false;

  resetShips();
  
  placeBoardMarkers();
  placeAircraftCarrier();
  placeBattleship();
  placeCruiser1();
  placeCruiser2();
  placeDefender();
  placeShipRepresentations();      

  updateMatrix();
}
void placeBoardMarkers() {
  for(int i = 0; i < MATRIX_SIZE; i++) {
    playerBoard[12][i] = ORANGE;    
  }
  for(int i = 0; i < NUMBER_ROWS_AND_COLUMNS; i++) {
    playerBoard[i][12] = ORANGE;
  }
}
void placeShipRepresentations() {  
  for(int i = 0; i < 5; i++) {
    playerBoard[aircraftCarrierRepresentation[i].row][aircraftCarrierRepresentation[i].column] = GREEN;    
  }
  for(int i = 0; i < 4; i++) {
    playerBoard[battleshipRepresentation[i].row][battleshipRepresentation[i].column] = GREEN;
  }
  for(int i = 0; i < 3; i++) {
    playerBoard[cruiser1Representation[i].row][cruiser1Representation[i].column] = GREEN;
    playerBoard[cruiser2Representation[i].row][cruiser2Representation[i].column] = GREEN;
  }
  for(int i = 0; i < 2; i++) {
    playerBoard[defenderRepresentation[i].row][defenderRepresentation[i].column] = GREEN;
  }   
}

void resetShips() {
  for(int i = 0; i < 5; i++) {
    aircraftCarrier[i].row = -1;
    aircraftCarrier[i].column = -1;    
  }
  for(int i = 0; i < 4; i++) {
    battleship[i].row = -1;
    battleship[i].column = -1;
  }
  for(int i = 0; i < 3; i++) {
    cruiser1[i].row = -1;
    cruiser1[i].column = -1;
    cruiser2[i].row = -1;
    cruiser2[i].column = -1;
  }
  for(int i = 0; i < 2; i++) {
    defender[i].row = -1;
    defender[i].column = -1;
  }
}

int getRandomDirection() {
  int randomNumber = random(0, 4);
  switch(randomNumber) {
    case 0:
      return UP_DIRECTION;
    case 1:
      return DOWN_DIRECTION;
    case 2:
      return LEFT_DIRECTION;
    case 3:
      return RIGHT_DIRECTION;
    default:
      return UP_DIRECTION;
  }
}

cell getRandomCell() {
  cell randomCell;
  randomCell.row = random(0, 12);
  randomCell.column = random(0, 12);
  return randomCell;
}

void generateShipPlacement(cell startCellOfShip, int directionOfShip, int shipSize, cell shipPlacement[]) {
  for(int i = 0; i < shipSize; i++) {
    switch(directionOfShip) {
      case UP_DIRECTION:        
        shipPlacement[i].row = startCellOfShip.row - i;
        shipPlacement[i].column = startCellOfShip.column;
      break;
      case DOWN_DIRECTION:        
        shipPlacement[i].row = startCellOfShip.row + i;
        shipPlacement[i].column = startCellOfShip.column;
        break;
      case LEFT_DIRECTION:
        shipPlacement[i].row = startCellOfShip.row;
        shipPlacement[i].column = startCellOfShip.column - i;
        break;
      case RIGHT_DIRECTION:
        shipPlacement[i].row = startCellOfShip.row;
        shipPlacement[i].column = startCellOfShip.column + i;
        break;
    }
  }
}

bool isValidShipPlacement(cell startCellOfShip, int directionOfShip, int shipSize) {  
  // check first if the placement can happen on the grid based on the size of the ship
  switch(directionOfShip) {
    case UP_DIRECTION:
      if(startCellOfShip.row - shipSize < 0) {
        return false;
      }
      break;
    case DOWN_DIRECTION:
      if(startCellOfShip.row + shipSize > 11) {
        return false;
      }
      break;
    case LEFT_DIRECTION:
      if(startCellOfShip.column - shipSize < 0) {
        return false;
      }
      break;
    case RIGHT_DIRECTION:
      if(startCellOfShip.column + shipSize > 11) {
        return false;
      }
      break;
    default:
      return false;
  }
  cell candidateShipPlacement[shipSize];
  generateShipPlacement(startCellOfShip, directionOfShip, shipSize, candidateShipPlacement);

  // next check if the ship interferes with any of the other ships
  if(aircraftCarrier[0].row != -1) {    
    if(placementsOverlap(aircraftCarrier, 5, candidateShipPlacement, shipSize)) {
      return false;
    }
  }
  if(battleship[0].row != -1) {
    if(placementsOverlap(battleship, 4, candidateShipPlacement, shipSize)) {
      return false;
    }
  }
  if(cruiser1[0].row != -1) {
    if(placementsOverlap(cruiser1, 3, candidateShipPlacement, shipSize)) {
      return false;
    }
  }
  if(cruiser2[0].row != -1) {
    if(placementsOverlap(cruiser2, 3, candidateShipPlacement, shipSize)) {
      return false;
    }
  }

  // if all these tests pass, then the ship placement is valid
  return true;
}

bool placementsOverlap(cell ship1[], int sizeOfShip1, cell ship2[], int sizeOfShip2) {
  for(int i = 0; i < sizeOfShip1; i++) {
    for(int j = 0; j < sizeOfShip2; j++) {
      if(ship1[i].row == ship2[j].row && ship1[i].column == ship2[j].column) {
        return true;
      }
    }
  }
  return false;
}

void placeShip(int shipSize, cell ship[]) {
  cell startCellOfShip;
  int directionOfShip;
  do {
    startCellOfShip = getRandomCell();
    directionOfShip = getRandomDirection();
  } while(!isValidShipPlacement(startCellOfShip, directionOfShip, shipSize));
  
  generateShipPlacement(startCellOfShip, directionOfShip, shipSize, ship);
}


void placeAircraftCarrier() {      
  placeShip(5, aircraftCarrier);    
}
void placeBattleship() {  
  placeShip(4, battleship);  
}
void placeCruiser1() {  
  placeShip(3, cruiser1);  
}
void placeCruiser2() {  
  placeShip(3, cruiser2);
}
void placeDefender() {
  placeShip(2, defender);
}

void readInputs() {
  buttonRow[0] = mcp2.digitalRead(GREEN_BUTTON) == LOW? true: false;
  buttonRow[1] = mcp2.digitalRead(YELLOW_BUTTON) == LOW? true: false;
  buttonRow[2] = mcp2.digitalRead(ORANGE_BUTTON) == LOW? true: false;
  buttonRow[3] = mcp2.digitalRead(RED_BUTTON) == LOW? true: false;
  buttonRow[4] = mcp3.digitalRead(GRAY_BUTTON) == LOW? true: false;
  buttonRow[5] = mcp3.digitalRead(WHITE_BUTTON) == LOW? true: false;
  buttonRow[6] = mcp3.digitalRead(PURPLE_BUTTON) == LOW? true: false;
  buttonRow[7] = mcp3.digitalRead(BLUE_BUTTON) == LOW? true: false;
  buttonRow[8] = mcp3.digitalRead(GREEN_BUTTON) == LOW? true: false;
  buttonRow[9] = mcp3.digitalRead(YELLOW_BUTTON) == LOW? true: false;
  buttonRow[10] = mcp3.digitalRead(ORANGE_BUTTON) == LOW? true: false;
  buttonRow[11] = mcp3.digitalRead(RED_BUTTON) == LOW? true: false;

  buttonCol[0] = mcp2.digitalRead(BLUE_BUTTON) == LOW? true: false;
  buttonCol[1] = mcp2.digitalRead(PURPLE_BUTTON) == LOW? true: false;
  buttonCol[2] = mcp2.digitalRead(WHITE_BUTTON) == LOW? true: false;
  buttonCol[3] = mcp2.digitalRead(GRAY_BUTTON) == LOW? true: false;
  buttonCol[4] = mcp1.digitalRead(RED_BUTTON) == LOW? true: false;
  buttonCol[5] = mcp1.digitalRead(ORANGE_BUTTON) == LOW? true: false;
  buttonCol[6] = mcp1.digitalRead(YELLOW_BUTTON) == LOW? true: false;
  buttonCol[7] = mcp1.digitalRead(GREEN_BUTTON) == LOW? true: false;
  buttonCol[8] = mcp1.digitalRead(BLUE_BUTTON) == LOW? true: false;
  buttonCol[9] = mcp1.digitalRead(PURPLE_BUTTON) == LOW? true: false;
  buttonCol[10] = mcp1.digitalRead(WHITE_BUTTON) == LOW? true: false;
  buttonCol[11] = mcp1.digitalRead(GRAY_BUTTON) == LOW? true: false;
}

bool fire() {
  Serial.println("FIRE!!!");  
  bool isHit = checkIfIsHit(lastRowPressed, lastColPressed);  
  if(isHit) {
    Serial.println("...HIT!");
    playerBoard[lastRowPressed][lastColPressed] = RED;
    updateShipHitCounts(lastRowPressed, lastColPressed);
  } else {
    Serial.println("...miss");
    playerBoard[lastRowPressed][lastColPressed] = WHITE;
  }
  updateShipRepresentations();  
  return isHit;
}

bool aircraftCarrierIsSunk() {
  return aircraftCarrierHits >= 5;
}
bool battleshipIsSunk() {
  return battleshipHits >= 4;
}
bool cruiser1IsSunk() {
  return cruiser1Hits >= 3;
}
bool cruiser2IsSunk() {
  return cruiser2Hits >= 3;
}
bool defenderIsSunk() {
  return defenderHits >= 2;
}

void updateShipRepresentations() {
  if(aircraftCarrierIsSunk()) {
    for(int i = 0; i < 5; i++) {
      playerBoard[aircraftCarrierRepresentation[i].row][aircraftCarrierRepresentation[i].column] = RED;
    }
    if(!displayedAircraftCarrierSunkMessage) {
      Serial.println("You sunk my aircraft carrier!");
      displayedAircraftCarrierSunkMessage = true;
    }
  }
  if(battleshipIsSunk()) {
    for(int i = 0; i < 4; i++) {
      playerBoard[battleshipRepresentation[i].row][battleshipRepresentation[i].column] = RED;
    }
    if(!displayedBattleshipSunkMessage) {
      Serial.println("You sunk my battleship!");
      displayedBattleshipSunkMessage = true;
    }
  }
  if(cruiser1IsSunk()) {
    for(int i = 0; i < 3; i++) {
      playerBoard[cruiser1Representation[i].row][cruiser1Representation[i].column] = RED;
    }
    if(!displayedCruiser1SunkMessage) {
      Serial.println("You sunk one of my cruisers!");  
      displayedCruiser1SunkMessage = true;
    }
    
  }
  if(cruiser2IsSunk()) {
    for(int i = 0; i < 3; i++) {
      playerBoard[cruiser2Representation[i].row][cruiser2Representation[i].column] = RED;
    }
    if(!displayedCruiser2SunkMessage) {
      Serial.println("You sunk one of my cruisers!");  
      displayedCruiser2SunkMessage = true;
    }
  }
  if(defenderIsSunk()) {
    for(int i = 0; i < 2; i++) {
      playerBoard[defenderRepresentation[i].row][defenderRepresentation[i].column] = RED;
    }
    if(!displayedDefenderSunkMessage) {
      Serial.println("You sunk my defender!");
      displayedDefenderSunkMessage = true;
    }
  }  
}

void updateShipHitCounts(int row, int col) {
  if(isAircraftCarrierHit(row, col)) {
    aircraftCarrierHits++;
  }
  if(isBattleshipHit(row, col)) {
    battleshipHits++;
  }
  if(isCruiser1Hit(row, col)) {
    cruiser1Hits++;
  }
  if(isCruiser2Hit(row, col)) {
    cruiser2Hits++;
  }
  if(isDefenderHit(row, col)) {
    defenderHits++;
  }
}

bool isAircraftCarrierHit(int row, int col) {
  for(int i = 0; i < 5; i++) {
    if(aircraftCarrier[i].row == row && aircraftCarrier[i].column == col) {      
      return true;
    }
  }
  return false;
}
bool isBattleshipHit(int row, int col) {
  for(int i = 0; i < 4; i++) {
    if(battleship[i].row == row && battleship[i].column == col) {
      return true;
    }
  }
  return false;
}
bool isCruiser1Hit(int row, int col) {
  for(int i = 0; i < 3; i++) {
    if(cruiser1[i].row == row && cruiser1[i].column == col) {
      return true;
    }
  }
  return false;
}
bool isCruiser2Hit(int row, int col) {
  for(int i = 0; i < 3; i++) {
    if(cruiser2[i].row == row && cruiser2[i].column == col) {
      return true;
    }
  }
  return false;
}
bool isDefenderHit(int row, int col) {
  for(int i = 0; i < 2; i++) {
    if(defender[i].row == row && defender[i].column == col) {
      return true;
    }
  }
  return false;
}

bool checkIfIsHit(int row, int col) {  
  return isAircraftCarrierHit(row, col) 
     || isBattleshipHit(row, col) 
     || isCruiser1Hit(row, col) 
     || isCruiser2Hit(row, col) 
     || isDefenderHit(row, col);  
}

bool displayOverlays() {
  if(timeOfLastBlinkToggle == 0) {
    timeOfLastBlinkToggle = millis();    
  }
  long currentTime = millis();
  if(currentTime - timeOfLastBlinkToggle > 200) {
    if(overlaysOn) {
      overlaysOn = false;
    } else {
      overlaysOn = true;
    }
    timeOfLastBlinkToggle = millis();
  }
  return overlaysOn;
}

void updateMatrix() {
  matrix.clear();
  for(int i = 0; i < MATRIX_SIZE; i++) {
    for(int j = 0; j < MATRIX_SIZE; j++) {
      matrix.setPixelColor(convertToMatrixPoint(i,j), playerBoard[i][j]);
    }
  }
  if(displayOverlays()) {
    overlayCrossHairs();
    if(gameMode == GAME_OVER_MODE) {
      overlayShips();
    }
  }
  
  matrix.show();
}
void overlayCrossHairs() {
  if(rowIsSelected()) {
    for(int i = 0; i < NUMBER_ROWS_AND_COLUMNS; i++) {
      matrix.setPixelColor(convertToMatrixPoint(lastRowPressed, i), YELLOW);
    }
  }
  if(colIsSelected()) {
    for(int i = 0; i < NUMBER_ROWS_AND_COLUMNS; i++) {
      matrix.setPixelColor(convertToMatrixPoint(i, lastColPressed), YELLOW);
    }
  }
  if(rowIsSelected() && colIsSelected()) {
    matrix.setPixelColor(convertToMatrixPoint(lastRowPressed, lastColPressed), RED);
  }
}
void overlayShips() {
  for(int i = 0; i < 5; i++) {
    matrix.setPixelColor(convertToMatrixPoint(aircraftCarrier[i].row, aircraftCarrier[i].column), BLUE);
  }
  for(int i = 0; i < 4; i++) {
    matrix.setPixelColor(convertToMatrixPoint(battleship[i].row, battleship[i].column), BLUE);
  }
  for(int i = 0; i < 3; i++) {
    matrix.setPixelColor(convertToMatrixPoint(cruiser1[i].row, cruiser1[i].column), BLUE);
    matrix.setPixelColor(convertToMatrixPoint(cruiser2[i].row, cruiser2[i].column), BLUE);
  }
  for(int i = 0; i < 2; i++) {
    matrix.setPixelColor(convertToMatrixPoint(defender[i].row, defender[i].column), BLUE);
  }
}

int convertToMatrixPoint(int i, int j) {
  if(i % 2 == 0) {
    return ((15 - i) * 16) + j;
  } else {
    return ((15 - i) * 16) + (15 - j);    
  }
}
Unknown's avatar

Collene Hansen

I'm a software engineer interested in too many things to list here! This blog includes my thoughts about various subjects -- technology, programming, career, life, electronics, books, and whatever else I feel like writing about.

Submit a comment