diff options
author | venomade <venomade@venomade.com> | 2025-02-27 17:25:46 +0000 |
---|---|---|
committer | venomade <venomade@venomade.com> | 2025-02-27 17:25:46 +0000 |
commit | 259c727658485ea00d6ef8617ecab579be871470 (patch) | |
tree | 5f548781584cf942b0c8a9101eed124da902c9ce /src/trainer |
Initial Commit
Diffstat (limited to 'src/trainer')
-rw-r--r-- | src/trainer/logging.c | 71 | ||||
-rw-r--r-- | src/trainer/logging.h | 14 | ||||
-rw-r--r-- | src/trainer/main.c | 135 |
3 files changed, 220 insertions, 0 deletions
diff --git a/src/trainer/logging.c b/src/trainer/logging.c new file mode 100644 index 0000000..f35ab73 --- /dev/null +++ b/src/trainer/logging.c @@ -0,0 +1,71 @@ +// File by "Yangelis" https://github.com/yangelis + +#include "../game.h" + +FILE *gnuplot_pipe = 0; +#define nOfGnuplotCmds 14 +char *gnuplotCmds[] = { + "reset\n", + "set size 1,1\n", + "set origin 0,0\n", + "set xlabel 'Generations'\n", + "set multiplot layout 2, 2 columnsfirst title 'gp live stats'\n", + "set ylabel 'Avg Lifetime'\n", + "plot 'log.dat' using 1:2 with lines lw 2 lt 10 notitle \n", + "set ylabel 'Min lifetime'\n", + "plot 'log.dat' using 1:3 with lines lw 2 lt 10 notitle\n", + "set ylabel 'Max lifetime'\n", + "plot 'log.dat' using 1:4 with lines lw 2 lt 10 notitle\n", + "set ylabel 'Food Eaten'\n", + "plot 'log.dat' using 1:5 with lines lw 2 lt 10 notitle\n", + "unset multiplot\n" +}; + + +float avg_lifetime(Agent *agents) { + int result = 0.0; + for (size_t i = 0; i < AGENTS_COUNT; ++i) { + result += agents[i].lifetime; + } + return (float)result / AGENTS_COUNT; +} +void log_header(FILE *stream) { + fprintf(stream, "#Loggind generations\n"); + fprintf( + stream, + "#Generation, Avg Lifetime, Min Lifetime, Max Lifetime, Food eaten\n"); + gnuplot_pipe = popen("gnuplot -p", "w"); +} +void log_generation(FILE *stream, int gen, Game *game) { + float avg_lf = avg_lifetime(game->agents); + int max_lifetime = game->agents[0].lifetime; + int min_lifetime = game->agents[0].lifetime; + for (size_t i = 1; i < AGENTS_COUNT; ++i) { + if (game->agents[i].lifetime > max_lifetime) { + max_lifetime = game->agents[i].lifetime; + } + if (game->agents[i].lifetime < min_lifetime) { + min_lifetime = game->agents[i].lifetime; + } + } + + int food_eaten = FOODS_COUNT; + for (size_t y = 0; y < BOARD_HEIGHT; ++y) { + for (size_t x = 0; x < BOARD_WIDTH; ++x) { + if (game->foods_map[y][x]) { + food_eaten--; + } + } + } + + /* Writing to log file*/ + fprintf(stream, "%d, %f, %d, %d, %d\n", gen, avg_lf, min_lifetime, + max_lifetime, food_eaten); +} +void log_live_update(void) { + for (size_t i = 0; i < nOfGnuplotCmds; ++i) { + fprintf(gnuplot_pipe, "%s \n", gnuplotCmds[i]); + } + fflush(gnuplot_pipe); +} +void log_close_pipe(void) { pclose(gnuplot_pipe); } diff --git a/src/trainer/logging.h b/src/trainer/logging.h new file mode 100644 index 0000000..93cb595 --- /dev/null +++ b/src/trainer/logging.h @@ -0,0 +1,14 @@ +#ifndef LOGGING_H +#define LOGGING_H + +#include "../game.h" + +void log_header(FILE *stream); + +void log_generation(FILE *stream, int gen, Game *game); + +void log_close_pipe(void); + +void log_live_update(void); + +#endif diff --git a/src/trainer/main.c b/src/trainer/main.c new file mode 100644 index 0000000..fa4d97f --- /dev/null +++ b/src/trainer/main.c @@ -0,0 +1,135 @@ +#include <assert.h> +#include <signal.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#include <SDL2/SDL.h> + +#include "../game.h" +#include "logging.h" + +Game games[2] = {0}; + +// Tsoding is now a 3-Star Developer! +const char *tsoding_shift(int *argc, char ***argv) { + assert(*argc > 0); + const char* result = **argv; + *argc -= 1; + *argv += 1; + return result; +} + +void usage(FILE *stream) { + fprintf(stream, "Usage: ./gp_trainer [OPTIONS]\n"); + fprintf(stream, " --gen|g <NUMBER>\n"); + fprintf(stream, " Amount of generations (default: 100)\n"); + fprintf(stream, " --out|o <FILEPATH>\n"); + fprintf(stream, " Output filepath (default: out.bin)\n"); + fprintf(stream, " --plot|p\n"); + fprintf(stream, " Enable Gnuplot live reporting\n"); +} + +FILE* gnulog; +int gnuplot; +int current; +const char* output_filepath; + +void ctrlc(int signum) { + if (gnuplot) { + log_close_pipe(); + fclose(gnulog); + } + + dump_game(output_filepath, &games[current]); + exit(1); +} + +int main(int argc, char *argv[]) { + + signal(SIGINT, ctrlc); + + tsoding_shift(&argc, &argv); //Skip Program Name + + srand(time(NULL)); + int gen_count = 100; + output_filepath = "out.bin"; + gnuplot = 0; + + while (argc > 0) { + const char *flag = tsoding_shift(&argc, &argv); + + if (strcmp(flag, "--gen") == 0 || strcmp(flag, "-g") == 0) { + if (argc == 0) { + usage(stderr); + fprintf(stderr, "ERROR: no value provided for flag %s\n", flag); + exit(1); + } + const char *value = tsoding_shift(&argc, &argv); + gen_count = atoi(value); + + } else if (strcmp(flag, "--out") == 0 || strcmp(flag, "-o") == 0) { + if (argc == 0) { + usage(stderr); + fprintf(stderr, "ERROR: no value provided for flag %s\n", flag); + exit(1); + } + const char *value = tsoding_shift(&argc, &argv); + output_filepath = value; + + } else if (strcmp(flag, "--plot") == 0 || strcmp(flag, "-p") == 0) { + gnuplot = 1; + + } else if (strcmp(flag, "--help") == 0 || strcmp(flag, "-h") == 0) { + usage(stdout); + exit(0); + } else { + usage(stderr); + fprintf(stderr, "ERROR: unknown flag: %s\n", flag); + exit(1); + } + } + + if (gnuplot) { + gnulog = fopen("log.dat", "w"); + log_header(gnulog); + } + + current = 0; + + init_game(&games[current]); + + for (int i = 0; i < gen_count; ++i) { + fprintf(stderr, "Generation %d... ", i); + fflush(stderr); + + clock_t begin = clock(); + while (!is_everyone_dead(&games[current])) { + step_game(&games[current]); + } + + printf("%fs\n", (float)(clock() - begin) / (float) CLOCKS_PER_SEC); + fflush(stdout); + + if (gnuplot) { + log_generation(gnulog, i, &games[current]); + fflush(gnulog); + log_live_update(); + } + + int next = 1 - current; + make_next_generation(&games[current], &games[next]); + current = next; + } + + if (gnuplot) { + log_close_pipe(); + fclose(gnulog); + } + + dump_game(output_filepath, &games[current]); + + return 0; +} |