Hi there,
I have made a electronic Catan board game and am using a Arduino Mega to run the board. After completing the board and getting the code all working, I have found after playing the board with some friends that after an hour or so the graphics begin glitching and after a while the program crashes.
My suspicion is that I may have a memory leak in my code and as I am using progmem to store the graphics it begins affecting my repeating graphic before it ultimately crashes.
I will upload my code, it is rather large but I believe the issue is in the loop code or its functions that it calls. I have had to remove alot of the startup functions to reduce the code to this forum's character limit. I also had remove all but one frame of the dice roll animation.
A brief description: The board can support up to 6 players, each player has a button, a LED and a display. There is code in the loop to keep track of the active player. When the active player presses their button a dice roll graphic is played by calling the 'void buildUp' which displays 43 frames loaded in memory with progmem to display the rolling dice graphic. Then a random dice roll is called and displayed. Player finishes their turn and moves to next player.
After around an hour of play the dice roll graphic starts glitching, small at first then progressively worse until the graphic unrecognizable. But the dice roll graphic continues to work fine after the diceroll function completes. the loop also seems to still work fine for a while after it starts glitching but after a short while the loop function starts glitching and showing the wrong player LED and not keeping track of the player well, then the program will crash all together.
Alot of the code is dependent if the board is smlGame or lrgGame, which depends on how many players there are. I have used the board for a few small games and never had the issue until once we played a large game.
Any help in pointing in the right direction on what could be the problem is appreciated.
I am positive that there are many areas where I can improve the code in here, as I am still learning as I go. Any feedback here would be appreciated also.
If you would like to get a visual on the whole setup a link to my github page for it is here
#include <ezButton.h>
#include "FastLED.h"
#include <EEPROM.h>
#define NUM_LEDS 107
#define DATA_PIN 2
#define tileSize 3
#define smlTileRange 19
#define lrgTileRange 30
#define smlPortRange 9
#define lrgPortRange 11
bool lrgGame = false;
bool settler1Roll = true;
bool settler1Turn = false;
bool s2tradeLock = false;
bool gameStart = false;
bool plrSelected = false;
CRGB leds[NUM_LEDS];
CRGB smlCurrentTileColors[smlTileRange];
CRGB lrgCurrentTileColors[lrgTileRange];
CRGB smlCurrentPortColors[smlPortRange];
CRGB lrgCurrentPortColors[lrgPortRange];
byte smlEEPROMTileColors[smlTileRange];
byte lrgEEPROMTileColors[lrgTileRange];
byte smlEEPROMPortColors[smlPortRange];
byte lrgEEPROMPortColors[lrgPortRange];
byte desertTile1;
byte desertTile2;
byte settler1;
byte settler2;
byte settler1Buttcount;
byte plrCount = 0;
byte players[6] = {0,0,0,0,0,0};
byte plrLEDs[6] = {0,1,2,3,4,5};
byte rollCount[11];
byte totalRolls;
byte convertRoll[11];
byte convertResource[5];
byte offsetArray[11];
//byte smlStartTile;
//byte lrgStartTile;
byte gameNumber;
byte resourceCount[5];
byte smlValuesStartTile = 1;
byte lrgValuesStartTile = 1;
long diceOne;
long diceTwo;
const byte BUTTON_NUM = 6;
const byte BUTTON_1_PIN = 4;
const byte BUTTON_2_PIN = 5;
const byte BUTTON_3_PIN = 6;
const byte BUTTON_4_PIN = 7;
const byte BUTTON_5_PIN = 8;
const byte BUTTON_6_PIN = 9;
ezButton buttonArray[] = {
ezButton(BUTTON_1_PIN),
ezButton(BUTTON_2_PIN),
ezButton(BUTTON_3_PIN),
ezButton(BUTTON_4_PIN),
ezButton(BUTTON_5_PIN),
ezButton(BUTTON_6_PIN)
};
// Brick, Wood, Wheat, Ore, Sheep, Desert
CRGB all[7] = {CRGB::Red,CRGB::Green,CRGB::Orange,CRGB::Cyan,CRGB::White,CRGB::Black,CRGB::Purple};
const uint32_t smlTileResource[]PROGMEM = {CRGB::Red,CRGB::Red,CRGB::Red,CRGB::Cyan,CRGB::Cyan,CRGB::Cyan,CRGB::Green,CRGB::Green,CRGB::Green,CRGB::Green,CRGB::Orange,CRGB::Orange,CRGB::Orange,CRGB::Orange,CRGB::White,CRGB::White,CRGB::White,CRGB::White,CRGB::Black};
const uint32_t lrgTileResource[]PROGMEM = {CRGB::Red,CRGB::Red,CRGB::Red,CRGB::Red,CRGB::Red,CRGB::Cyan,CRGB::Cyan,CRGB::Cyan,CRGB::Cyan,CRGB::Cyan,CRGB::Green,CRGB::Green,CRGB::Green,CRGB::Green,CRGB::Green,CRGB::Green,CRGB::Orange,CRGB::Orange,CRGB::Orange,CRGB::Orange,CRGB::Orange,CRGB::Orange,CRGB::White,CRGB::White,CRGB::White,CRGB::White,CRGB::White,CRGB::White,CRGB::Black,CRGB::Black};
const uint32_t smlPortResource[]PROGMEM = {CRGB::Red,CRGB::Cyan,CRGB::Green,CRGB::Orange,CRGB::White,CRGB::Purple,CRGB::Purple,CRGB::Purple,CRGB::Purple};
const uint32_t lrgPortResource[]PROGMEM = {CRGB::Red,CRGB::Cyan,CRGB::Green,CRGB::Orange,CRGB::White,CRGB::White,CRGB::Purple,CRGB::Purple,CRGB::Purple,CRGB::Purple,CRGB::Purple};
byte smlTileValuesArray[18] = {5,2,6,3,8,10,9,12,11,4,8,10,9,4,5,6,3,11};
//const byte smlValuesStartTileArray[] = {20,22,12,3,1,8}; // Tile number (courner) to start the tile values sequence
//const byte smlValuesArray[] = {11,12,9,4,3,6,10,8,11,5,8,10,9,4,3,5,2,6,
// 9,10,8,12,6,5,3,11,3,4,6,4,11,9,2,8,10,5,
// 8,3,6,10,5,4,2,9,6,9,5,12,3,11,10,11,4,8,
// 6,2,5,3,4,9,10,8,5,11,8,10,6,3,4,9,12,11,
// 5,10,8,2,9,11,4,6,4,3,11,3,5,6,12,8,10,9,
// 8,4,11,10,11,3,12,5,9,6,9,2,4,5,10,6,3,8};
byte lrgTileValuesArray[28] = {2,5,4,6,3,9,8,11,11,10,6,3,8,4,8,10,11,12,10,5,4,9,5,9,12,3,2,6};
//const byte lrgValuesStartTileArray[] = {28,30,18,3,1,13}; // Tile number (courner) to start the tile values sequence
//const byte lrgValuesArray[] = {6,10,11,3,5,9,11,8,9,4,8,4,12,6,5,9,8,3,2,10,3,10,11,12,6,2,5,4,
// 11,11,8,10,9,4,9,6,5,5,3,3,9,6,10,6,8,12,2,12,4,4,3,11,5,8,10,2,
// 9,3,6,8,5,10,4,11,4,6,12,5,11,9,2,11,2,10,5,3,10,6,9,12,8,3,8,4,
// 4,5,2,6,12,11,10,3,10,2,3,8,9,5,6,12,4,8,4,9,8,11,9,5,3,11,10,6,
// 2,10,8,5,11,3,4,4,12,2,12,8,6,10,6,9,3,3,5,5,6,9,4,9,10,8,11,11,
// 4,8,3,8,12,9,6,10,3,5,10,2,11,2,9,11,5,12,6,4,11,4,10,5,8,6,3,9};
byte smlCurrentTileLEDs[57];
const byte smlTileLEDsArray[]PROGMEM = { //Defines Tile order depending on start tile of Tile Values
8,9,16, 10,11,15, 12,13,14, 24,25,26, 38,39,41, 55,56,60, 71,72,77, 69,70,78, 67,68,79, 49,50,63, 30,31,45, 18,19,29, 20,21,28, 22,23,27, 36,37,42, 53,54,61, 51,52,62, 32,33,44, 34,35,43,
12,13,14, 24,25,26, 38,39,41, 55,56,60, 71,72,77, 69,70,78, 67,68,79, 49,50,63, 30,31,45, 18,19,29, 8,9,16, 10,11,15, 22,23,27, 36,37,42, 53,54,61, 51,52,62, 32,33,44, 20,21,28, 34,35,43,
38,39,41, 55,56,60, 71,72,77, 69,70,78, 67,68,79, 49,50,63, 30,31,45, 18,19,29, 8,9,16, 10,11,15, 12,13,14, 24,25,26, 36,37,42, 53,54,61, 51,52,62, 32,33,44, 20,21,28, 22,23,27, 34,35,43,
71,72,77, 69,70,78, 67,68,79, 49,50,63, 30,31,45, 18,19,29, 8,9,16, 10,11,15, 12,13,14, 24,25,26, 38,39,41, 55,56,60, 53,54,61, 51,52,62, 32,33,44, 20,21,28, 22,23,27, 36,37,42, 34,35,43,
67,68,79, 49,50,63, 30,31,45, 18,19,29, 8,9,16, 10,11,15, 12,13,14, 24,25,26, 38,39,41, 55,56,60, 71,72,77, 69,70,78, 51,52,62, 32,33,44, 20,21,28, 22,23,27, 36,37,42, 53,54,61, 34,35,43,
30,31,45, 18,19,29, 8,9,16, 10,11,15, 12,13,14, 24,25,26, 38,39,41, 55,56,60, 71,72,77, 69,70,78, 67,68,79, 49,50,63, 32,33,44, 20,21,28, 22,23,27, 36,37,42, 53,54,61, 51,52,62, 34,35,43
};
byte lrgCurrentTileLEDs[90];
const byte lrgTileLEDsArray[]PROGMEM = { //Defines Tile order depending on start tile of Tile Values
8,9,16, 10,11,15, 12,13,14, 24,25,26, 38,39,41, 57,58,59, 73,74,76, 88,89,91, 100,101,102, 98,99,103, 96,97,104, 82,83,94, 65,66,80, 47,48,64, 30,31,45, 18,19,29, 20,21,28, 22,23,27, 36,37,42, 55,56,60, 71,72,77, 86,87,92, 84,85,93, 67,68,79, 49,50,63, 32,33,44, 34,35,43, 53,54,61, 69,70,78, 51,52,62,
12,13,14, 24,25,26, 38,39,41, 57,58,59, 73,74,76, 88,89,91, 100,101,102, 98,99,103, 96,97,104, 82,83,94, 65,66,80, 47,48,64, 30,31,45, 18,19,29, 8,9,16, 10,11,15, 22,23,27, 36,37,42, 55,56,60, 71,72,77, 86,87,92, 84,85,93, 67,68,79, 49,50,63, 32,33,44, 20,21,28, 34,35,43, 53,54,61, 69,70,78, 51,52,62,
57,58,59, 73,74,76, 88,89,91, 100,101,102, 98,99,103, 96,97,104, 82,83,94, 65,66,80, 47,48,64, 30,31,45, 18,19,29, 8,9,16, 10,11,15, 12,13,14, 24,25,26, 38,39,41, 55,56,60, 71,72,77, 86,87,92, 84,85,93, 67,68,79, 49,50,63, 32,33,44, 20,21,28, 22,23,27, 36,37,42, 53,54,61, 69,70,78, 51,52,62, 34,35,43,
100,101,102, 98,99,103, 96,97,104, 82,83,94, 65,66,80, 47,48,64, 30,31,45, 18,19,29, 8,9,16, 10,11,15, 12,13,14, 24,25,26, 38,39,41, 57,58,59, 73,74,76, 88,89,91, 86,87,92, 84,85,93, 67,68,79, 49,50,63, 32,33,44, 20,21,28, 22,23,27, 36,37,42, 55,56,60, 71,72,77, 69,70,78, 51,52,62, 34,35,43, 53,54,61,
96,97,104, 82,83,94, 65,66,80, 47,48,64, 30,31,45, 18,19,29, 8,9,16, 10,11,15, 12,13,14, 24,25,26, 38,39,41, 57,58,59, 73,74,76, 88,89,91, 100,101,102, 98,99,103, 84,85,93, 67,68,79, 49,50,63, 32,33,44, 20,21,28, 22,23,27, 36,37,42, 55,56,60, 71,72,77, 86,87,92, 69,70,78, 51,52,62, 34,35,43, 53,54,61,
47,48,64, 30,31,45, 18,19,29, 8,9,16, 10,11,15, 12,13,14, 24,25,26, 38,39,41, 57,58,59, 73,74,76, 88,89,91, 100,101,102, 98,99,103, 96,97,104, 82,83,94, 65,66,80, 49,50,63, 32,33,44, 20,21,28, 22,23,27, 36,37,42, 55,56,60, 71,72,77, 86,87,92, 84,85,93, 67,68,79, 51,52,62, 34,35,43, 53,54,61, 69,70,78
};
const byte lrgPortLEDs[]PROGMEM = {6,7,17,40,46,75,81,90,95,105,106};
const byte smlPortLEDs[]PROGMEM = {6,7,17,40,46,57,65,88,85};
bool arrayIncludeElement(int randArray[], int input, int range) { //checks if random number is already used in an array, i think?
for (int i = 0; i < range; i++) {
if (randArray[i] == input) {
return true;
}
}
return false;
}
//------------------------------------------------------int Buzzer-----------------------------------------------------
#include "pitches.h"
const int buzzer = 3;
int songofstorms[] = {
NOTE_D4,4, NOTE_A4,4, NOTE_A4,4,
REST,8, NOTE_E4,8, NOTE_B4,2,
NOTE_F4,4, NOTE_C5,4, NOTE_C5,4,
REST,8, NOTE_E4,8, NOTE_B4,2,
NOTE_D4,4, NOTE_A4,4, NOTE_A4,4,
REST,8, NOTE_E4,8, NOTE_B4,2,
NOTE_F4,4, NOTE_C5,4, NOTE_C5,4,
REST,8, NOTE_E4,8, NOTE_B4,2,
NOTE_D4,8, NOTE_F4,8, NOTE_D5,2,
NOTE_D4,8, NOTE_F4,8, NOTE_D5,2,
NOTE_E5,-4, NOTE_F5,8, NOTE_E5,8, NOTE_E5,8,
NOTE_E5,8, NOTE_C5,8, NOTE_A4,2,
NOTE_A4,4, NOTE_D4,4, NOTE_F4,8, NOTE_G4,8,
NOTE_A4,-2,
NOTE_A4,4, NOTE_D4,4, NOTE_F4,8, NOTE_G4,8,
NOTE_E4,-2,
NOTE_D4,8, NOTE_F4,8, NOTE_D5,2,
NOTE_D4,8, NOTE_F4,8, NOTE_D5,2,
NOTE_E5,-4, NOTE_F5,8, NOTE_E5,8, NOTE_E5,8,
NOTE_E5,8, NOTE_C5,8, NOTE_A4,2,
NOTE_A4,4, NOTE_D4,4, NOTE_F4,8, NOTE_G4,8,
NOTE_A4,2, NOTE_A4,4,
NOTE_D4,1,
};
int tempo = 120;
int notes = sizeof(songofstorms) / sizeof(songofstorms[0]) / 2;
int wholenote = (60000 * 4) / tempo;
int divider = 0, noteDuration = 0;
//------------------------------------------------------int Display-----------------------------------------------------
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_ADDRESS 0x3C
Adafruit_SSD1306 display(128, 64, &Wire, -1);
const unsigned char PROGMEM Dice0 [] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
const unsigned char PROGMEM Dice1 [] = { };
const unsigned char PROGMEM Dice2 [] = { };
const unsigned char PROGMEM Dice3 [] = { };
const unsigned char PROGMEM Dice4 [] = { };
const unsigned char PROGMEM Dice5 [] = { };
const unsigned char PROGMEM Dice6 [] = { };
const unsigned char PROGMEM Dice7 [] = { };
const unsigned char PROGMEM Dice8 [] = { };
const unsigned char PROGMEM Dice9 [] = { };
const unsigned char PROGMEM Dice10 [] = { };
const unsigned char PROGMEM Dice11 [] = { };
const unsigned char PROGMEM Dice12 [] = { };
const unsigned char PROGMEM Dice13 [] = { };
const unsigned char PROGMEM Dice14 [] = { };
const unsigned char PROGMEM Dice15 [] = { };
const unsigned char PROGMEM Dice16 [] = { };
const unsigned char PROGMEM Dice17 [] = { };
const unsigned char PROGMEM Dice18 [] = { };
const unsigned char PROGMEM Dice19 [] = { };
const unsigned char PROGMEM Dice20 [] = { };
const unsigned char PROGMEM Dice21 [] = { };
const unsigned char PROGMEM Dice22 [] = { };
const unsigned char PROGMEM Dice23 [] = { };
const unsigned char PROGMEM Dice24 [] = { };
const unsigned char PROGMEM Dice25 [] = { };
const unsigned char PROGMEM Dice26 [] = { };
const unsigned char PROGMEM Dice27 [] = { };
const unsigned char PROGMEM Dice28 [] = { };
const unsigned char PROGMEM Dice29 [] = { };
const unsigned char PROGMEM Dice30 [] = { };
const unsigned char PROGMEM Dice31 [] = { };
const unsigned char PROGMEM Dice32 [] = { };
const unsigned char PROGMEM Dice33 [] = { };
const unsigned char PROGMEM Dice34 [] = { };
const unsigned char PROGMEM Dice35 [] = { };
const unsigned char PROGMEM Dice36 [] = { };
const unsigned char PROGMEM Dice37 [] = { };
const unsigned char PROGMEM Dice38 [] = { };
const unsigned char PROGMEM Dice39 [] = { };
const unsigned char PROGMEM Dice40 [] = { };
const unsigned char PROGMEM Dice41 [] = { };
const unsigned char PROGMEM Dice42 [] = { };
const unsigned char PROGMEM Dice43 [] = { };
const uint8_t *dice[44] = {Dice0,Dice1,Dice2,Dice3,Dice4,Dice5,Dice6,Dice7,Dice8,Dice9,Dice10,Dice11,Dice12,Dice13,Dice14,Dice15,Dice16,Dice17,Dice18,Dice19,Dice20,Dice21,Dice22,Dice23,Dice24,Dice25,Dice26,Dice27,Dice28,Dice29,Dice30,Dice31,Dice32,Dice33,Dice34,Dice35,Dice36,Dice37,Dice38,Dice39,Dice40,Dice41,Dice42,Dice43};
const unsigned char PROGMEM robber [] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x10, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x10, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x18, 0x00, 0x78, 0x00, 0x00, 0x00, 0x38, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x38, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x78, 0x00, 0x3F, 0xC0, 0x00, 0x01, 0xF8, 0x00, 0x3F, 0xFF, 0x40, 0x1F, 0xB8, 0x00, 0x1F, 0xFF, 0xFF, 0xFE, 0x70, 0x00, 0xCF, 0xFF, 0xFD, 0x01, 0xF0, 0x00, 0xE7, 0xFF, 0xBF, 0xFF, 0xF0, 0x02, 0x73, 0xFF, 0xFF, 0xFF, 0xE0, 0x03, 0x3E, 0xFF, 0xDF, 0xFD, 0xE0, 0x01, 0x8F, 0xFF, 0xE9, 0xED, 0xC0, 0x00, 0xE7, 0xFF, 0xF1, 0xF3, 0x80, 0x00, 0xF7, 0xFF, 0xFF, 0xFF, 0x80, 0x04, 0x7F, 0xFF, 0x16, 0x87, 0x00, 0x07, 0x1F, 0xFF, 0x00, 0x0E, 0x00, 0x03, 0x9F, 0xD4, 0x00, 0x1C, 0x00, 0x03, 0xFF, 0xF0, 0x00, 0x38, 0x00, 0x01, 0xFF, 0xA8, 0x00, 0xE0, 0x00, 0x00, 0xFF, 0x80, 0x03, 0x80, 0x00, 0x01, 0xFF, 0xE0, 0x1E, 0x00, 0x00, 0x01, 0xFE, 0x00, 0x7C, 0x00, 0x00, 0x03, 0xFE, 0x03, 0xE0, 0x00, 0x00, 0x03, 0xF6, 0x1F, 0x80, 0x00, 0x00, 0x03, 0xF8, 0x7C, 0x00, 0x00, 0x00, 0x03, 0xE9, 0xF0, 0x00, 0x00, 0x00, 0x03, 0xF3, 0xC0, 0x00, 0x00, 0x00, 0x07, 0xC7, 0x00, 0x00, 0x00, 0x00, 0x03, 0xCC, 0x00, 0x00, 0x00, 0x00, 0x03, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x03, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x03, 0xB0, 0x00, 0x00, 0x00, 0x00, 0x01, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x01, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
//------------------------------------------------------beep-----------------------------------------------------
void beep(){
tone(buzzer,NOTE_G4,35);
delay(35);
tone(buzzer,NOTE_G5,35);
delay(35);
tone(buzzer,NOTE_G6,35);
delay(35);
noTone(buzzer);
}
//------------------------------------------------------buildUp-----------------------------------------------------
void buildUp() { //rolling dice graphic
for (int i=0; i<44; i++) {
display.clearDisplay();
display.drawBitmap(12, 17,dice[i],104,48, 1);
display.display();
delay(20);
}
delay(500);
}
//------------------------------------------------------rollDice-----------------------------------------------------
void rollDice() {
//Clear LEDs
if (lrgGame == false) {
for (int i = 0; i < smlTileRange; i++) {
setTile(i+1, CRGB::Black, false);
}
}
else {
for (int i = 0; i < lrgTileRange; i++) {
setTile(i+1, CRGB::Black, false);
}
}
randomSeed(analogRead(1));
FastLED.show();
delay(1000);
buildUp();
diceOne = random(1, 7);
diceOne = random(1, 7);
diceTwo = random(1, 7);
diceTwo = random(1, 7);
display.clearDisplay();
display.setTextSize(2);
display.setTextColor(WHITE); // Draw text
display.setCursor(0, 0); // Start at top-left corner
display.cp437(true); // Use full 256 char 'Code Page 437' font
display.print("ROLLED:");
display.setCursor(85, 0);
display.print(diceOne);
display.setCursor(100, 0);
display.print("&");
display.setCursor(115, 0);
display.println(diceTwo);
int roll = diceOne + diceTwo;
display.setTextSize(7);
if (roll > 9) {
display.setCursor(24, 16);
display.print("1");
display.setCursor(60, 16);
display.print(roll-10);
display.display();
}
else {
display.setCursor(44, 16);
display.println(roll);
display.display();
}
delay(1000);
//If 7 is Rolled
if (roll == 7) {
display.setTextSize(2);
display.clearDisplay();
display.setCursor(4, 0);
display.println("THE ROBBER");
display.drawBitmap(0, 17, robber, 48, 48, 1);
display.display();
display.startscrollright(2,7);
}
//Show only tiles with that roll
//SMALL GAME
if (lrgGame == false) {
if (roll == 7){ // Flash Board Red 3 times for robber //I might change for LED display
for (int a = 0; a < 4; a++) {
for (int i = 0; i < smlTileRange; i++) {
setTile(i+1, CRGB::Red, false);
}
FastLED.show();
delay(1000);
if (a < 3) {
for (int i = 0; i < smlTileRange; i++) {
setTile(i+1, CRGB::Black, false);
}
}
FastLED.show();
delay(1000);
}
}
else { //Flash tiles equal to roll
for (int a = 0; a < 4; a++) {
int j = 0; //Desert tile counter
for (int i = 0; i < smlTileRange; i++) {
if (smlCurrentTileColors[i] == all[5]) { //If Desert tile found skip loop and add to desert tile counter
i++;
j++;
}
if (smlTileValuesArray[i-j] == roll) { //If values array [loop minus desert counter] is equal to roll, flash the loop tile (i)
setTile(i+1, CRGB::White, false);
}
}
FastLED.show();
delay(1000);
j = 0;
if (a <3) {
for (int i = 0; i < smlTileRange; i++) {
if (smlCurrentTileColors[i] == all[5]) {
i++;
j++;
}
if (smlTileValuesArray[i-j] == roll){
setTile(i+1, CRGB::Black, false);
}
}
}
FastLED.show();
delay(1000);
}
}
int j = 0; //Desert tile counter
for (int i = 0; i < smlTileRange; i++) {
if (smlCurrentTileColors[i] == all[5]) { //If Desert tile found skip loop and add to desert tile counter
i++;
j++;
}
if (smlTileValuesArray[i-j] == roll) { //If values array [loop minus desert counter] is equal to roll, add to resource counters
if (smlCurrentTileColors[i] == all[0]){ //brick
resourceCount[3]++;;
}
if (smlCurrentTileColors[i] == all[1]){ //wood
resourceCount[2]++;
}
if (smlCurrentTileColors[i] == all[2]){ //wheat
resourceCount[1]++;;
}
if (smlCurrentTileColors[i] == all[3]){ //ore
resourceCount[4]++;;
}
if (smlCurrentTileColors[i] == all[4]){ //sheepies
resourceCount[0]++;
}
}
}
}
else { //LARGE GAME
if (roll == 7){ // Flash Board Red 3 times for robber //I might change for LED display
for (int a = 0; a < 4; a++) {
for (int i = 0; i < lrgTileRange; i++) {
setTile(i+1, CRGB::Red, false);
}
FastLED.show();
delay(1000);
if (a < 3) {
for (int i = 0; i < lrgTileRange; i++) {
setTile(i+1, CRGB::Black, false);
}
}
FastLED.show();
delay(1000);
}
}
else { //Flash tiles equal to roll
for (int a = 0; a < 4; a++) {
// Serial.println("loop start");
int j = 0; //Desert tile counter
for (int i = 0; i < lrgTileRange; i++) {
if (lrgCurrentTileColors[i] == all[5]) { //If Desert tile found skip loop and add to desert tile counter
i++;
j++;
}
if (lrgTileValuesArray[i-j] == roll) { //If values array [loop minus desert counter] is equal to roll, flash the loop tile (i)
setTile(i+1, CRGB::White, false);
}
}
FastLED.show();
delay(1000);
j = 0;
if (a < 3) {
for (int i = 0; i < lrgTileRange; i++) {
if (lrgCurrentTileColors[i] == all[5]) {
i++;
j++;
}
if (lrgTileValuesArray[i-j] == roll){
setTile(i+1, CRGB::Black, false);
}
}
}
FastLED.show();
delay(1000);
}
}
int j = 0; //Desert tile counter
for (int i = 0; i < lrgTileRange; i++) {
if (lrgCurrentTileColors[i] == all[5]) { //If Desert tile found skip loop and add to desert tile counter
i++;
j++;
}
if (lrgTileValuesArray[i-j] == roll) { //If values array [loop minus desert counter] is equal to roll, add to resource counters
if (lrgCurrentTileColors[i] == all[0]){ //brick
resourceCount[3]++;;
}
if (lrgCurrentTileColors[i] == all[1]){ //wood
resourceCount[2]++;
}
if (lrgCurrentTileColors[i] == all[2]){ //wheat
resourceCount[1]++;;
}
if (lrgCurrentTileColors[i] == all[3]){ //ore
resourceCount[4]++;;
}
if (lrgCurrentTileColors[i] == all[4]){ //sheepies
resourceCount[0]++;
}
}
}
}
for (int i=0; i<=11; i++) { // Add roll to rollCount
if (roll == i+2) {
rollCount[i] ++;
// Serial.print(rollCount[i]);
// Serial.print(",");
}
}
// Serial.println();
totalRolls ++;
// Serial.print("Sheep =");
// Serial.println(resourceCount[0]);
// Serial.print("Wheat =");
// Serial.println(resourceCount[1]);
// Serial.print("Wood =");
// Serial.println(resourceCount[2]);
// Serial.print("Brick =");
// Serial.println(resourceCount[3]);
// Serial.print("Ore =");
// Serial.println(resourceCount[4]);
// Serial.println("--------------");
}
//------------------------------------------------------tradeLock-----------------------------------------------------
void tradeLock() {
display.clearDisplay();
display.setTextSize(2);
display.setTextColor(WHITE);
display.setCursor(6, 0);
display.cp437(true);
display.print("Settler 2");
display.setTextSize(3);
display.setCursor(20, 16);
display.println("Trade");
display.setCursor(20, 40);
display.println("Locked");
display.display();
}
//------------------------------------------------------ready2Roll-----------------------------------------------------
void ready2Roll() {
// Serial.println("readyToRoll - Start");
display.clearDisplay(); // Clear the buffer.
display.setTextSize(2);
display.setTextColor(WHITE); // Draw text
display.setCursor(6, 0); // Start at top-left corner
display.cp437(true); // Use full 256 char 'Code Page 437' font
display.println("Settler 1");
display.println("Ready to"); //will need centering
display.setTextSize(4);
display.setCursor(30, 32);
display.println("ROLL"); //will need centering
display.display();
// Serial.println("readyToRoll - End");
}
//------------------------------------------------------settlerPlus-----------------------------------------------------
int settlerPlus (int settler) {
settler ++;
for (settler; settler<7; settler++) {
if (settler == 6) {
settler = 0;
}
// if (players[settler] == 0) {
// }
if (players[settler] == 1) {
break;
}
}
return (settler);
}
//-----------------------------------------------------plrSelect------------------------------------------------------
void plrSelect() {
// Serial.println("plrSelect - Start");
int i;
int r;
while (1) {
delay(100);
r=random(0,7); //find start position
r=random(0,7); //find start position
if (players[r] == 1){
i = r;
break;
}
}
// Serial.print("start poss = ");
// Serial.println(r);
int tt = 30; //green LED on timer
display.clearDisplay(); // Clear the buffer.
display.setTextSize(2);
display.setTextColor(WHITE); // Draw text
display.setCursor(0,0); // Start at top-left corner //will need centering?
display.cp437(true); // Use full 256 char 'Code Page 437' font
display.setTextWrap(false);
display.println(">>>>>>>>>>>>>>>>");
display.println(" Spinning");
display.setCursor(6,32);
display.println("for First");
display.println(" Player");
display.display();
display.startscrollright(0,1);
delay(1000);
plrSelected = true;
// Loop for number of initial rotations
for (int l=0; l < 20; l++) {
for (i; i<6; i++) {
if (players[i] == 1) {
leds[plrLEDs[i]] = CRGB::Green;
tone(buzzer,NOTE_G6,35);
// Serial.print(i);
FastLED.show();
delay(tt);
leds[plrLEDs[i]] = CRGB::Black;
FastLED.show();
delay(tt);
}
}
i=0;
}
i = r;
int a = 0;
for (i; i<7; i++) { // Loop with slow down multiplyer
if (i == 6) {
i=0;
}
if (players[i] == 1) {
leds[plrLEDs[i]] = CRGB::Green;
tone(buzzer,NOTE_G6,35);
FastLED.show();
delay(tt);
leds[plrLEDs[i]] = CRGB::Black;
FastLED.show();
delay(30);
tt *= 1.15; //slow down time multiplier
if (tt > 1500) {
// a = i;
break;
}
}
}
for (a; a < 3; a++) {
delay(200);
leds[plrLEDs[i]] = CRGB::Green;
tone(buzzer,NOTE_D8,250);
FastLED.show();
delay(500);
if (a < 2){
leds[plrLEDs[i]] = CRGB::Black;
FastLED.show();
delay(250);
}
}
// Serial.print("s1 = ");
// Serial.println(i);
settler1 = i;
int s2 = 0;
for (int i = settler1; i < 6; i++) { //Define Settler2 Player
s2 += players[i];
if (s2 == 4) {
settler2 = i;
break;
}
if (i == 5) {
i = -1;
}
}
display.stopscroll();
if (lrgGame == true) {
s2tradeLock = true;
}
delay(1000);
ready2Roll();
// Serial.println("plrSelect - End");
}
//------------------------------------------------------loop-----------------------------------------------------
void loop() {
// SETTLER 1
buttonArray[settler1].loop();
if (buttonArray[settler1].isPressed()) {
beep();
int t=0;
unsigned long previousMillis = 0;
while (t <= 10) { // Check for 10 second hold for end game
unsigned long currentMillis = millis();
const int interval = 1000;
if (currentMillis - previousMillis >= interval) {
previousMillis = currentMillis;
(t++);
}
if (t == 10) {
endGameStats();
}
buttonArray[settler1].loop();
if (buttonArray[settler1].isReleased()) { //If Settler 1 releases button, Roll Dice
break;
}
}
if (settler1Roll == true) { //Roll dice if Settler 1 Roll = true
rollDice();
settler1Roll = false;
settler1Turn = true;
}
else if (settler1Turn == true) { //or if Settler 1 has already rolled
leds[settler1] = CRGB::Black;
settler1 = settlerPlus(settler1);
if (s2tradeLock == true) { //pass to settler 2 if tradelock on
leds[settler1] = CRGB::Orange;
leds[settler2] = CRGB::Green;
settler1Turn = false;
tradeLock();
}
else { //or pass to next player if trade lock is off
settler1Roll = true;
settler1Turn = false;
display.stopscroll();
display.clearDisplay();
FastLED.clear();
FastLED.show();
if (lrgGame == true) {
s2tradeLock = true;
leds[settler2] = CRGB::Orange;
}
ready2Roll();
leds[settler1] = CRGB::Green;
}
}
FastLED.show();
}
// SETTLER 2
if (lrgGame == true) {
buttonArray[settler2].loop();
if (buttonArray[settler2].isPressed()) { //settler 2 press button
beep();
leds[settler2] = CRGB::Black;
settler2 = settlerPlus(settler2);
if (settler1Roll == true or settler1Turn == true) { //if settler 1 roll/turn just release tradelock
s2tradeLock = false;
}
else { //else pass turn to next player
settler1Roll = true;
ready2Roll();
display.stopscroll();
FastLED.clear();
leds[settler1] = CRGB::Green;
leds[settler2] = CRGB::Orange;
}
FastLED.show();
}
}
}