Added puzzle color Remember
This commit is contained in:
parent
7ad21cd1d4
commit
f1f17cf754
5
terminal/puzzle_colorRemember/.gitignore
vendored
Normal file
5
terminal/puzzle_colorRemember/.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
.pio
|
||||||
|
.vscode/.browse.c_cpp.db*
|
||||||
|
.vscode/c_cpp_properties.json
|
||||||
|
.vscode/launch.json
|
||||||
|
.vscode/ipch
|
||||||
17
terminal/puzzle_colorRemember/platformio.ini
Normal file
17
terminal/puzzle_colorRemember/platformio.ini
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
; PlatformIO Project Configuration File
|
||||||
|
;
|
||||||
|
; Build options: build flags, source filter
|
||||||
|
; Upload options: custom upload port, speed and extra flags
|
||||||
|
; Library options: dependencies, extra library storages
|
||||||
|
; Advanced options: extra scripting
|
||||||
|
;
|
||||||
|
; Please visit documentation for the other options and examples
|
||||||
|
; https://docs.platformio.org/page/projectconf.html
|
||||||
|
|
||||||
|
[env:nanoatmega328new]
|
||||||
|
platform = atmelavr
|
||||||
|
board = nanoatmega328new
|
||||||
|
framework = arduino
|
||||||
|
lib_deps =
|
||||||
|
adafruit/Adafruit NeoPixel@^1.15.2
|
||||||
|
robtillaart/PCF8575@^0.2.4
|
||||||
327
terminal/puzzle_colorRemember/src/main.cpp
Normal file
327
terminal/puzzle_colorRemember/src/main.cpp
Normal file
@ -0,0 +1,327 @@
|
|||||||
|
|
||||||
|
// ================== Projekt: Modul 2 ==================
|
||||||
|
// SPIELMECHANIK – mit Gewinnanimation + Gewinnsignal
|
||||||
|
//
|
||||||
|
// Fix integriert:
|
||||||
|
// - zeitbasierte Entprellung pro Taster
|
||||||
|
// - verhindert Mehrfachregistrierung eines einzelnen Tastendrucks
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <Wire.h>
|
||||||
|
#include <PCF8575.h>
|
||||||
|
#include <Adafruit_NeoPixel.h>
|
||||||
|
|
||||||
|
// ------------------ Hardware ------------------
|
||||||
|
|
||||||
|
PCF8575 expander(0x20);
|
||||||
|
|
||||||
|
#define PIN_NEOPIXEL_BUTTONS 4
|
||||||
|
#define NUM_NEOPIXEL_BUTTONS 18
|
||||||
|
|
||||||
|
#define PIN_NEOPIXEL_LOESUNG 6
|
||||||
|
#define NUM_NEOPIXEL_LOESUNG 6
|
||||||
|
|
||||||
|
#define PIN_POWER_ON 13
|
||||||
|
#define PIN_TRIGGER_SHUFFLE 2
|
||||||
|
#define PIN_SEND_WIN 5
|
||||||
|
|
||||||
|
// ------------------ Timing ------------------
|
||||||
|
|
||||||
|
#define WIN_OFF_DELAY_MS 300
|
||||||
|
#define WIN_STEP_DELAY_MS 60
|
||||||
|
#define DEBOUNCE_TIME_MS 200 // <<< Entprellzeit
|
||||||
|
|
||||||
|
Adafruit_NeoPixel pixelsButtons(
|
||||||
|
NUM_NEOPIXEL_BUTTONS,
|
||||||
|
PIN_NEOPIXEL_BUTTONS,
|
||||||
|
NEO_RGB + NEO_KHZ800
|
||||||
|
);
|
||||||
|
|
||||||
|
Adafruit_NeoPixel pixelsSolution(
|
||||||
|
NUM_NEOPIXEL_LOESUNG,
|
||||||
|
PIN_NEOPIXEL_LOESUNG,
|
||||||
|
NEO_RGB + NEO_KHZ800
|
||||||
|
);
|
||||||
|
|
||||||
|
// ------------------ Mapping ------------------
|
||||||
|
|
||||||
|
enum ButtonSource { SRC_NANO, SRC_PCF8575 };
|
||||||
|
|
||||||
|
struct LedButtonMap {
|
||||||
|
uint8_t ledIndex;
|
||||||
|
ButtonSource source;
|
||||||
|
uint8_t pin;
|
||||||
|
};
|
||||||
|
|
||||||
|
const LedButtonMap ledButtonMap[18] = {
|
||||||
|
{ 0, SRC_NANO, A0 }, { 1, SRC_NANO, A1 }, { 2, SRC_NANO, A2 }, { 3, SRC_NANO, A3 },
|
||||||
|
{ 4, SRC_NANO, 7 }, { 5, SRC_NANO, 8 },
|
||||||
|
{ 6, SRC_PCF8575, 0 }, { 7, SRC_PCF8575, 1 }, { 8, SRC_PCF8575, 2 }, { 9, SRC_PCF8575, 3 },
|
||||||
|
{10, SRC_PCF8575, 4 }, {11, SRC_PCF8575, 5 }, {12, SRC_PCF8575, 6 }, {13, SRC_PCF8575, 7 },
|
||||||
|
{14, SRC_PCF8575, 8 }, {15, SRC_PCF8575, 9 }, {16, SRC_PCF8575,10 }, {17, SRC_PCF8575,11 }
|
||||||
|
};
|
||||||
|
|
||||||
|
// ------------------ Pride-Farben (dunkler) ------------------
|
||||||
|
|
||||||
|
const uint8_t prideColors[6][3] = {
|
||||||
|
{25, 0, 0},
|
||||||
|
{35, 10, 0},
|
||||||
|
{25, 25, 0},
|
||||||
|
{ 0, 25, 0},
|
||||||
|
{ 0, 0, 25},
|
||||||
|
{20, 0, 25}
|
||||||
|
};
|
||||||
|
|
||||||
|
// ------------------ Spielzustände ------------------
|
||||||
|
|
||||||
|
uint8_t solutionOrder[6];
|
||||||
|
uint8_t expectedOrder[6];
|
||||||
|
int8_t buttonAssignment[18];
|
||||||
|
bool winActive = false;
|
||||||
|
bool powerOnState = true;
|
||||||
|
|
||||||
|
|
||||||
|
bool lastPressed[18];
|
||||||
|
unsigned long ledOffTime[18];
|
||||||
|
unsigned long lastPressTime[18]; // <<< Entprellspeicher
|
||||||
|
|
||||||
|
uint8_t progressIndex = 0;
|
||||||
|
bool lastTriggerState = LOW;
|
||||||
|
|
||||||
|
// ------------------ Hilfsfunktionen ------------------
|
||||||
|
|
||||||
|
bool readButton(uint8_t i) {
|
||||||
|
if (ledButtonMap[i].source == SRC_NANO)
|
||||||
|
return digitalRead(ledButtonMap[i].pin) == LOW;
|
||||||
|
return expander.read(ledButtonMap[i].pin) == LOW;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------ Neues Spiel ------------------
|
||||||
|
|
||||||
|
void generateNewGame() {
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < 6; i++) solutionOrder[i] = i;
|
||||||
|
|
||||||
|
for (int i = 5; i > 0; i--) {
|
||||||
|
int j = random(i + 1);
|
||||||
|
uint8_t t = solutionOrder[i];
|
||||||
|
solutionOrder[i] = solutionOrder[j];
|
||||||
|
solutionOrder[j] = t;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < 6; i++)
|
||||||
|
expectedOrder[i] = solutionOrder[5 - i];
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < 6; i++) {
|
||||||
|
uint8_t c = solutionOrder[i];
|
||||||
|
pixelsSolution.setPixelColor(
|
||||||
|
i,
|
||||||
|
pixelsSolution.Color(
|
||||||
|
prideColors[c][0],
|
||||||
|
prideColors[c][1],
|
||||||
|
prideColors[c][2]
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
pixelsSolution.show();
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < 18; i++) {
|
||||||
|
buttonAssignment[i] = -1;
|
||||||
|
pixelsButtons.setPixelColor(i, 0);
|
||||||
|
ledOffTime[i] = 0;
|
||||||
|
lastPressTime[i] = 0;
|
||||||
|
}
|
||||||
|
pixelsButtons.show();
|
||||||
|
|
||||||
|
uint8_t idx[18];
|
||||||
|
for (uint8_t i = 0; i < 18; i++) idx[i] = i;
|
||||||
|
|
||||||
|
for (int i = 17; i > 0; i--) {
|
||||||
|
int j = random(i + 1);
|
||||||
|
uint8_t t = idx[i];
|
||||||
|
idx[i] = idx[j];
|
||||||
|
idx[j] = t;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < 6; i++)
|
||||||
|
buttonAssignment[idx[i]] = solutionOrder[i];
|
||||||
|
|
||||||
|
progressIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------ Gewinnanimation + Signal ------------------
|
||||||
|
|
||||||
|
void winAnimation() {
|
||||||
|
|
||||||
|
winActive = true;
|
||||||
|
digitalWrite(PIN_SEND_WIN, HIGH);
|
||||||
|
|
||||||
|
// 1) letzte korrekte Farbe stehen lassen
|
||||||
|
delay(500);
|
||||||
|
|
||||||
|
// 2) ALLES AUS (inkl. Off-Timer löschen)
|
||||||
|
for (uint8_t i = 0; i < 18; i++)
|
||||||
|
ledOffTime[i] = 0;
|
||||||
|
|
||||||
|
pixelsSolution.clear();
|
||||||
|
pixelsButtons.clear();
|
||||||
|
pixelsSolution.show();
|
||||||
|
pixelsButtons.show();
|
||||||
|
delay(WIN_OFF_DELAY_MS);
|
||||||
|
|
||||||
|
// 3) richtige Reihenfolge (umgekehrt), Lösung + Taster synchron
|
||||||
|
for (int i = 5; i >= 0; i--) {
|
||||||
|
|
||||||
|
uint8_t color = solutionOrder[i];
|
||||||
|
|
||||||
|
// Lösungs-LED
|
||||||
|
pixelsSolution.setPixelColor(
|
||||||
|
i,
|
||||||
|
pixelsSolution.Color(
|
||||||
|
prideColors[color][0],
|
||||||
|
prideColors[color][1],
|
||||||
|
prideColors[color][2]
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
// zugehöriger Taster
|
||||||
|
for (uint8_t b = 0; b < 18; b++) {
|
||||||
|
if (buttonAssignment[b] == color) {
|
||||||
|
pixelsButtons.setPixelColor(
|
||||||
|
b,
|
||||||
|
pixelsButtons.Color(
|
||||||
|
prideColors[color][0],
|
||||||
|
prideColors[color][1],
|
||||||
|
prideColors[color][2]
|
||||||
|
)
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pixelsSolution.show();
|
||||||
|
pixelsButtons.show();
|
||||||
|
delay(WIN_STEP_DELAY_MS);
|
||||||
|
}
|
||||||
|
|
||||||
|
digitalWrite(PIN_SEND_WIN, LOW);
|
||||||
|
winActive = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// ------------------ Setup ------------------
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
randomSeed(analogRead(A0));
|
||||||
|
|
||||||
|
Wire.begin();
|
||||||
|
expander.begin();
|
||||||
|
|
||||||
|
pinMode(PIN_TRIGGER_SHUFFLE, INPUT);
|
||||||
|
pinMode(PIN_POWER_ON, INPUT);
|
||||||
|
powerOnState = digitalRead(PIN_POWER_ON);
|
||||||
|
pinMode(PIN_SEND_WIN, OUTPUT);
|
||||||
|
digitalWrite(PIN_SEND_WIN, LOW);
|
||||||
|
|
||||||
|
pinMode(A0, INPUT_PULLUP);
|
||||||
|
pinMode(A1, INPUT_PULLUP);
|
||||||
|
pinMode(A2, INPUT_PULLUP);
|
||||||
|
pinMode(A3, INPUT_PULLUP);
|
||||||
|
pinMode(7, INPUT_PULLUP);
|
||||||
|
pinMode(8, INPUT_PULLUP);
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < 12; i++)
|
||||||
|
expander.write(i, HIGH);
|
||||||
|
|
||||||
|
pixelsButtons.begin();
|
||||||
|
pixelsSolution.begin();
|
||||||
|
|
||||||
|
generateNewGame();
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < 18; i++)
|
||||||
|
lastPressed[i] = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------ Loop ------------------
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
if (powerOnState && digitalRead(PIN_POWER_ON) == LOW)
|
||||||
|
{
|
||||||
|
powerOnState = false;
|
||||||
|
pixelsSolution.begin();
|
||||||
|
for (size_t i = 0; i < 6; i++)
|
||||||
|
{
|
||||||
|
pixelsSolution.setPixelColor(i, pixelsSolution.Color(0, 0, 0, 0));
|
||||||
|
}
|
||||||
|
pixelsSolution.show();
|
||||||
|
pixelsButtons.begin();
|
||||||
|
for (size_t i = 0; i < 18; i++)
|
||||||
|
{
|
||||||
|
pixelsButtons.setPixelColor(i, pixelsButtons.Color(0, 0, 0, 0));
|
||||||
|
}
|
||||||
|
pixelsButtons.show();
|
||||||
|
|
||||||
|
}
|
||||||
|
// Detecting turn-on
|
||||||
|
if (!powerOnState && digitalRead(PIN_POWER_ON) == HIGH)
|
||||||
|
{
|
||||||
|
generateNewGame();
|
||||||
|
powerOnState = true;
|
||||||
|
}
|
||||||
|
if (!powerOnState)
|
||||||
|
{
|
||||||
|
// We are turned-off and stop anything after here
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
unsigned long now = millis();
|
||||||
|
|
||||||
|
bool trigger = digitalRead(PIN_TRIGGER_SHUFFLE);
|
||||||
|
if (trigger && !lastTriggerState) {
|
||||||
|
generateNewGame();
|
||||||
|
}
|
||||||
|
lastTriggerState = trigger;
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < 18; i++) {
|
||||||
|
bool pressed = readButton(i);
|
||||||
|
|
||||||
|
if (pressed && !lastPressed[i] &&
|
||||||
|
(now - lastPressTime[i] > DEBOUNCE_TIME_MS)) {
|
||||||
|
|
||||||
|
lastPressTime[i] = now;
|
||||||
|
int8_t color = buttonAssignment[i];
|
||||||
|
|
||||||
|
if (color >= 0) {
|
||||||
|
pixelsButtons.setPixelColor(
|
||||||
|
i,
|
||||||
|
pixelsButtons.Color(
|
||||||
|
prideColors[color][0],
|
||||||
|
prideColors[color][1],
|
||||||
|
prideColors[color][2]
|
||||||
|
)
|
||||||
|
);
|
||||||
|
pixelsButtons.show();
|
||||||
|
ledOffTime[i] = now + 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (color < 0 || color != expectedOrder[progressIndex]) {
|
||||||
|
progressIndex = 0;
|
||||||
|
} else {
|
||||||
|
progressIndex++;
|
||||||
|
if (progressIndex == 6) {
|
||||||
|
winAnimation();
|
||||||
|
progressIndex = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!winActive && ledOffTime[i] && now >= ledOffTime[i]) {
|
||||||
|
|
||||||
|
pixelsButtons.setPixelColor(i, 0);
|
||||||
|
pixelsButtons.show();
|
||||||
|
ledOffTime[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
lastPressed[i] = pressed;
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user