#include <Streaming.h>
#include <SPI.h>
#include <Adafruit_ILI9341.h>
#include <Button_SL.hpp>
Print &cout {Serial};
class Player {
public:
Player(unsigned int color) : color {color} {}
void setDiceValue(byte value) {
diceValue = value;
sum += value;
}
byte getDiceValue() const { return diceValue; }
unsigned int getColor() const { return color; }
unsigned int getSum() const { return sum; }
private:
unsigned int color;
byte diceValue;
unsigned int sum;
};
struct DicePip {
unsigned int xPos;
unsigned int yPos;
unsigned int radius;
};
// Display coordinates. Must be adjusted for the respective display resolution.
constexpr DicePip DICE_PIPS[] {
{280, 40, 20}, // dot top right
{280, 200, 20}, // dot bottom right
{160, 40, 20}, // dot top middle
{160, 120, 20}, // dot middle middle (1)
{160, 200, 20}, // dot bottom middle
{40, 40, 20}, // dot top left
{40, 200, 20} // dot bottom left
};
// Maps the current number of "dice pip count" to the drawing coordinates in the DicePip structure.
constexpr byte PIP_VALS[6][6] {
{3}, // 1
{0, 6}, // 2
{0, 3, 6}, // 3
{0, 1, 5, 6}, // 4
{0, 1, 3, 5, 6}, // 5
{0, 1, 2, 4, 5, 6} // 6
};
constexpr byte MIN_DICE_VALUE {1};
constexpr byte MAX_DICE_VALUE {6};
constexpr byte MIN_ANIMATION_COUNT {6};
constexpr byte MAX_ANIMATION_COUNT {24};
constexpr byte ANIMATIONDELAY_MS {50};
constexpr unsigned int BG_COLOR {ILI9341_BLACK};
constexpr unsigned int TXT_COLOR {ILI9341_WHITE};
constexpr unsigned int COLORS[4] {ILI9341_RED, ILI9341_BLUE, ILI9341_YELLOW, ILI9341_GREEN};
const char *START_TEXT[3] {"Start", "->", "Taste"};
byte BUTTON_PIN {2};
constexpr byte PIN_ADC {A0};
Adafruit_ILI9341 tft = Adafruit_ILI9341(9, 10);
// Initialize the player objects for the four possible player colours
Player player[4] {ILI9341_RED, ILI9341_BLUE, ILI9341_YELLOW, ILI9341_GREEN};
// The playerSelect variable determines which player colors have been selected
// and in which order they are played.
byte playerSelect[] {0, 1, 3}; // Init for three player (red, blue, green)
// byte playerSelect[] {0, 2}; // Init for two player (red,yellow)
// byte playerSelect[] {0, 1, 2, 3}; // Init for four player (all colors)
constexpr byte MAX_PLAYER {sizeof(playerSelect) / sizeof(playerSelect[0])};
// Bounce initialisieren
Btn::Button diceBtn(BUTTON_PIN);
void deletePips() {
const byte idx {MAX_DICE_VALUE-1};
tft.fillCircle(DICE_PIPS[PIP_VALS[0][0]].xPos, DICE_PIPS[PIP_VALS[0][0]].yPos, DICE_PIPS[PIP_VALS[0][0]].radius,
BG_COLOR);
for (byte i = 0; i < MAX_DICE_VALUE; ++i) {
tft.fillCircle(DICE_PIPS[PIP_VALS[idx][i]].xPos, DICE_PIPS[PIP_VALS[idx][i]].yPos,
DICE_PIPS[PIP_VALS[idx][i]].radius, BG_COLOR);
}
}
void drawPips(byte number, unsigned int color, bool doShow = true) {
byte idx = number - 1;
for (byte i = 0; i < number; ++i) {
tft.fillCircle(DICE_PIPS[PIP_VALS[idx][i]].xPos, DICE_PIPS[PIP_VALS[idx][i]].yPos,
DICE_PIPS[PIP_VALS[idx][i]].radius, color);
}
delay(100);
if (false == doShow) { deletePips(); }
}
void showFrame(unsigned int color) {
tft.drawRoundRect(3, 2, tft.width() - 6, tft.height() - 6, 10, color);
tft.drawRoundRect(5, 4, tft.width() - 10, tft.height() - 10, 10, color);
}
void showHint(unsigned int yPos, unsigned int yOffset) {
showFrame(TXT_COLOR);
tft.setCursor(0, 0);
tft.setTextColor(TXT_COLOR);
tft.setTextSize(4);
for (auto item : START_TEXT) {
tft.setCursor((tft.width() - (strlen(item) * 24)) / 2, yPos);
tft.println(item);
yPos += yOffset;
}
}
void setup() {
Serial.begin(115200);
diceBtn.begin(); // Assign the button to the bounce object
tft.begin();
tft.setRotation(1);
showHint(50, 50); // yPos, yOffset of Text
}
void doDice(Player &player) {
byte diceValue {MIN_DICE_VALUE};
randomSeed(analogRead(PIN_ADC));
byte animationCount = static_cast<byte>(random(MIN_ANIMATION_COUNT, (MAX_ANIMATION_COUNT + 1)));
for (byte i = 0; i < animationCount; ++i) { // Dice effect: Display random numbers in quick succession.
drawPips(diceValue, player.getColor(), false);
diceValue = (diceValue < MAX_DICE_VALUE) ? diceValue + 1 : 1;
delay(ANIMATIONDELAY_MS);
}
player.setDiceValue(static_cast<byte>(random(MIN_DICE_VALUE, (MAX_DICE_VALUE + 1))));
drawPips(player.getDiceValue(), player.getColor(), true);
}
void loop() {
static byte index {0}; // Index to the player
static bool isStarted {false};
if (diceBtn.tick()) {
if (false == isStarted) {
tft.fillRect(50, 50, tft.width() - 100, tft.height() - 100, BG_COLOR); // Clear Screen
showFrame(player[playerSelect[index]].getColor());
isStarted = true;
delay(1000);
} else {
deletePips();
}
doDice(player[playerSelect[index]]);
cout << F("Player: ") << index + 1 << F(" ") << F("Pips: ") <<
player[playerSelect[index]].getDiceValue() << F(" ") << F("Pip sum: ") <<
_WIDTH(player[playerSelect[index]].getSum(),5) << endl;
// If a six is rolled, do not change Player.
if (player[playerSelect[index]].getDiceValue() != MAX_DICE_VALUE) {
index = (index + 1) % MAX_PLAYER;
if (0 == index) { cout << F("--------------------------------\n"); }
}
showFrame(player[playerSelect[index]].getColor());
}
}