#include <Arduino.h>
#include <avr/sleep.h>
#include <avr/power.h>
#include <avr/eeprom.h>
#define BLUE_BTN PB1
#define GREEN_BTN PB2
#define RED_BTN PB3
#define YELLOW_BTN PB4
#define BLUE 0b00
#define GREEN 0b01
#define RED 0b10
#define YELLOW 0b11
uint8_t curr;
uint8_t lvl;
uint8_t lvl_idx;
uint16_t seed;
const uint8_t buttons[] = {BLUE_BTN, GREEN_BTN, RED_BTN, YELLOW_BTN};
volatile uint8_t color = -1;
uint8_t simple_random4();
void enableInterrupts();
void allButtonsInput();
void allButtonsOutput();
void turnOn(uint8_t color);
void turnOff(uint8_t color);
void sleep();
void saveSeed(uint16_t seed);
uint16_t loadSeed();
void flashRotate();
void flash(uint8_t color);
void flash(uint8_t color, uint32_t delayMs);
ISR(PCINT0_vect) {
// Check which button was pressed and save it in a variable
if (digitalRead(BLUE_BTN) == LOW) {
color = BLUE;
} else if (digitalRead(GREEN_BTN) == LOW) {
color = GREEN;
} else if (digitalRead(RED_BTN) == LOW) {
color = RED;
} else if (digitalRead(YELLOW_BTN) == LOW) {
color = YELLOW;
}
}
void setup() {
// put your setup code here, to run once:
seed = 0;
lvl = 0;
curr = 0;
lvl_idx = 0;
randomSeed(loadSeed() + analogRead(0));
allButtonsInput();
}
void loop() {
if (lvl == 0) {
// new game, generate seed
seed = random(0, 65535);
// flash all buttons
for (uint8_t i = 0; i < 4; i++) {
flashRotate();
}
lvl = 1;
lvl_idx = 0;
curr = rand() % 4;
flash(curr, 300);
sleep();
} else {
// game in progress
if (lvl_idx == lvl) {
// level completed. Move to the next level, show current sequence plus new color
randomSeed(seed);
for (uint8_t i = 0; i < lvl; i++) {
curr = rand() % 4;
turnOn(curr);
delay(300);
turnOff(curr);
delay(100);
}
curr = rand() % 4;
turnOn(curr);
delay(300);
turnOff(curr);
lvl_idx = 0;
lvl++;
randomSeed(seed);
sleep();
} else {
// check if the right button was pressed
if (color == curr) {
// correct button pressed, move to the next count
lvl_idx++;
curr = rand() % 4;
sleep();
} else {
// wrong button pressed
// flash all buttons the number of times equal to the level
for (uint8_t i = 0; i < lvl; i++) {
turnOn(0);
turnOn(1);
turnOn(2);
turnOn(3);
turnOff(0);
turnOff(1);
turnOff(2);
turnOff(3);
delay(300);
}
lvl = 0;
curr = 0;
color = -1;
lvl_idx = 0;
}
}
}
}
uint8_t simple_random4() {
static uint32_t ctx;
ctx = ctx * 1103515245 + 12345; // too big for ATtiny13
//ctx = 2053 * ctx + 13849;
uint32_t temp = ctx ^ (ctx >> 8); // XOR two bytes
temp ^= (temp >> 4); // XOR two nibbles
return (temp ^ (temp >> 2)) & 0b00000011; // XOR two pairs of bits and return remainder after division by 4
}
// enable interrupts for all buttons
void enableInterrupts() {
GIMSK |= _BV(PCIE);
PCMSK |= _BV(PCINT1) | _BV(PCINT2) | _BV(PCINT3) | _BV(PCINT4);
}
void allButtonsInput() {
for (uint8_t i = 0; i < 4; i++) {
pinMode(buttons[i], INPUT_PULLUP);
}
}
void allButtonsOutput() {
for (uint8_t i = 0; i < 4; i++) {
pinMode(buttons[i], OUTPUT);
digitalWrite(buttons[i], HIGH);
}
}
void turnOn(uint8_t color) {
pinMode(buttons[color], OUTPUT);
digitalWrite(buttons[color], LOW);
}
void turnOff(uint8_t color) {
pinMode(buttons[color], INPUT_PULLUP);
}
void sleep() {
// Disable ADC - saves about 324.5uA in sleep mode!
ADCSRA = 0;
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
sleep_enable();
noInterrupts();
enableInterrupts();
interrupts();
sleep_cpu();
}
void saveSeed(uint16_t seed) {
uint8_t low = seed & 0xFF;
uint8_t high = seed >> 8;
eeprom_write_byte((uint8_t*)0, low);
eeprom_write_byte((uint8_t*)1, high);
}
uint16_t loadSeed() {
uint8_t low = eeprom_read_byte((uint8_t*)0);
uint8_t high = eeprom_read_byte((uint8_t*)1);
return (high << 8) | low;
}
void flashRotate() {
for (uint8_t i = 0; i < 4; i++) {
flash(i);
}
}
void flash(uint8_t color) {
flash(color, 100);
}
void flash(uint8_t color, uint32_t delayMs) {
turnOn(color);
delay(delayMs);
turnOff(color);
}