最后活跃于 1 week ago Unlisted

greg.cpp 原始文件 Playground
1#include <M5Unified.h>
2#include <M5GFX.h>
3
4template<uint32_t size>
5struct stack {
6 int data[size] = {};
7 uint32_t top = 0;
8 inline void push(int symbol) {
9 if(!full()) {
10 data[top++] = symbol;
11 }
12 }
13 inline int pop() {
14 if(!empty()) {
15 return data[--top];
16 }
17 return 0;
18 }
19 inline int peek() {
20 if(!empty()) {
21 return data[top - 1];
22 }
23 return 0;
24 }
25 inline bool empty() {
26 return top == 0;
27 }
28 inline bool full() {
29 return top >= size;
30 }
31 inline void clear() {
32 top = 0;
33 }
34 void print() {
35 for(uint32_t cursor = 0; cursor < top; cursor++) {
36 Serial.printf("%d ", data[cursor]);
37 }
38 Serial.println();
39 }
40};
41
42template<uint32_t stack_size, uint32_t program_size>
43struct generator {
44 stack<stack_size> stack;
45 char program[program_size] = {};
46 uint32_t length = program_size;
47 generator() {
48 randomize();
49 }
50 generator(const char* program) {
51 uint32_t cursor = 0;
52 while(program[cursor] != '\0' && cursor < program_size - 1) {
53 this->program[cursor] = program[cursor];
54 cursor++;
55 }
56 length = cursor;
57 this->program[length + 1] = '\0';
58 }
59 char random_command() {
60 const char commands[] = "0123456789abcdefxywhtrsopzq_=+*&|^~<>-/%";
61 return commands[random(0, sizeof(commands) - 1)];
62 }
63 void randomize() {
64 length = random(2, program_size-1);
65 for(uint32_t cursor = 0; cursor < length; cursor++) {
66 program[cursor] = random_command();
67 }
68 program[length] = '\0';
69 }
70 int run(uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint32_t t, int previous, uint16_t tx, uint16_t ty) {
71 for(uint32_t cursor = 0; cursor < length; cursor++) {
72 char instruction = program[cursor];
73 if(instruction >= '0' && instruction <= '9') {
74 stack.push(instruction - '0');
75 } else if(instruction >= 'a' && instruction <= 'f') {
76 stack.push((instruction - 'a') + 10);
77 } else {
78 switch(instruction) {
79 case 'x': stack.push(x); break;
80 case 'y': stack.push(y); break;
81 case 'w': stack.push(w); break;
82 case 'h': stack.push(h); break;
83 case 't': stack.push(t); break;
84 case 'r': stack.push(random()); break;
85 case 's': stack.push(sin(stack.pop()) * INT_MAX); break;
86 case 'o': stack.push(cos(stack.pop()) * INT_MAX); break;
87 case 'p': stack.push(previous); break;
88 case 'z': stack.push(tx); break;
89 case 'q': stack.push(ty); break;
90 case '_': stack.push(abs(stack.pop())); break;
91 case '=': stack.push(stack.pop() == stack.pop()); break;
92 case '+': stack.push(stack.pop() + stack.pop()); break;
93 case '*': stack.push(stack.pop() * stack.pop()); break;
94 case '&': stack.push(stack.pop() & stack.pop()); break;
95 case '|': stack.push(stack.pop() | stack.pop()); break;
96 case '^': stack.push(stack.pop() ^ stack.pop()); break;
97 case '~': stack.push(~stack.pop()); break;
98 case '<': {
99 int first = stack.pop();
100 int second = stack.pop();
101 stack.push(second < first);
102 break;
103 }
104 case '>': {
105 int first = stack.pop();
106 int second = stack.pop();
107 stack.push(second < first);
108 break;
109 }
110 case '-': {
111 int first = stack.pop();
112 int second = stack.pop();
113 if(first == 0) {
114 first = -1;
115 }
116 if(second == 0) {
117 second = -1;
118 }
119 stack.push(second - first);
120 break;
121 }
122 case '/': {
123 int first = stack.pop();
124 int second = stack.pop();
125 stack.push(second / first);
126 break;
127 }
128 case '%': {
129 int first = stack.pop();
130 int second = stack.pop();
131 stack.push(second % first);
132 break;
133 }
134 default: break;
135 }
136 }
137 }
138 return stack.pop();
139 }
140 void print(uint32_t size) {
141 M5.Display.pushState();
142 M5.Display.writeFillRect(0, M5.Display.height() - (size * 8), M5.Display.width(), M5.Display.height(), TFT_BLACK);
143 M5.Display.setCursor(0, M5.Display.height() - (size * 8) + 4);
144 M5.Display.setTextSize(3);
145 M5.Display.setTextWrap(true);
146 M5.Display.setTextColor(TFT_DARKGREY, TFT_BLACK);
147 for(uint32_t instruction = 0; instruction < length; instruction++) {
148 M5.Display.print(program[instruction]);
149 }
150 M5.Display.popState();
151 }
152};
153
154uint32_t width = 0;
155uint32_t height = 0;
156uint32_t size = 10;
157uint32_t tile_size = 1;
158uint32_t t = 0;
159uint32_t cooldown = 0;
160uint8_t wait = 25;
161int8_t offset = 1;
162generator<256, 53*3> pixel("xy+xy-&9f+%9>8-");
163
164inline bool shaken(float ax, float ay, float az) {
165 return (abs(ax) >= 1.75) || (abs(ay) >= 1.5) || (abs(az) >= 1.75);
166}
167
168void intro() {
169 M5.Display.setTextSize(4);
170 M5.Display.drawCenterString("For Greg", M5.Display.width() / 2, (M5.Display.height() / 2) - 16);
171 M5.Display.drawCenterString("From Nouveau", M5.Display.width() / 2, (M5.Display.height() / 2) + 16);
172 M5.Display.setTextColor(random(0, UINT16_MAX), random(0, UINT16_MAX));
173 delay(5000);
174 M5.Display.clear();
175 M5.Display.setTextSize(size);
176 int previous = pixel.run(0, 0, width, height, 0, 0, 0, 0);
177 for(uint32_t x = 0; x < width; x++) {
178 for(uint32_t y = 0; y < height; y++) {
179 const int value = pixel.run(x, y, width, height, t, previous, 0, 0);
180 const int character = (abs(value % 17)) + 127;
181 M5.Display.drawChar(character, x * tile_size, y * tile_size);
182 previous = value;
183 delay(1);
184 }
185 }
186 delay(1000);
187 M5.Display.setTextSize(4);
188 M5.Display.setTextColor(TFT_CYAN, TFT_DARKCYAN);
189 M5.Display.drawCenterString(" ", M5.Display.width() / 2, (M5.Display.height() / 2) - 48);
190 M5.Display.drawCenterString(" ALL THESE WORLDS ", M5.Display.width() / 2, (M5.Display.height() / 2) - 16);
191 M5.Display.drawCenterString(" ARE YOURS ", M5.Display.width() / 2, (M5.Display.height() / 2) + 16);
192 M5.Display.drawCenterString(" ", M5.Display.width() / 2, (M5.Display.height() / 2) + 48);
193 delay(5000);
194 pixel.randomize();
195 M5.Display.fillRect(0, 0, M5.Display.width(), M5.Display.height(), TFT_BLACK);
196 delay(1000);
197}
198
199void setup(void) {
200 Serial.begin(9600);
201 M5.begin();
202 M5.Display.setRotation(1);
203 M5.Display.setFont(&fonts::Font8x8C64);
204 M5.Display.waitDisplay();
205 size = 2;
206 tile_size = size * 8;
207 width = M5.Display.width() / tile_size;
208 height = (M5.Display.height() / tile_size) - 1;
209 intro();
210 size = 10;
211 tile_size = size * 8;
212 width = M5.Display.width() / tile_size;
213 height = (M5.Display.height() / tile_size) - 1;
214 M5.Display.setTextSize(size);
215 M5.Display.setTextColor(random(), random());
216 pixel.print(size);
217}
218
219void loop(void) {
220 lgfx::touch_point_t point = {};
221 float ax = 0, ay = 0, az = 0;
222 bool touch = false;
223 M5.Imu.update();
224 M5.Imu.getAccel(&ax, &ay, &az);
225 if(M5.Display.getTouchRaw(&point, 1)) {
226 M5.Display.convertRawXY(&point, 1);
227 touch = true;
228 }
229 M5.Display.startWrite();
230 int previous = pixel.run(0, 0, width, height, 0, 0, 0, 0);
231 bool alive = false;
232 for(uint32_t x = 0; x < width; x++) {
233 for(uint32_t y = 0; y < height; y++) {
234 const int value = pixel.run(x, y, width, height, t, previous, map(point.x, 0, M5.Display.width(), 0, width), map(point.y, 0, M5.Display.height(), 0, height));
235 const int character = (abs(value % 17)) + 127;
236 M5.Display.drawChar(character, x * tile_size, y * tile_size);
237 if(((abs(previous % 17)) + 127) != character) {
238 alive = true;
239 }
240 previous = value;
241 }
242 }
243 M5.Display.endWrite();
244 t += offset;
245 if(wait > 0) {
246 wait--;
247 }
248 if(cooldown > 0) {
249 cooldown--;
250 }
251 if(touch) {
252 cooldown = 100;
253 }
254 if(!alive) {
255 wait = 0;
256 }
257 if((shaken(ax, ay, az) && !touch) || (wait == 0 && (!alive || cooldown == 0))) {
258 pixel.randomize();
259 if(alive) {
260 M5.Display.setTextColor(random(), random());
261 }
262 wait = 50;
263 pixel.print(size);
264 t = 0;
265 }
266 if(t >= 1000000) {
267 offset = -1;
268 } else if(t == 0) {
269 offset = 1;
270 }
271}
272