commit c7cab684a50a397b5c85bd90c2680eade180bae7 Author: cannoli-fruit Date: Thu Jul 16 16:13:00 2026 -0400 Init diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..94fad81 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +mt-tree +build/* diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..1a426d8 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "Lazyc"] + path = Lazyc + url = https://youra.monster/git/Cody/Lazyc.git diff --git a/Lazyc b/Lazyc new file mode 160000 index 0000000..c92f5df --- /dev/null +++ b/Lazyc @@ -0,0 +1 @@ +Subproject commit c92f5df3546b4e5fb7540de58c847129acde7b20 diff --git a/README.md b/README.md new file mode 100644 index 0000000..0d4506a --- /dev/null +++ b/README.md @@ -0,0 +1,5 @@ +# Monte carlo tree visualizer + +This is a tree visualizer loosely based on the monte carlo method of untangling headphones [here](https://youtu.be/Lq-Y7crQo44?t=617) + + diff --git a/bldit.lua b/bldit.lua new file mode 100644 index 0000000..755c0ec --- /dev/null +++ b/bldit.lua @@ -0,0 +1,63 @@ +bldit_version = "1.1.3" +package_version = "1.1.3" + +dependencies = {} + +exec_name = "mt-tree" +libs = "-lm -lraylib" +includes = "-I./Lazyc" + +execute = function(str) + print(str) + return os.execute(str) +end + +targets = { + default = { + build = function() + e,h,c = execute("rm -fr build") + if c ~= 0 and c ~= nil then + print("Build Error") + print("GIVEN UP") + return c + end + e,h,c = execute("mkdir build") + if c ~= 0 and c ~= nil then + print("Build Error") + print("GIVEN UP") + return c + end + cmd = [[find src -type f -name "*.c" -print]] + p = io.popen(cmd) + assert(p, "File detection error, GIVEN UP") + + for f in p:lines() do + base = f:match("([^/]+)%.c$") + obj = "build/"..base..".o" + cc = "cc -c '"..f.."' -o '"..obj.."' "..includes + e,h,c = execute(cc) + if c ~= 0 and c ~= nil then + print("Compilation Error") + print("GIVEN UP") + return c + end + end + p:close() + e,h,c = execute("cc build/*.o "..libs.." -o "..exec_name) + if c ~= 0 and c ~= nil then + print("Compilation Error") + print("GIVEN UP") + return c + end + return 0 + end, + install = function() + e,h,c = execute("cp "..exec_name.." /bin") + return c or 0 + end, + uninstall = function() + e,h,c = execute("rm /bin"..exec_name) + return c or 0 + end, + } +} diff --git a/pentagon.txt b/pentagon.txt new file mode 100644 index 0000000..3bb56e4 --- /dev/null +++ b/pentagon.txt @@ -0,0 +1,12 @@ +dec 0 +dec 1 +dec 2 +dec 3 +dec 4 +con 0 1 +con 1 2 +con 2 3 +con 3 4 +con 0 4 +go + diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..d2692e2 --- /dev/null +++ b/src/main.c @@ -0,0 +1,206 @@ +#include +#include +#define LAZY_IMPL +#include "lazy.h" +#include "raylib.h" +#include "time.h" +#include +#include + +#define WIDTH 800 +#define HEIGHT 600 +#define SPRING_LEN 150 +#define NODE_SIZE 50 +#define PHYS_NODE_ETC .x=rand()%WIDTH,.y=rand()%HEIGHT,.dx=0,.dy=0 + +double friction = 0.01; + +typedef struct { + const char *txt; + Lz_DA(void*) connections; +} Node; + +typedef struct PhysicsNode PhysicsNode; + +struct PhysicsNode{ + const char *txt; + Lz_DA(PhysicsNode*) connections; + double x,y; + double dx,dy; +}; + +void updateNode(PhysicsNode *n) { + n->x += n->dx; + n->y += n->dy; + n->dx *= (1-friction); + n->dy *= (1-friction); +} + +void applyForceToNode(PhysicsNode *n, double ddx, double ddy) { + n->dx += ddx; + n->dy += ddy; +} + +double randfloat() { + return (double)rand()/2147483648.0; +} + +// From the man page because we love disguising gnu extensions as posix +#define strncpy(dst, src, dsize) memset(mempcpy(dst, src,\ + strnlen(src, dsize)), '\0',\ + dsize - strnlen(src, dsize))\ + +int main(int argc, char **argv) { + int mode = 0; + char outbuf[4096]; // Ken Thompson please forgive me + if (argc != 1) { + if (!strcmp(argv[1],"int")) { + printf("Interactive Mode\n"); + mode = 0; + } else if (!strcmp(argv[1],"rend")) { + if (argc != 2) { + printf("Render Mode\n"); + mode = 1; + strncpy(outbuf, argv[2], 1024); + } else { + exit(2); + } + } + } + printf("Hello World!\n"); + srand(time(NULL)); + Lz_DA(PhysicsNode) physicsNodes = {0}; + + char buf[256]; + while (true) { + fgets(buf, 256, stdin); + printf("%s", buf); + if (!strcmp(buf, "go\n")) break; + if (strlen(buf) < 3 && strlen(buf) != 0) { + exit(1); + } + if (!strncmp(buf, "dec",3)) { + char *dat = malloc(253); // Leaks but linux with garbage collect + memcpy(dat, buf+3, 253); + + PhysicsNode n = (PhysicsNode) { + .txt = dat, + .connections = {0}, + PHYS_NODE_ETC + }; + lz_da_append(physicsNodes, n); + } + if (!strncmp(buf, "con",3)) { + Lz_Slc s = lz_slc_from_cstr(buf); + lz_slc_drop_left(&s,4); + Lz_Slc dst = {0}; + lz_slc_split_typ(&s, isspace, &dst); + int x1 = lz_slc_atoi(&dst); + lz_slc_split_typ(&s, isspace, &dst); + int x2 = lz_slc_atoi(&dst); + + lz_da_append(physicsNodes.data[x1].connections, &physicsNodes.data[x2]); + } + } + + if(!mode) InitWindow(WIDTH, HEIGHT, "Monte-Carlo Tree Renderer"); + if(!mode) SetTargetFPS(60); + + friction = 0.0001; + + while (mode ? friction < 0.99 : !WindowShouldClose()) { + friction *= 1.003; + if (friction >= 1.0) friction = 1.0; + char buf[256]; + snprintf(buf, 256, "Friction: %f", friction); + if(!mode) DrawText(buf, 12, 12, 24, BLUE); + if(!mode) BeginDrawing(); + if(!mode) ClearBackground(BLACK); + lz_da_foreach(PhysicsNode, n, physicsNodes) { + lz_da_foreach(PhysicsNode*, other, n->connections) { + if(!mode) DrawLine(n->x, n->y, (*other)->x, (*other)->y, RAYWHITE); + } + if(!mode) DrawCircle(n->x, n->y, NODE_SIZE, RED); + int fsize = 48; + if(!mode) DrawText(n->txt, n->x-fsize/4, n->y-fsize/2, fsize, GREEN); + } + if(!mode) EndDrawing(); + + lz_da_foreach(PhysicsNode, n, physicsNodes) { + updateNode(n); + double s = 0.001; + applyForceToNode(n, 2*s*(randfloat()-0.5), 2*s*(randfloat()-0.5)); + // Hookean spring force + lz_da_foreach(PhysicsNode*, other, n->connections) { + double delta_x = (*other)->x - n->x; + double delta_y = (*other)->y - n->y; + double dist = sqrtf(delta_x*delta_x+delta_y*delta_y); + + double disp = dist - SPRING_LEN; + double kP = 0.0002; + double f = kP*disp; + double fX = delta_x/dist * f; + double fY = delta_y/dist * f; + applyForceToNode(n, fX, fY); + applyForceToNode(*other, -fX, -fY); + } + // Electrostatic repulsion + lz_da_foreach(PhysicsNode, other, physicsNodes) { + if (other == n) continue; + double delta_x = other->x - n->x; + double delta_y = other->y - n->y; + double distsq = (delta_x*delta_x+delta_y*delta_y); + double dist = sqrtf(distsq); + + double kP = -100; + + double f = kP/distsq; + double fX = delta_x/dist * f; + double fY = delta_y/dist * f; + applyForceToNode(n, fX, fY); + } + // Get back on the damn screen + if (n->y > HEIGHT-NODE_SIZE) { + applyForceToNode(n, 0, -n->dy*1.6); + n->y = HEIGHT-NODE_SIZE-1; + } + if (n->y < NODE_SIZE) { + applyForceToNode(n, 0, -n->dy*1.6); + n->y = NODE_SIZE+1; + } + if (n->x > WIDTH-NODE_SIZE) { + applyForceToNode(n, -n->dx*1.6, 0); + n->x = WIDTH-NODE_SIZE-1; + } + if (n->x < NODE_SIZE) { + applyForceToNode(n, -n->dx*1.6, 0); + n->x = NODE_SIZE+1; + } + } + } + if (!mode) CloseWindow(); + if (!mode) exit(0); + Font font = GetFontDefault(); + Texture2D tex = font.texture; + printf("Font loaded\n"); + Image im = GenImageColor(WIDTH, HEIGHT, BLACK); + printf("Image generated\n"); + InitWindow(1,1,"AHH"); + + lz_da_foreach(PhysicsNode, n, physicsNodes) { + lz_da_foreach(PhysicsNode*, other, n->connections) { + ImageDrawLine(&im, n->x, n->y, (*other)->x, (*other)->y, RAYWHITE); + printf("Line?\n"); + } + ImageDrawCircle(&im,n->x, n->y, NODE_SIZE, RED); + printf("Circle?\n"); + float fsize = 48; + Vector2 pos = (Vector2) { .x = n->x - fsize/4, .y = n->y-fsize/2 }; + printf("Vector?\n"); + ImageDrawText(&im, n->txt, n->x-fsize/4, n->y-fsize/2, 48, GREEN); + printf("Text?\n"); + } + CloseWindow(); + + ExportImage(im, outbuf); +} diff --git a/triangle.txt b/triangle.txt new file mode 100644 index 0000000..c49fea2 --- /dev/null +++ b/triangle.txt @@ -0,0 +1,8 @@ +dec 0 +dec 1 +dec 2 +con 0 1 +con 1 2 +con 0 2 +go +