From 894d62b01f8fb8e0ef1db7d401a155e1e89ee97a Mon Sep 17 00:00:00 2001
From: Enzo DE CARVALHO BITTENCOURT <enzo.decarvalhobittencourt@ensiie.eu>
Date: Fri, 22 Mar 2024 03:51:28 +0100
Subject: [PATCH] Upload New File

---
 main.c | 387 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 387 insertions(+)
 create mode 100644 main.c

diff --git a/main.c b/main.c
new file mode 100644
index 0000000..ee164f2
--- /dev/null
+++ b/main.c
@@ -0,0 +1,387 @@
+/******************************************************************************
+
+Copyright (c) Anzo.
+Simple Terminal based Boids
+
+===============================================================================
+
+	This program is free software: you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation, either version 3 of the License, or (at your option) any later
+version.
+
+		This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License along with
+this program. If not, see <https://www.gnu.org/licenses/>.
+
+===============================================================================
+
+small c file with boids represented in terminal, with only the libc as
+dependency. This was mostly done using Conrad Parker pseudocode boid
+implementation (http://www.kfish.org/boids/pseudocode.html), and thus lacks
+optimizations. 
+
+===============================================================================
+COMPILING AND REQUIREMENTS :
+
+terminal must support truecolor.
+
+compile this file with linkage to math library (generally -lm)
+`
+gcc main.c -lm -o boids
+`
+
+the executable takes two optional args : width and height of the board
+example :
+`
+boids 50 120
+`
+
+Theres a bunch of defines down there that parametrizes the boids. tinkering
+with them maybe fun idk
+******************************************************************************/
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h> 
+#include <sys/ioctl.h>
+#include <time.h>
+#include <fcntl.h>
+#include <sys/param.h>
+#include <string.h>
+#include <math.h>
+
+int width;
+int height;
+
+struct winsize w;
+
+int w_c; //"center" coordinates
+int h_c;
+
+/*
++---------------------------------+
+|       | h_c                     | <-- your screen
+|-------+-----------------+       |
+| w_c   |                 |       |
+|       |                 |       |
+|       |     content     |       |
+|       |                 |       |
+|       +-----------------+       |
+|                                 |
++---------------------------------+
+*/
+
+char* grid;
+char* prevGrid;
+
+int DEBUG;
+int PAUSE;
+
+void initFlushGrid()
+{
+	int h, w;//current h w
+
+	int v,r,g,b;
+
+	for (int i=0; i<width*height; i++)
+	{
+		h = (i/width) + h_c + 1;
+		w = (i%width) + w_c + 1;
+		
+		//int v = (!grid[i]) ? 0 : MIN(grid[i]*10 + 50, 255); //value
+		int r = (!grid[i]) ? 0 : MIN(grid[i]*35 + 0, 255);
+		int g = (!grid[i]) ? 0 : MIN(grid[i]*15 + 100, 255);
+		int b = (!grid[i]) ? 0 : MIN(grid[i]*10 + 75, 255);
+		printf("\033[%i;%iH\033[48;2;%i;%i;%im ", h, w, r, g, b);
+	}
+	
+	fflush(stdout);
+	return;
+}
+
+void flushGrid()
+{
+	int h, w;//current h w
+	
+	for (int i=0; i<width*height; i++)
+	{
+		if (grid[i] != prevGrid[i])
+		{
+			h = (i/width) + h_c + 1;
+			w = (i%width) + w_c + 1;
+			//int v = (!grid[i]) ? 0 : MIN(grid[i]*10 + 50, 255); //value
+			int r = (!grid[i]) ? 0 : MIN(grid[i]*35 + 0, 255);
+			int g = (!grid[i]) ? 0 : MIN(grid[i]*15 + 100, 255);
+			int b = (!grid[i]) ? 0 : MIN(grid[i]*10 + 75, 255);
+
+			printf("\033[%i;%iH\033[48;2;%i;%i;%im ", h, w, r, g, b);
+		} 
+	}
+
+	printf("\033[0;0H");
+
+	fflush(stdout);
+	return;
+}
+
+//random float between 0 and 1
+float randf()
+{
+	return (float) random() / RAND_MAX;
+}  
+
+float norm(float x, float y)
+{
+	return sqrtf(x*x + y*y);
+}
+
+#define BOIDS_AMOUNT 500
+#define MAX_SPEED 0.4
+#define BOUNCE_BACK
+
+#define SEEING_DISTANCE 5
+
+//rule 1 cst
+#define TO_CENTER_FACTOR 0.01
+
+//rule 2 cst
+#define AWAY_DIST 0.2
+#define KEEP_ME_AWAY_FACTOR 2
+
+//rule 3 cst
+#define MATCH_VEL_FACTOR 0.125
+
+/* a boid is a point + velocity*/
+typedef struct
+{
+	float x;
+	float y;
+	float vx;
+	float vy; 
+} boid;
+
+boid *boidsList;
+
+float boidDist(boid a, boid b)
+{
+	return norm(a.x - b.x, a.y - b.y);
+} 
+
+int inSight(boid a, boid b)
+{
+	return (boidDist(a,b) < (float)SEEING_DISTANCE) ? 1 : 0;
+} 
+
+//randomly put them boids in the board.
+//with random init velocity.
+void initBoids()
+{
+	boid* b;
+	float normb;
+	for (int i=0; i < BOIDS_AMOUNT; i++)
+	{
+		b = &boidsList[i];
+
+		boidsList[i].x = randf() * width;
+		boidsList[i].y = randf() * height;
+
+		boidsList[i].vx = randf() * 2 - 1;
+		boidsList[i].vy = randf() * 2 - 1;
+	}
+	
+	//limit velocity	
+	normb = norm(b->vx, b->vy);
+	if ( normb > MAX_SPEED)
+	{
+		b->vx = (b->vx / normb) * MAX_SPEED;
+		b->vy = (b->vy / normb) * MAX_SPEED;
+	} 
+} 
+
+//apply the three rules of boid mvmt
+void UpdateBoids()
+{
+	boid* b;
+	float normb;
+	
+	float r1vx;
+	float r1vy;
+
+	float r2vx;
+	float r2vy;
+	
+	float r3vx;
+	float r3vy;
+
+	int N = 0; //number of boids in sight 
+
+	for (int i=0; i < BOIDS_AMOUNT; i++)
+	{
+		b = &boidsList[i];
+		
+		//rule 1 : move toward percieved center (no "seeing distance")
+		//-----------------------------------------------------------
+		N = 0;
+		r1vx = 0;
+		r1vy = 0;
+
+		for (int j=0; j < BOIDS_AMOUNT; j++)
+		{
+			if (i==j){continue;}
+			if (inSight(*b, boidsList[j]))
+			{
+				r1vx += boidsList[j].x;
+				r1vy += boidsList[j].y;
+				N += 1;
+			}	
+		}
+			
+		r1vx = r1vx / MAX(N, 1);
+		r1vy = r1vy / MAX(N, 1);
+		//here, vx and vy holds barycenter of all other boids
+
+		r1vx = (r1vx - b->x) * TO_CENTER_FACTOR;
+		r1vy = (r1vy - b->y) * TO_CENTER_FACTOR;
+		// correct vector
+
+		//rule 2 : try not to collide
+		//----------------------------------------------------------	
+		N = 0;
+		r2vx = 0;
+		r2vy = 0;
+		for (int j=0; j < BOIDS_AMOUNT; j++)
+		{
+			if (i==j){continue;}
+			normb = norm(b->x - boidsList[j].x, b->y - boidsList[j].y);
+			if ( normb < AWAY_DIST)
+			{ 
+				r2vx = (b->x - boidsList[j].x) * KEEP_ME_AWAY_FACTOR;
+				r2vy = (b->y - boidsList[j].y) * KEEP_ME_AWAY_FACTOR;
+			}	
+		}
+			
+		//rule 3 : match velocity of peers (no seeing distance)
+		//---------------------------------------------------------
+		N = 0;
+		r3vx = 0;
+		r3vy = 0;
+
+		for (int j=0; j < BOIDS_AMOUNT; j++)
+		{
+			if (i==j){continue;}
+			if (inSight(*b, boidsList[j]))
+			{ 
+				r3vx += boidsList[j].vx;
+				r3vy += boidsList[j].vy; 
+				N += 1;
+			}	
+		}
+
+		r3vx = (r3vx / MAX(N,1)) * MATCH_VEL_FACTOR;
+		r3vy = (r3vy / MAX(N,1)) * MATCH_VEL_FACTOR;
+		
+		//add velocity	
+		b->vx += r1vx + r2vx + r3vx;
+		b->vy += r1vy + r2vy + r3vy;	
+
+		//limit velocity
+		normb = norm(b->vx, b->vy);
+		if ( normb > MAX_SPEED)
+		{
+			b->vx = (b->vx / normb) * MAX_SPEED;
+			b->vy = (b->vy / normb) * MAX_SPEED;
+		} 
+		
+#ifdef BOUNCE_BACK  		
+		//bounce back b inside board
+		if (b->x + b->vx > width || b->x + b->vx < 0)
+		{b->vx *= -1;}
+
+		if (b->y + b->vy > height || b->y + b->vy < 0)
+		{b->vy *= -1;}
+		
+#else
+		//warp pos b inside the board
+		if (b->x + b->vx > width)
+		{b->x = 0 + b->vx;}
+
+		if (b->x + b->vx < 0)
+		{b->x = width + b->vx;} 
+		
+		if (b->vy + b->y > height)
+		{b->y = height + b->vy;}
+
+		if (b->y + b->vy < 0)
+		{b->y = height + b->vy;} 
+#endif
+		
+		//update pos
+		b->x += b->vx;
+		b->y += b->vy;	
+	} 
+} 
+//reset the grid to 0, and 
+//add one to each cell of where a boid is.
+void renderBoidsToGrid()
+{
+	for (int i = 0; i < width*height; i++)
+	{grid[i]=0;}
+
+	int pos; // index in grid
+	for (int ib = 0; ib < BOIDS_AMOUNT ; ib++)
+	{
+		pos = ((int)boidsList[ib].y)*width + (int)boidsList[ib].x;
+		grid[pos] += 1;
+		//printf("grid[%i] : %i\n", pos, grid[pos]);
+	} 
+}
+
+int main(int argc, char** argv)
+{
+	DEBUG = 0;
+	
+	//init rng with seed
+	srandom(time(NULL));
+	
+	//init grids
+  ioctl(0, TIOCGWINSZ, &w);
+	if (argc == 3)
+	{
+		width=atoi(argv[1]);
+		height=atoi(argv[2]);
+	}
+	else
+	{
+		width=w.ws_col;
+		height=w.ws_row;
+	}
+	
+	w_c = (w.ws_col - width) / 2;
+	h_c = (w.ws_row - height) / 2;
+
+	grid = calloc((width*height),sizeof(char));
+	prevGrid = calloc((width*height),sizeof(char));
+	
+	//init boids
+	boidsList = calloc(BOIDS_AMOUNT, sizeof(boid));
+	
+	printf("\033[1J");
+
+	initBoids();
+	
+	renderBoidsToGrid();
+	initFlushGrid();
+	
+	while(1)
+	{ 	
+		usleep(2500);
+		memcpy(prevGrid, grid, width*height*sizeof(char));
+		UpdateBoids();
+		renderBoidsToGrid();
+		flushGrid();
+	}
+}
-- 
GitLab