Skip to content

Instantly share code, notes, and snippets.

@SanderMertens
Last active February 27, 2023 15:25
Show Gist options
  • Save SanderMertens/cceeea0d209e1c9d4ec30c1bb162ae3d to your computer and use it in GitHub Desktop.
Save SanderMertens/cceeea0d209e1c9d4ec30c1bb162ae3d to your computer and use it in GitHub Desktop.
#include <c_app.h>
#include "flecs.h"
#include <stdio.h>
#include <stdlib.h>
#define STARS (1000)
#define PLANETS_MAX (10)
#define P_PLANET_WATER (0.1)
#define P_PLANET_OIL (0.005)
#define P_PLANET_COPPER (0.05)
#define P_PLANET_URANIUM (0.01)
#define SPACESHIPS (10 * 1000)
#define P_FREIGHTER (0.1)
#define T_LIQUID_TRANSPORT (0.4)
#define T_SOLID_TRANSPORT (0.8)
#define T_RADIOACTIVE_TRANSPORT (1.0)
#define MEASURE (2.0)
typedef struct {
float value;
} Value;
float randf(float max) {
return max * (float)rand() / (float)RAND_MAX;
}
bool chance(float p) {
return randf(1.0) > (1.0 - p);
}
int main(int argc, char* argv[])
{
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Value);
ecs_struct(world, {
.entity = ecs_id(Value),
.members = {
{ .name = "value", .type = ecs_id(ecs_f32_t) }
}
});
/* Relationships */
ECS_ENTITY(world, InSystem, (With, ChildOf));
ECS_TAG(world, Has);
ECS_TAG(world, Requires);
ECS_TAG(world, Faction);
/* Celestial bodies */
ECS_TAG(world, Star);
ECS_TAG(world, Planet);
ECS_TAG(world, Moon);
/* Spaceships */
ECS_TAG(world, SpaceShip);
ECS_TAG(world, Freighter);
ECS_TAG(world, LiquidStorage);
ECS_TAG(world, SolidStorage);
ECS_TAG(world, RadioActiveStorage);
/* Factions */
ECS_TAG(world, Humans);
ECS_TAG(world, Dolphins);
ECS_TAG(world, Zorgs);
/* Resources */
ECS_ENTITY(world, Water, (Requires, LiquidStorage));
ECS_ENTITY(world, Oil, (Requires, LiquidStorage));
ECS_ENTITY(world, Copper, (Requires, SolidStorage));
ECS_ENTITY(world, Uranium, (Requires, RadioActiveStorage));
ecs_set(world, Water, Value, {0.14});
ecs_set(world, Oil, Value, {23});
ecs_set(world, Copper, Value, {1.2});
ecs_set(world, Uranium, Value, {85.7});
int32_t planet_count = 0, freighter_count = 0;
ecs_time_t t = {0};
ecs_time_measure(&t);
ecs_entity_t *stars = ecs_os_malloc_n(ecs_entity_t, STARS);
for (int s = 0; s < STARS; s ++) {
stars[s] = ecs_new(world, Star);
int planets = randf(PLANETS_MAX);
for (int p = 0; p < planets; p ++) {
ecs_entity_t planet = ecs_new(world, Planet);
ecs_add_pair(world, planet, InSystem, stars[s]);
if (chance(P_PLANET_WATER)) {
ecs_add_pair(world, planet, Has, Water);
}
if (chance(P_PLANET_OIL)) {
ecs_add_pair(world, planet, Has, Oil);
}
if (chance(P_PLANET_COPPER)) {
ecs_add_pair(world, planet, Has, Copper);
}
if (chance(P_PLANET_URANIUM)) {
ecs_add_pair(world, planet, Has, Uranium);
}
float faction = randf(1.0);
if (faction < 0.33) {
ecs_add_pair(world, planet, Faction, Humans);
} else if (faction < 0.66) {
ecs_add_pair(world, planet, Faction, Dolphins);
} else {
ecs_add_pair(world, planet, Faction, Zorgs);
}
planet_count ++;
}
}
ecs_entity_t *spaceships = ecs_os_malloc_n(ecs_entity_t, SPACESHIPS);
for (int s = 0; s < SPACESHIPS; s ++) {
spaceships[s] = ecs_new(world, SpaceShip);
ecs_entity_t star = stars[(int)randf(STARS)];
ecs_add_pair(world, spaceships[s], InSystem, star);
if (chance(P_FREIGHTER)) {
ecs_add(world, spaceships[s], Freighter);
float kind = randf(1.0);
if (kind < T_LIQUID_TRANSPORT) {
ecs_add_pair(world, spaceships[s], Has, LiquidStorage);
} else if (kind < T_SOLID_TRANSPORT) {
ecs_add_pair(world, spaceships[s], Has, SolidStorage);
} else {
ecs_add_pair(world, spaceships[s], Has, RadioActiveStorage);
}
freighter_count ++;
}
float faction = randf(1.0);
if (faction < 0.33) {
ecs_add_pair(world, spaceships[s], Faction, Humans);
} else if (faction < 0.66) {
ecs_add_pair(world, spaceships[s], Faction, Dolphins);
} else {
ecs_add_pair(world, spaceships[s], Faction, Zorgs);
}
}
printf("Loaded in %.2fs (stars = %d, planets = %d, spaceships = %d, freighters = %d)\n",
ecs_time_measure(&t),
STARS, planet_count, SPACESHIPS, freighter_count);
// Uncomment to run as a command line app
// char cmd[1024];
// while (true) {
// printf("?- "); fgets(cmd, 1024, stdin);
// ecs_rule_t *r = ecs_rule(world, {
// .expr = cmd
// });
// if (!r) {
// continue;
// }
// ecs_iter_t it = ecs_rule_iter(world, r);
// while (ecs_iter_next(&it)) {
// char *str = ecs_iter_str(&it);
// printf("%s\n", str);
// ecs_os_free(str);
// }
// char *str = ecs_rule_str(r);
// printf("%s\n", str);
// ecs_os_free(str);
// }
const char *q =
"Freighter($this), "
"InSystem($this, $star), "
"InSystem($_planet, $star), "
"Planet($_planet), "
"Faction($this, $faction), "
"Faction($_planet, $faction), "
"Has($_planet, $resource), "
"Requires($resource, $requires), "
"Has($this, $requires), "
"Value($resource)"
;
ecs_rule_t *r = ecs_rule(world, {
.entity = ecs_entity(world, { .name = "resource_transports" }),
.expr = q,
});
int32_t iter = 0, count = 0;
ecs_time_measure(&t);
ecs_time_t start = t;
while (true) {
ecs_iter_t it = ecs_rule_iter(world, r);
while (ecs_rule_next(&it)) {
count += it.count;
}
iter ++;
if (!(iter % 100)) {
ecs_time_t tt = start;
if (ecs_time_measure(&tt) > MEASURE) {
break;
}
}
}
printf("query takes %.3f ms (%d found)\n",
(ecs_time_measure(&t) / (float)iter) * 1000,
count / iter);
// Prints profile in debug mode
ecs_iter_t it = ecs_rule_iter(world, r);
it.flags |= EcsIterProfile;
while (ecs_rule_next(&it)) {
count += it.count;
}
return ecs_app_run(world, &(ecs_app_desc_t) {
.enable_rest = true,
.target_fps = 60
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment