#include <Arduino.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// Pins
#define BUTTON_PIN 34
#define BUZZER_PIN 15
// Button timing
#define DEBOUNCE_MS 40
#define LONG_PRESS_MS 2000
// State
unsigned long lastChange = 0;
bool btnLast = false;
bool btnStable = false;
unsigned long pressedAt = 0;
bool isPressed = false;
void beep(int ms = 80) {
tone(BUZZER_PIN, 1200);
delay(ms);
noTone(BUZZER_PIN);
}
void drawDiceFace(int value) {
display.clearDisplay();
int x=28, y=4, s=64;
display.drawRoundRect(x, y, s, s, 6, WHITE);
auto dot = [&](int cx, int cy) { display.fillCircle(cx, cy, 4, WHITE); };
int cx = x + s/2; int cy = y + s/2;
int left = x + s*2/7; int right = x + s*5/7;
int top = y + s*2/7; int bottom= y + s*5/7;
switch (value) {
case 1: dot(cx, cy); break;
case 2: dot(left, top); dot(right, bottom); break;
case 3: dot(left, top); dot(cx, cy); dot(right, bottom); break;
case 4: dot(left, top); dot(right, top); dot(left, bottom); dot(right, bottom); break;
case 5: dot(left, top); dot(right, top); dot(cx, cy); dot(left, bottom); dot(right, bottom); break;
case 6: dot(left, top); dot(right, top); dot(left, cy); dot(right, cy); dot(left, bottom); dot(right, bottom); break;
}
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(6, 54);
display.print("Value: ");
display.print(value);
display.display();
}
void showSplash() {
display.clearDisplay();
display.setTextSize(2);
display.setTextColor(WHITE);
display.setCursor(8, 10);
display.print("DICE");
display.setCursor(8, 34);
display.print("GAME");
display.display();
delay(700);
display.clearDisplay();
display.setTextSize(1);
display.setCursor(8, 22);
display.print("Press button to roll");
display.setCursor(8, 38);
display.print("Long press to reset");
display.display();
}
bool readButtonRaw() { return digitalRead(BUTTON_PIN) == HIGH; }
void updateButton() {
bool now = readButtonRaw();
if (now != btnLast) {
lastChange = millis();
btnLast = now;
}
if (millis() - lastChange > DEBOUNCE_MS) {
if (btnStable != now) {
btnStable = now;
if (btnStable) { pressedAt = millis(); isPressed = true; }
else { isPressed = false; }
}
}
}
bool shortPressTriggered() {
if (!btnStable && pressedAt > 0) {
unsigned long dur = millis() - pressedAt;
if (dur >= 60 && dur < LONG_PRESS_MS) { pressedAt = 0; return true; }
}
return false;
}
bool longPressDetected() {
if (btnStable && isPressed && (millis() - pressedAt >= LONG_PRESS_MS)) {
isPressed = false; pressedAt = 0; return true;
}
return false;
}
void rollAnimation() {
for (int i=0;i<10;i++) {
int v = random(1,7);
drawDiceFace(v);
delay(60 + i*15);
}
}
void setup() {
pinMode(BUTTON_PIN, INPUT);
pinMode(BUZZER_PIN, OUTPUT);
noTone(BUZZER_PIN);
Wire.begin(21,22);
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
display.clearDisplay();
display.display();
randomSeed(analogRead(32) ^ millis());
showSplash();
}
void loop() {
updateButton();
if (longPressDetected()) {
display.clearDisplay();
display.setTextSize(2);
display.setTextColor(WHITE);
display.setCursor(20, 20);
display.print("RESET");
display.display();
beep(120);
delay(400);
showSplash();
}
if (shortPressTriggered()) {
beep(60);
rollAnimation();
int value = random(1,7);
drawDiceFace(value);
}
}