aboutsummaryrefslogtreecommitdiff
path: root/puzzle/neo/main.cpp
blob: 831f97e11faf0317a14af6566816f4c9b4a45d0f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
#include <Arduino.h>
#include <Wire.h>
#include <Adafruit_NeoTrellis.h>
#include "pb-types.h"
#include "pb-mod.h"
#include "pb.h"

#define MATRIX_SIZE 8
#define LED_COLOR_ON 0x0000FF // Color of the LEDs in ON state
#define LED_COLOR_OFF 0x000000 // Color of the LEDs in OFF state
#define LED_COLOR_RED 0xFF0000 // Red color for UNINIT state
#define LED_COLOR_ORANGE 0xFFA500 // Orange color for IDLE state

Adafruit_NeoTrellis t_array[MATRIX_SIZE / 4][MATRIX_SIZE / 4] = {
	{ Adafruit_NeoTrellis(PB_ADDR_ADA_NEO_1), Adafruit_NeoTrellis(PB_ADDR_ADA_NEO_2) },
	{ Adafruit_NeoTrellis(PB_ADDR_ADA_NEO_3), Adafruit_NeoTrellis(PB_ADDR_ADA_NEO_4) },
};

Adafruit_MultiTrellis trellis((Adafruit_NeoTrellis *)t_array, MATRIX_SIZE / 4, MATRIX_SIZE / 4);

bool neoMatrix[MATRIX_SIZE][MATRIX_SIZE]; // To track state of each pixel

unsigned long previousMillis = 0;
const long interval = 500; // Interval at which to blink (milliseconds)

bool gamefield = false;
bool ledState = false;

// Puzzle state
pb_global_state_t puzzleState = PB_GS_NOINIT;

void toggleAdjacentLEDs(int x, int y) {
	for (int dx = -1; dx <= 1; ++dx) {
		for (int dy = -1; dy <= 1; ++dy) {
			if (dx == 0 && dy == 0) continue; // Skip the center button itself
			int nx = x + dx, ny = y + dy;
			if (nx >= 0 && nx < MATRIX_SIZE && ny >= 0 && ny < MATRIX_SIZE) {
				neoMatrix[nx][ny] = !neoMatrix[nx][ny];
				trellis.setPixelColor(nx * MATRIX_SIZE + ny, neoMatrix[nx][ny] ? LED_COLOR_ON : LED_COLOR_OFF);
			}
		}
	}
}


bool isNeoPuzzleSolved() {
	for (int i = 0; i < MATRIX_SIZE; i++) {
		for (int j = 0; j < MATRIX_SIZE; j++) {
			if (neoMatrix[i][j]) return false; // If any LED is on, puzzle is not solved
		}
	}
	return true;
}

TrellisCallback buttonCallback(keyEvent evt) {
	int x = evt.bit.NUM / MATRIX_SIZE;
	int y = evt.bit.NUM % MATRIX_SIZE;

	if (evt.bit.EDGE == SEESAW_KEYPAD_EDGE_RISING) {
		toggleAdjacentLEDs(x, y);
		trellis.show();
		if (isNeoPuzzleSolved()) {
			pb_hook_mod_state_write(PB_GS_SOLVED);
			Serial.println("The NeoTrellis puzzle is solved!");
		}
	}
	return 0;
}

void setup() {
	Serial.begin(115200);
	while (!Serial); // Wait for Serial to be read
	if (!trellis.begin()) {
		Serial.println("Failed to initialize NeoTrellis");
		pb_hook_mod_state_write(PB_GS_NOINIT);
	}
}

void set_game_field() {
	if (gamefield == false){
		// Initialize the matrix with a checkerboard pattern
		bool toggle = false;
		for (int i = 0; i < MATRIX_SIZE; i++) {
			for (int j = 0; j < MATRIX_SIZE; j++) {
				neoMatrix[i][j] = toggle;
				toggle = !toggle;
				trellis.setPixelColor(i * MATRIX_SIZE + j, neoMatrix[i][j] ? LED_COLOR_ON : LED_COLOR_OFF);
			}
			toggle = !toggle;
		}
		trellis.show();

		// Register the callback for each key
		for (int i = 0; i < MATRIX_SIZE * MATRIX_SIZE; i++) {
			trellis.activateKey(i, SEESAW_KEYPAD_EDGE_RISING, true);
			trellis.activateKey(i, SEESAW_KEYPAD_EDGE_FALLING, true);
			trellis.registerCallback(i, buttonCallback);
		}
		gamefield = true;
	}
}

pb_global_state_t pb_hook_mod_state_read() {
	return puzzleState;
}

void pb_hook_mod_state_write(pb_global_state_t state) {
	puzzleState = state;
}

void flashCorners(uint32_t color) {
	unsigned long currentMillis = millis();

	if (currentMillis - previousMillis >= interval) {
		previousMillis = currentMillis;
		ledState = !ledState;

		for (int i = 0; i < MATRIX_SIZE / 4; i++) {
			for (int j = 0; j < MATRIX_SIZE / 4; j++) {
				int baseIndex = (i * 4 * MATRIX_SIZE) + (j * 4);
				if (ledState) {
					trellis.setPixelColor(baseIndex, color); // Top-left corner
					trellis.setPixelColor(baseIndex + 3, color); // Top-right corner
					trellis.setPixelColor(baseIndex + 3 * MATRIX_SIZE, color); // Bottom-left corner
					trellis.setPixelColor(baseIndex + 3 * MATRIX_SIZE + 3, color); // Bottom-right corner
				} else {
					trellis.setPixelColor(baseIndex, LED_COLOR_OFF);
					trellis.setPixelColor(baseIndex + 3, LED_COLOR_OFF);
					trellis.setPixelColor(baseIndex + 3 * MATRIX_SIZE, LED_COLOR_OFF);
					trellis.setPixelColor(baseIndex + 3 * MATRIX_SIZE + 3, LED_COLOR_OFF);
				}
			}
		}
		trellis.show();
	}
}

void loop() {
	switch(puzzleState) {
		case PB_GS_PLAYING:
			set_game_field();
			trellis.read(); // Process button events
			delay(20);
			break;
		case PB_GS_SOLVED:
			Serial.println("STATE = PB_GS_SOLVED");
			break;
		case PB_GS_NOINIT:
			Serial.println("STATE = PB_GS_NOINIT");
			flashCorners(LED_COLOR_RED);
			break;
		case PB_GS_IDLE:
			Serial.println("STATE = PB_GS_IDLE");
			flashCorners(LED_COLOR_ORANGE);
			break;
	}
}