//#define WOKWI
/*
* Board: attiny 25/45/85
* Processor: attiny 85
* Clock: internal 16MHz
* Programmer: Arduino as ISP
*/
#ifdef WOKWI
#include <TinyDebug.h>
#endif
#undef F_CPU
#define F_CPU 16000000L
#define PIN_LTCH PB0 // connect to STCP
#define PIN_CLCK PB1 // connect to SHCP
#define PIN_DATA PB2 // connect to DS
#define PIN_POT1 A2 // = PB4
#define PIN_POT2 A3 // = PB3
#define BLOCKS_MAX 12
#define BLOCKS_MIN 1
#define SNAKE_MAX 20
#define SNAKE_MIN 2
#define MAX_PERIOD 400
#define MIN_PERIOD 0
byte display[8]; // 8x8 content of display
byte zero_display[8] = {0,0,0,0,0,0,0,0};
bool display_empty = false;
byte blocks[BLOCKS_MAX]; // index of blocks to light up [0, BLOCKS_MAX)
byte block_indx = 0;
byte block_count = BLOCKS_MIN;
int snake_dir = 1; // (1,-1, 8, -8)
int cur_spot = 35;
int update_display_ms = 1024;
unsigned long last_update = 0;
int panning_width = 2;
int last_pot_vals = 0;
unsigned long last_change_time = 0;
#define TIMEOUT_S 20
bool justbooted = true;
#ifdef WOKWI
int framecount = 0;
#endif
int pot1_val;
int pot2_val;
void setup() {
//3 output pins for shift registers
pinMode(PIN_LTCH, OUTPUT);
pinMode(PIN_CLCK, OUTPUT);
pinMode(PIN_DATA, OUTPUT);
pinMode(PIN_POT1, INPUT);
pinMode(PIN_POT2, INPUT);
last_pot_vals = analogRead(PIN_POT1) + analogRead(PIN_POT2);
randomSeed(last_pot_vals);
// start with random blocks
for (int i=0; i<BLOCKS_MAX; i++){
blocks[i] = random(64);
}
//assign to display
blocks_to_display();
#ifdef WOKWI
Debug.begin();
#endif
}
void loop() {
int time = millis();
pot1_val = analogRead(PIN_POT1);
pot2_val = analogRead(PIN_POT2);
update_display_ms = map(pot1_val, 0, 1023, MIN_PERIOD, MAX_PERIOD);
if (time - last_update > update_display_ms){
last_update = time;
update_blocks();
}
if (abs(pot1_val + pot2_val - last_pot_vals) > 4){
last_change_time = time;
last_pot_vals = pot1_val + pot2_val;
justbooted = false;
}
if (justbooted | (time - last_change_time > TIMEOUT_S * 1000)){
// Don't show
if (!display_empty){
shiftout_data(zero_display);
display_empty = true;
}
}
else{
display_empty = false;
shiftout_data(display);
}
}
void blocks_to_display(){
// start with with empty field
for(int i=0; i<8; i++){
display[i] = 0;
}
// fill at block index
for (int i=0; i<block_count; i++){
display[blocks[i]/8] |= 1<<(blocks[i]%8);
}
}
void update_blocks(){
block_count = map(pot2_val,0,1024,BLOCKS_MAX,BLOCKS_MIN);
block_indx +=1;
block_indx %= block_count;
/* Directions:
-1
-8 8
1 */
// if corner : always update direction, only one possible
if (cur_spot == 0){
// -8 > 1, -1 > 8 ==> x + 9
snake_dir += 9;
}else if (cur_spot == 7){
// 1>8, -8>-1 ==> x + 7
snake_dir += 7;
}else if (cur_spot == 56){
// 8 > 1, -1 > -8 ==> x-7
snake_dir -= 7;
}else if (cur_spot == 63){
// 1 >-8, 8 > -1 ==> x-9
snake_dir -= 9;
// else if edge
// if direction orthogonal: update
// if direction parallel : maybe update
}else if (cur_spot < 7 || cur_spot > 56){ // left edge || right edge
if (snake_dir == -8 || snake_dir == 8){
// orth direction: surely update
snake_dir = random(2) ? -1 : 1;
}else {
snake_dir = random(3) ? snake_dir : (cur_spot < 7 ? 8 : -8);
}
}else if (cur_spot % 8 == 0 || cur_spot % 8 == 7){ // top edge || bottom edge
if (snake_dir == -1 || snake_dir == 1){
// orth direction: surely update
snake_dir = random(2) ? -8 : 8;
}else {
snake_dir = random(3) ? snake_dir : (cur_spot % 8 ==0 ? 1 : -1);
}
// else field:
// any left / right maybe
}else if (random(4) == 0){
if (snake_dir == -8 || snake_dir == 8){
snake_dir = random(2) ? -1 : 1;
}else{
snake_dir = random(2) ? -8 : 8;
}
}
#ifdef WOKWI
Debug.print("cur_spot: ");
Debug.print(cur_spot);
Debug.print(" (");
Debug.print(cur_spot % 8);
Debug.print(" , ");
Debug.print(cur_spot / 8);
Debug.print(")");
Debug.print(" snake_dir: ");
Debug.println(snake_dir);
#endif
cur_spot += snake_dir;
blocks[block_indx] = cur_spot;
blocks_to_display();
}
void shiftout_data(byte display[8]){
for (int j = 0; j < 8; j++) {
//ground PIN_LTCH and hold low for as long as you are transmitting
digitalWrite(PIN_LTCH, LOW);
// shift out the row index (cathode -> active low)
shiftOut(PIN_DATA, PIN_CLCK, MSBFIRST, ~(1 << j));
// shift out the column content
shiftOut(PIN_DATA, PIN_CLCK, MSBFIRST, display[j]);
// done transmitting, latch high
digitalWrite(PIN_LTCH, HIGH);
}
}