snake_compiler git · main
Snake compiled to a bare-metal RISC-V microcontroller
C 95.2% Markdown 3.3%git clone https://git.christianimmanuel.de/embedded/snake_compiler.gitwget https://git.christianimmanuel.de/embedded/snake_compiler/archive/snake_compiler.tar.gzsnake_ascii_editor/main.c raw
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#ifdef _WIN32
#include <conio.h>
#include <windows.h>
#define CLEAR "cls"
#else
#include <unistd.h>
#include <termios.h>
#include <fcntl.h>
#define CLEAR "clear"
int getch(void) {
struct termios o, n;
tcgetattr(STDIN_FILENO, &o);
n = o;
n.c_lflag &= ~(ICANON | ECHO);
tcsetattr(STDIN_FILENO, TCSANOW, &n);
int ch = getchar();
tcsetattr(STDIN_FILENO, TCSANOW, &o);
return ch;
}
#endif
#define SIZE 16
#define MAX_SNAKE 256
#define MAX_VARS 10
#define MAX_CODE 8192
typedef struct {
int x, y;
} Point;
typedef enum {
NONE, VARIABLE, ARRAY, FUNCTION, MAIN_FUNC, STATEMENT
} EntityType;
typedef enum {
STATE_NORMAL, STATE_CREATE, STATE_SELECT_ENTITY, STATE_SET_VALUE,
STATE_SET_DIM, STATE_SET_ARRAY_SIZE, STATE_SELECT_VAR, STATE_SELECT_STATEMENT,
STATE_BUILD_EXPR, STATE_BUILD_IF_COND, STATE_BUILD_WHILE_COND, STATE_BUILD_DO_COND, STATE_SET_LOOP_INIT,
STATE_SET_LOOP_COND, STATE_SET_LOOP_INC
} GameState;
typedef enum {
STMT_NONE, STMT_IF, STMT_WHILE, STMT_FOR, STMT_DO_WHILE, STMT_ASSIGN, STMT_CALL,
STMT_BREAK, STMT_RETURN, STMT_BLOCK_END
} StatementType;
typedef enum {
BT_NONE, BT_IF, BT_WHILE, BT_FOR, BT_DO_WHILE, BT_FUNC, BT_MAIN
} BlockType;
typedef struct {
char name[32];
char value[64];
int used;
} Variable;
typedef struct {
char name[32];
int dimensions;
int sizes[3];
int used;
} Array;
typedef struct {
char name[32];
char params[128];
char body[512];
int used;
} Function;
Point snake[MAX_SNAKE];
int slen = 3;
int dx = 1, dy = 0;
char grid[SIZE][SIZE];
char code[MAX_CODE] = "";
GameState state = STATE_NORMAL;
EntityType creating = NONE;
StatementType current_stmt = STMT_NONE;
int selected_entity = 0;
Variable vars[MAX_VARS];
Array arrs[MAX_VARS];
Function funcs[MAX_VARS];
int has_main = 0;
char current_value[128] = "";
char current_value2[128] = "";
char current_operation[8] = "";
int setting_second_value = 0;
int current_dim_count = 0;
int indent_level = 0;
// For building complex statements
char expr_buffer[256] = "";
char condition_buffer[256] = "";
char loop_init[128] = "";
char loop_cond[128] = "";
char loop_inc[128] = "";
BlockType block_stack[32];
int block_level = 0;
#ifndef _WIN32
int old_flags;
#endif
void add_indent() {
for (int i = 0; i < indent_level; i++) {
strcat(code, " ");
}
}
void init_game() {
snake[0].x = 3; snake[0].y = 8;
snake[1].x = 2; snake[1].y = 8;
snake[2].x = 1; snake[2].y = 8;
for (int i = 0; i < MAX_VARS; i++) {
vars[i].used = 0;
arrs[i].used = 0;
funcs[i].used = 0;
}
memset(block_stack, 0, sizeof(block_stack));
block_level = 0;
#ifndef _WIN32
old_flags = fcntl(STDIN_FILENO, F_GETFL, 0);
fcntl(STDIN_FILENO, F_SETFL, old_flags | O_NONBLOCK);
#endif
}
void check_collision() {
int hx = snake[0].x;
int hy = snake[0].y;
// Wrap through walls
if (hx < 0) hx = SIZE - 1;
if (hx >= SIZE) hx = 0;
if (hy < 0) hy = SIZE - 1;
if (hy >= SIZE) hy = 0;
snake[0].x = hx;
snake[0].y = hy;
// Check special tiles
if (state == STATE_NORMAL) {
// Creation tiles
if (hx == 1 && hy == 2) {
state = STATE_CREATE;
creating = VARIABLE;
} else if (hx == 1 && hy == 4) {
state = STATE_CREATE;
creating = ARRAY;
} else if (hx == 1 && hy == 6) {
state = STATE_CREATE;
creating = FUNCTION;
} else if (hx == 1 && hy == 8) {
state = STATE_CREATE;
creating = MAIN_FUNC;
} else if (hx == 1 && hy == 10) {
state = STATE_SELECT_STATEMENT;
creating = STATEMENT;
}
// Print code
else if (hx == 15 && hy == 14) {
printf("\n=== GENERATED CODE ===\n%s\n=====================\n", code);
printf("Press any key to continue...");
while (getch() != 10);
}
// Close block }
else if (hx == 15 && hy == 13) {
if (block_level > 0) {
BlockType bt = block_stack[--block_level];
indent_level--;
add_indent();
if (bt == BT_DO_WHILE) {
state = STATE_BUILD_DO_COND;
strcpy(condition_buffer, "");
strcpy(current_value, "");
strcpy(current_value2, "");
strcpy(current_operation, "");
setting_second_value = 0;
} else {
strcat(code, "}\n");
}
}
}
} else if (state == STATE_CREATE) {
// Select entity (variables/arrays/functions 0-9)
if (hx == 3 && hy >= 2 && hy <= 11) {
selected_entity = hy - 2;
if (creating == VARIABLE) {
if (!vars[selected_entity].used) {
sprintf(vars[selected_entity].name, "var%d", selected_entity);
vars[selected_entity].used = 1;
strcpy(vars[selected_entity].value, "");
state = STATE_SET_VALUE;
strcpy(current_value, "");
strcpy(current_value2, "");
strcpy(current_operation, "");
setting_second_value = 0;
}
} else if (creating == ARRAY) {
if (!arrs[selected_entity].used) {
sprintf(arrs[selected_entity].name, "arr%d", selected_entity);
arrs[selected_entity].used = 1;
arrs[selected_entity].dimensions = 0;
for (int i = 0; i < 3; i++) arrs[selected_entity].sizes[i] = 0;
state = STATE_SET_DIM;
strcpy(current_value, "");
current_dim_count = 0;
}
} else if (creating == FUNCTION) {
if (!funcs[selected_entity].used) {
sprintf(funcs[selected_entity].name, "func%d", selected_entity);
funcs[selected_entity].used = 1;
strcpy(funcs[selected_entity].params, "");
strcpy(funcs[selected_entity].body, "");
add_indent();
char line[256];
sprintf(line, "void %s() {\n", funcs[selected_entity].name);
strcat(code, line);
indent_level++;
block_stack[block_level++] = BT_FUNC;
state = STATE_NORMAL;
}
} else if (creating == MAIN_FUNC) {
if (!has_main) {
has_main = 1;
add_indent();
strcat(code, "int main() {\n");
indent_level++;
block_stack[block_level++] = BT_MAIN;
state = STATE_NORMAL;
}
}
}
} else if (state == STATE_SELECT_STATEMENT) {
// Use selectors at col 3
if (hx == 3 && hy >= 2 && hy <= 11) {
int stmt_idx = hy - 2;
StatementType stmts[] = {STMT_IF, STMT_WHILE, STMT_FOR, STMT_DO_WHILE,
STMT_ASSIGN, STMT_CALL, STMT_BREAK, STMT_RETURN, STMT_BLOCK_END};
if (stmt_idx < 9) {
current_stmt = stmts[stmt_idx];
if (current_stmt == STMT_BREAK) {
add_indent();
strcat(code, "break;\n");
state = STATE_NORMAL;
} else if (current_stmt == STMT_RETURN) {
add_indent();
strcat(code, "return ");
state = STATE_BUILD_EXPR;
strcpy(expr_buffer, "");
strcpy(current_value, "");
strcpy(current_value2, "");
strcpy(current_operation, "");
setting_second_value = 0;
} else if (current_stmt == STMT_BLOCK_END) {
if (block_level > 0) {
BlockType bt = block_stack[--block_level];
indent_level--;
add_indent();
if (bt == BT_DO_WHILE) {
state = STATE_BUILD_DO_COND;
strcpy(condition_buffer, "");
strcpy(current_value, "");
strcpy(current_value2, "");
strcpy(current_operation, "");
setting_second_value = 0;
} else {
strcat(code, "}\n");
}
}
state = STATE_NORMAL;
} else if (current_stmt == STMT_IF) {
state = STATE_BUILD_IF_COND;
strcpy(condition_buffer, "");
strcpy(current_value, "");
strcpy(current_value2, "");
strcpy(current_operation, "");
setting_second_value = 0;
} else if (current_stmt == STMT_WHILE) {
state = STATE_BUILD_WHILE_COND;
strcpy(condition_buffer, "");
strcpy(current_value, "");
strcpy(current_value2, "");
strcpy(current_operation, "");
setting_second_value = 0;
} else if (current_stmt == STMT_FOR) {
state = STATE_SET_LOOP_INIT;
strcpy(loop_init, "");
strcpy(loop_cond, "");
strcpy(loop_inc, "");
strcpy(current_value, "");
strcpy(current_value2, "");
strcpy(current_operation, "");
setting_second_value = 0;
} else if (current_stmt == STMT_DO_WHILE) {
add_indent();
strcat(code, "do {\n");
indent_level++;
block_stack[block_level++] = BT_DO_WHILE;
state = STATE_NORMAL;
} else if (current_stmt == STMT_ASSIGN || current_stmt == STMT_CALL) {
state = STATE_BUILD_EXPR;
strcpy(expr_buffer, "");
strcpy(current_value, "");
strcpy(current_value2, "");
strcpy(current_operation, "");
setting_second_value = 0;
}
}
}
} else if (state == STATE_SET_DIM) {
// Set dimension count for array
if (hx >= 2 && hx <= 11 && hy == 14) {
int digit = hx - 2;
if (digit >= 1 && digit <= 3) {
arrs[selected_entity].dimensions = digit;
state = STATE_SET_ARRAY_SIZE;
strcpy(current_value, "");
current_dim_count = 0;
}
}
} else if (state == STATE_SET_ARRAY_SIZE) {
// Set size for each dimension
if (hx >= 2 && hx <= 11 && hy == 14) {
int digit = hx - 2;
char d[2] = {digit + '0', '\0'};
strcat(current_value, d);
}
// Confirm dimension size with S
else if (hx == 15 && hy == 10) {
if (strlen(current_value) > 0) {
arrs[selected_entity].sizes[current_dim_count] = atoi(current_value);
current_dim_count++;
strcpy(current_value, "");
// If all dimensions set, generate code
if (current_dim_count >= arrs[selected_entity].dimensions) {
add_indent();
char line[128];
sprintf(line, "int %s", arrs[selected_entity].name);
for (int i = 0; i < arrs[selected_entity].dimensions; i++) {
char dim[16];
sprintf(dim, "[%d]", arrs[selected_entity].sizes[i]);
strcat(line, dim);
}
strcat(line, ";\n");
strcat(code, line);
state = STATE_NORMAL;
}
}
}
} else if (state == STATE_SET_VALUE || state == STATE_BUILD_IF_COND || state == STATE_BUILD_WHILE_COND || state == STATE_BUILD_DO_COND || state == STATE_BUILD_EXPR || state == STATE_SET_LOOP_INIT || state == STATE_SET_LOOP_COND || state == STATE_SET_LOOP_INC) {
// Number tiles (0-9)
if (hx >= 2 && hx <= 11 && hy == 14) {
int digit = hx - 2;
char d[2] = {digit + '0', '\0'};
if (setting_second_value) {
strcat(current_value2, d);
} else {
strcat(current_value, d);
}
}
// Variable selection area (col 4)
else if (hx == 4 && hy >= 2 && hy <= 11) {
int var_idx = hy - 2;
if (vars[var_idx].used) {
if (setting_second_value) {
strcat(current_value2, vars[var_idx].name);
} else {
strcat(current_value, vars[var_idx].name);
}
}
}
// Array selection with index (col 6)
else if (hx == 6 && hy >= 2 && hy <= 11) {
int arr_idx = hy - 2;
if (arrs[arr_idx].used) {
char arr_access[64];
sprintf(arr_access, "%s[", arrs[arr_idx].name);
if (setting_second_value) {
strcat(current_value2, arr_access);
} else {
strcat(current_value, arr_access);
}
}
}
// Function call (col 11)
else if (hx == 11 && hy >= 2 && hy <= 11) {
int func_idx = hy - 2;
if (funcs[func_idx].used) {
char func_call[64];
sprintf(func_call, "%s(", funcs[func_idx].name);
if (setting_second_value) {
strcat(current_value2, func_call);
} else {
strcat(current_value, func_call);
}
}
}
// Operations
else if (hx == 13 && hy >= 2 && hy <= 13) {
int idx = hy - 2;
if (idx < 12) {
const char *ops[] = {"+", "-", "*", "/", ">", "<", "==", "&&", ">=", "<=", "!=", "||"};
if (setting_second_value && strlen(current_operation) > 0) {
char temp[256];
sprintf(temp, " %s %s", current_operation, current_value2);
strcat(current_value, temp);
strcpy(current_value2, "");
strcpy(current_operation, "");
}
strcpy(current_operation, ops[idx]);
setting_second_value = 1;
}
}
// Special chars
else if (hx == 12 && hy >= 2 && hy <= 13) {
int idx = hy - 2;
if (idx < 12) {
const char *chars[] = {"[", "]", "(", ")", ",", "=", ";", ".", "!", "~", "&", "*"};
char s[2] = {chars[idx][0], '\0'};
if (setting_second_value) {
strcat(current_value2, s);
} else {
strcat(current_value, s);
}
}
}
// Confirm with set button
else if (hx == 15 && hy == 10) {
char line[256];
char buffer[256] = "";
if (strlen(current_operation) > 0 && strlen(current_value2) > 0) {
sprintf(buffer, "%s %s %s", current_value, current_operation, current_value2);
} else {
strcpy(buffer, current_value);
}
if (state == STATE_SET_VALUE) {
if (strlen(buffer) > 0) {
add_indent();
sprintf(line, "int %s = %s;\n", vars[selected_entity].name, buffer);
strcat(code, line);
} else {
add_indent();
sprintf(line, "int %s;\n", vars[selected_entity].name);
strcat(code, line);
}
state = STATE_NORMAL;
} else if (state == STATE_BUILD_IF_COND || state == STATE_BUILD_WHILE_COND || state == STATE_BUILD_DO_COND) {
strcpy(condition_buffer, buffer);
add_indent();
if (state == STATE_BUILD_DO_COND) {
strcat(code, "} while (");
strcat(code, condition_buffer);
strcat(code, ");\n");
} else {
strcat(code, state == STATE_BUILD_IF_COND ? "if (" : "while (");
strcat(code, condition_buffer);
strcat(code, ") {\n");
indent_level++;
block_stack[block_level++] = state == STATE_BUILD_IF_COND ? BT_IF : BT_WHILE;
}
state = STATE_NORMAL;
} else if (state == STATE_SET_LOOP_INIT) {
strcpy(loop_init, buffer);
state = STATE_SET_LOOP_COND;
} else if (state == STATE_SET_LOOP_COND) {
strcpy(loop_cond, buffer);
state = STATE_SET_LOOP_INC;
} else if (state == STATE_SET_LOOP_INC) {
strcpy(loop_inc, buffer);
add_indent();
sprintf(line, "for (%s; %s; %s) {\n", loop_init, loop_cond, loop_inc);
strcat(code, line);
indent_level++;
block_stack[block_level++] = BT_FOR;
state = STATE_NORMAL;
} else if (state == STATE_BUILD_EXPR) {
strcpy(expr_buffer, buffer);
add_indent();
if (current_stmt == STMT_RETURN) {
sprintf(line, "return %s;\n", expr_buffer);
} else {
sprintf(line, "%s;\n", expr_buffer);
}
strcat(code, line);
state = STATE_NORMAL;
}
}
}
// Undo button
if (hx == 15 && hy == 12) {
if (state == STATE_SET_VALUE || state == STATE_BUILD_IF_COND || state == STATE_BUILD_WHILE_COND || state == STATE_BUILD_DO_COND ||
state == STATE_BUILD_EXPR || state == STATE_SET_LOOP_INIT ||
state == STATE_SET_LOOP_COND || state == STATE_SET_LOOP_INC) {
if (setting_second_value && strlen(current_value2) > 0) {
strcpy(current_value2, "");
} else if (strlen(current_value) > 0) {
strcpy(current_value, "");
} else {
strcpy(current_operation, "");
setting_second_value = 0;
}
} else if (state == STATE_SET_ARRAY_SIZE) {
strcpy(current_value, "");
}
}
}
void move_snake() {
for (int i = slen - 1; i > 0; i--) {
snake[i] = snake[i - 1];
}
snake[0].x += dx;
snake[0].y += dy;
check_collision();
}
void draw() {
system(CLEAR);
// Clear grid
for (int i = 0; i < SIZE; i++) {
for (int j = 0; j < SIZE; j++) {
grid[i][j] = '.';
}
}
// Mark creation tiles
grid[2][1] = 'V';
grid[4][1] = 'A';
grid[6][1] = 'F';
grid[8][1] = 'M';
grid[10][1] = 'S';
// Selection rows
for (int i = 2; i <= 11; i++) {
grid[i][3] = '0' + (i - 2); // Entity selection
if (vars[i - 2].used) grid[i][4] = 'V'; // Vars at col 4
if (arrs[i - 2].used) grid[i][6] = 'A'; // Arrays at col 6
if (funcs[i - 2].used) grid[i][11] = 'F'; // Functions at col 11
}
// Number tiles
for (int i = 2; i <= 11; i++) {
grid[14][i] = '0' + (i - 2);
}
// Operation tiles
char display_ops[12] = {'+', '-', '*', '/', '>', '<', '=', '&', 'g', 'l', 'n', 'o'};
for (int i = 0; i < 12; i++) {
if (2 + i < SIZE) grid[2 + i][13] = display_ops[i];
}
// Special character tiles
char display_chars[12] = {'[', ']', '(', ')', ',', '=', ';', '.', '!', '~', '&', '*'};
for (int i = 0; i < 12; i++) {
if (2 + i < SIZE) grid[2 + i][12] = display_chars[i];
}
// Action tiles
grid[10][15] = 'S'; // Set
grid[12][15] = 'U'; // Undo
grid[13][15] = '}'; // Close block
grid[14][15] = 'P'; // Print
// Draw snake
for (int i = 0; i < slen; i++) {
int x = snake[i].x;
int y = snake[i].y;
if (x >= 0 && x < SIZE && y >= 0 && y < SIZE) {
grid[y][x] = (i == 0) ? '@' : '#';
}
}
// Print grid
printf("╔");
for (int i = 0; i < SIZE * 2; i++) printf("═");
printf("╗\n");
for (int i = 0; i < SIZE; i++) {
printf("║");
for (int j = 0; j < SIZE; j++) {
printf("%c ", grid[i][j]);
}
printf("║\n");
}
printf("╚");
for (int i = 0; i < SIZE * 2; i++) printf("═");
printf("╝\n");
printf("\nWASD=Move Q=Quit | Indent: %d\n", indent_level);
printf("State: ");
switch (state) {
case STATE_NORMAL: printf("NORMAL"); break;
case STATE_CREATE: printf("CREATING"); break;
case STATE_SELECT_STATEMENT: printf("SELECT STATEMENT"); break;
case STATE_SET_VALUE: printf("SET VALUE"); break;
case STATE_BUILD_IF_COND:
case STATE_BUILD_WHILE_COND:
case STATE_BUILD_DO_COND: printf("BUILD CONDITION"); break;
case STATE_BUILD_EXPR: printf("BUILD EXPRESSION"); break;
case STATE_SET_DIM: printf("SET DIMENSION"); break;
case STATE_SET_ARRAY_SIZE: printf("SET SIZE [%d/%d]", current_dim_count + 1, arrs[selected_entity].dimensions); break;
case STATE_SET_LOOP_INIT: printf("FOR INIT"); break;
case STATE_SET_LOOP_COND: printf("FOR CONDITION"); break;
case STATE_SET_LOOP_INC: printf("FOR INCREMENT"); break;
default: printf("UNKNOWN"); break;
}
printf("\n");
if (state == STATE_SET_VALUE || state == STATE_BUILD_IF_COND || state == STATE_BUILD_WHILE_COND || state == STATE_BUILD_DO_COND ||
state == STATE_BUILD_EXPR || state == STATE_SET_LOOP_INIT ||
state == STATE_SET_LOOP_COND || state == STATE_SET_LOOP_INC) {
printf("Val1: %s | Op: %s | Val2: %s\n", current_value, current_operation, current_value2);
printf("%s\n", setting_second_value ? "(2nd value)" : "(1st value)");
} else if (state == STATE_SET_DIM) {
printf("Dimensions (1-3): %s\n", current_value);
} else if (state == STATE_SELECT_STATEMENT) {
printf("Selectors 0-9: 0=if 1=while 2=for 3=do-while 4=assign 5=call 6=break 7=return 8=}\n");
}
printf("\nLegend:\n");
printf("V=Var A=Array F=Func M=Main S=Stmt | Col3=Select Col4=Vars Col6=Arrays\n");
printf("Col11=Funcs | Bottom=0-9 | Right:[]()*+/><=&\n");
printf("S=Set U=Undo }=Close P=Print\n");
}
int main() {
init_game();
char input;
printf("Programming Snake - Write C code!\n");
printf("Create variables, arrays, functions, and control structures.\n");
printf("Press any key to start...\n");
getch();
while (1) {
draw();
int ch;
#ifdef _WIN32
if (_kbhit()) {
ch = getch();
} else {
ch = -1;
}
#else
ch = getch();
#endif
if (ch != -1) {
input = (char)ch;
if (input == 'q' || input == 'Q') break;
else if (input == 'w' || input == 'W') { dx = 0; dy = -1; }
else if (input == 's' || input == 'S') { dx = 0; dy = 1; }
else if (input == 'a' || input == 'A') { dx = -1; dy = 0; }
else if (input == 'd' || input == 'D') { dx = 1; dy = 0; }
move_snake();
}
#ifdef _WIN32
Sleep(150);
#else
usleep(150000);
#endif
}
#ifndef _WIN32
fcntl(STDIN_FILENO, F_SETFL, old_flags);
#endif
printf("\n=== FINAL CODE ===\n%s\n==================\n", code);
return 0;
}