about summary refs log tree commit diff
path: root/src/trainer/main.c
diff options
context:
space:
mode:
authorvenomade <venomade@venomade.com>2025-02-27 17:25:46 +0000
committervenomade <venomade@venomade.com>2025-02-27 17:25:46 +0000
commit259c727658485ea00d6ef8617ecab579be871470 (patch)
tree5f548781584cf942b0c8a9101eed124da902c9ce /src/trainer/main.c
Initial Commit
Diffstat (limited to 'src/trainer/main.c')
-rw-r--r--src/trainer/main.c135
1 files changed, 135 insertions, 0 deletions
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;
+}