This commit is contained in:
cannoli-fruit 2026-07-16 16:13:00 -04:00
commit c7cab684a5
8 changed files with 300 additions and 0 deletions

2
.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
mt-tree
build/*

3
.gitmodules vendored Normal file
View file

@ -0,0 +1,3 @@
[submodule "Lazyc"]
path = Lazyc
url = https://youra.monster/git/Cody/Lazyc.git

1
Lazyc Submodule

@ -0,0 +1 @@
Subproject commit c92f5df3546b4e5fb7540de58c847129acde7b20

5
README.md Normal file
View file

@ -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)

63
bldit.lua Normal file
View file

@ -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,
}
}

12
pentagon.txt Normal file
View file

@ -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

206
src/main.c Normal file
View file

@ -0,0 +1,206 @@
#include <stdio.h>
#include <stdlib.h>
#define LAZY_IMPL
#include "lazy.h"
#include "raylib.h"
#include "time.h"
#include <ctype.h>
#include <math.h>
#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);
}

8
triangle.txt Normal file
View file

@ -0,0 +1,8 @@
dec 0
dec 1
dec 2
con 0 1
con 1 2
con 0 2
go