/* vim: sw=2:ts=2:ai */ #define YELLOW 0 #define BUTTON 1 #define M 2 #define I 3 #define U 4 #define TICKS_SEC 20 #define TICK_MS (1000 / TICKS_SEC) #define MILLIS(millis) ((int)(millis/TICK_MS)) #define INACTIVE_SEC 60 #define VMAX 80 byte down; int inactive; int active; enum State { S_START, S_RECITE, S_GAP, S_RABBIT_RIGHT, S_CLICKED, S_BAD, S_MU }; byte state; int arg; // Some states use arg. int tick; // How long in state and arg. byte clicks; // Count number of button presss. byte vlen; // Length of v string. byte v[VMAX]; // Vector holding string. void setup() { // initialize the digital pin as an output. pinMode(YELLOW, OUTPUT); pinMode(BUTTON, INPUT_PULLUP); pinMode(M, OUTPUT); pinMode(I, OUTPUT); pinMode(U, OUTPUT); } void set(byte m, byte i, byte u) { digitalWrite(M, m ? HIGH : LOW); digitalWrite(I, i ? HIGH : LOW); digitalWrite(U, u ? HIGH : LOW); } #define setM() set(1,0,0) #define setI() set(0,1,0) #define setU() set(0,0,1) #define set0() set(0,0,0) void on() { digitalWrite(YELLOW, HIGH); } void off() { digitalWrite(YELLOW, LOW); } void bad() { tick=0,arg=2000,state=S_BAD; } void copy(int n, int from, int to) { for (int i = 0; i < n; i++) { v[to+i] = v[from+i]; } } void production1() { if (vlen >= VMAX) { bad(); } else if (vlen < 1) { bad(); } else if (v[vlen-1] != I) { bad(); } else { v[vlen]=U; vlen++; } } void production2() { int p; for (p=0; p VMAX) { bad(); } else { copy(c, p+1, vlen); vlen += c; } } } void production3() { } void production4() { } void production5() { } void loop() { off(); down = (digitalRead(BUTTON) == LOW); // Keep track of active & inactive times. if (down) { ++active; inactive = 0; } else { ++inactive; active = 0; } // Check for victory. if (vlen==2 && v[0]==M && v[1]==U) tick=0,arg=0,state=S_MU; if (down) { set(1,1,1); if (active == 1) { // Once per click. ++clicks; } tick=0,arg=0,state=S_CLICKED; } else switch (state) { case S_START: vlen = 2; v[0] = M; v[1] = I; // vlen = 4; v[0] = M; v[1] = I; v[2] = U; v[3] = U; tick=0,arg=5,state=S_RABBIT_RIGHT; break; case S_CLICKED: on(); #define TICKS_CLICKED ((int)(800/TICK_MS)) if (tick < TICKS_CLICKED) { set(clicks&4, clicks&2, clicks&1); } else { switch(clicks) { case 1: production1(); break; case 2: production2(); break; case 3: production3(); break; case 4: production4(); break; case 5: production5(); break; } clicks=0, tick=0, arg=1, state=S_RABBIT_RIGHT; } break; case S_RECITE: // arg must init to 0 #define TICKS_ON ((int)(500/TICK_MS)) #define TICKS_OFF ((int)(500/TICK_MS)) if (tick < TICKS_ON) { switch (v[arg]) { case M: setM(); break; case I: setI(); break; case U: setU(); break; default: set0(); } } else if (tick < TICKS_ON+TICKS_OFF) { set0(); } else { tick = 0; ++arg; if (arg >= vlen) tick=0,arg=MILLIS(1500),state=S_GAP; } break; case S_GAP: // arg is how many ticks. if (tick < arg) { set0(); } else { tick=0,arg=0,state=S_RECITE; } break; case S_RABBIT_RIGHT: // arg is how many rabbits. #define TICKS_RABBIT ((int)(100/TICK_MS)) if (tick < 1*TICKS_RABBIT) { setM(); } else if (tick < 2*TICKS_RABBIT) { setI(); } else if (tick < 3*TICKS_RABBIT) { setU(); } else if (tick < 6*TICKS_RABBIT) { set0(); } else { tick = 0; --arg; if (arg < 1) { tick=0,arg=MILLIS(1000),state=S_GAP; } } break; case S_BAD: // arg is how long. #define TICKS_BEEP ((int)(100/TICK_MS)) if (tick < arg) { if ((tick / TICKS_BEEP) & 1) { set(1,1,1); } else { set(0,0,0); } } else { tick=0,arg=MILLIS(1000),state=S_GAP; } break; case S_MU: // arg is how long. #define TICKS_MU ((int)(100/TICK_MS)) if (tick < arg) { if ((tick / TICKS_MU) & 1) { setU(); } else { setM(); } } else { tick=0,arg=MILLIS(1000),state=S_GAP; } break; } delay(TICK_MS); ++tick; }