From fec8a1007eed33209d883d578633c3c035dec4cb Mon Sep 17 00:00:00 2001 From: Tristan Russell Date: Thu, 2 Jan 2025 21:49:40 -0500 Subject: [PATCH] feat: Initial Commit --- .gitignore | 2 ++ CMakeLists.txt | 5 +++ SS13ArcadeEnv.c | 76 ++++++++++++++++++++++++++++++++++++++++ SS13ArcadeEnv.h | 23 +++++++++++++ main.c | 92 +++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 198 insertions(+) create mode 100644 .gitignore create mode 100644 CMakeLists.txt create mode 100644 SS13ArcadeEnv.c create mode 100644 SS13ArcadeEnv.h create mode 100644 main.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4e7bf47 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +build/ +.cache diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..afa522a --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,5 @@ +cmake_minimum_required(VERSION 3.15) +project(SS13ArcadeEndpoint) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) +set(CMAKE_BUILD_TYPE Debug) +add_executable(SS13ArcadeEndpoint main.c SS13ArcadeEnv.c) diff --git a/SS13ArcadeEnv.c b/SS13ArcadeEnv.c new file mode 100644 index 0000000..4f9965e --- /dev/null +++ b/SS13ArcadeEnv.c @@ -0,0 +1,76 @@ +#include "SS13ArcadeEnv.h" +#include + +int clamp(int value, int min, int max) { + if(value < min) return min; + if(value > max) return max; + return value; +} + +void CreateEnvironment(struct SS13ArcadeEnv* env) { + env->player_hp = 30; + env->player_mp = 10; + env->enemy_hp = 45; + env->enemy_mp = 20; + env->steps = 0; +} + +void Step(struct SS13ArcadeEnv* instance, const int action, struct Observation* obs) { + int reward = 0; + bool done = false; + + switch (action) { + case 0: // Attack + instance->enemy_hp -= rand() % 4 + 2; + break; + case 1: // Heal + instance->player_hp += rand() % 6 + 2; + instance->player_mp -= rand() % 1 + 2; + break; + case 2: // Charge + instance->player_mp += rand() % 4 + 3; + break; + } + + if(instance->enemy_hp <= 0 || instance->enemy_mp <= 0) { // Enemy Defeated + reward = 1; + done = true; + } else if(instance->enemy_mp <= 5 && rand() % 1 + 9 >= 7) { // Enemy Drain Player MP + instance->player_mp -= rand() % 2 + 1; + } else if(instance->enemy_hp <= 10 && instance->enemy_mp > 4) { // Enemy Heal + instance->enemy_hp += 4; + instance->enemy_mp -= 4; + } else { + instance->player_hp -= rand() % 3 + 3; + } + + if(instance->player_hp <= 0 || instance->player_mp <= 0 || instance->steps == 200) { + reward = -1; + done = true; + } + instance->steps += 1; + + instance->player_hp = clamp(instance->player_hp, 0, 100); + instance->player_mp = clamp(instance->player_mp, 0, 100); + instance->enemy_hp = clamp(instance->enemy_hp, 0, 100); + + struct State state; + GetState(instance, &state); + + obs->state = state; + obs->reward = reward; + obs->done = done; +} + +void GetState(struct SS13ArcadeEnv* instance, struct State* state) { + state->player_hp = instance->player_hp; + state->player_mp = instance->player_mp; + state->enemy_hp = instance->enemy_hp; + state->enemy_mp = instance->enemy_mp; + state->steps = instance->steps; +} + +void Reset(struct SS13ArcadeEnv* instance, struct State* state) { + CreateEnvironment(instance); + GetState(instance, state); +} diff --git a/SS13ArcadeEnv.h b/SS13ArcadeEnv.h new file mode 100644 index 0000000..0a5d5f6 --- /dev/null +++ b/SS13ArcadeEnv.h @@ -0,0 +1,23 @@ +#ifndef ARCADE_ENV_H +#define ARCADE_ENV_H +#include + +struct __attribute__((packed)) State { + int player_hp, player_mp, enemy_hp, enemy_mp, steps; +}; + +struct __attribute__((packed)) Observation { + struct State state; + int reward; + bool done; +}; + +struct SS13ArcadeEnv { + int player_hp, player_mp, enemy_hp, enemy_mp, steps; +}; + +void CreateEnvironment(struct SS13ArcadeEnv* env); +void Step(struct SS13ArcadeEnv* instance, const int action, struct Observation* obs); +void GetState(struct SS13ArcadeEnv* env, struct State* state); +void Reset(struct SS13ArcadeEnv*, struct State* state); +#endif diff --git a/main.c b/main.c new file mode 100644 index 0000000..8608e15 --- /dev/null +++ b/main.c @@ -0,0 +1,92 @@ +#include "SS13ArcadeEnv.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int SetupServer(int* socket_fd, int port) { + printf("Starting Server\n"); + *socket_fd = socket(AF_INET, SOCK_STREAM, 0); + struct sockaddr_in server_addr; + server_addr.sin_family = AF_INET; + server_addr.sin_port = htons(port); + server_addr.sin_addr.s_addr = INADDR_ANY; + + int bound = bind(*socket_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)); + if(bound < 0) { + printf("Bind error: %s (%i)\n", strerror(errno), errno); + return -1; + } + listen(*socket_fd, 5); + return 0; +} + +int StartEnv(int port) { + int socket_fd; + int setup = SetupServer(&socket_fd, port); + if(setup < 0) { + printf("Error setting up server\n"); + return -1; + } + + printf("Waiting for connections\n"); + struct sockaddr_in client_addr; + int client_size = sizeof(client_addr); + int client_sock = accept(socket_fd, (struct sockaddr*)&client_addr, &client_size); + printf("Connection received\n"); + + int obs_size = sizeof(struct Observation); + struct SS13ArcadeEnv env; + CreateEnvironment(&env); + while(true) { + char buffer[5]; + int bytes_received; + bytes_received = recv(client_sock, buffer, sizeof(buffer), 0); + if(bytes_received < 0) { + printf("Receive Error: %s (%d)\n", strerror(errno), errno); + } else if(bytes_received == 0) { + continue; + } + + if(buffer[0] == 0x0) { // Step + uint32_t action; + memcpy(&action, buffer+1, sizeof(uint32_t)); + action = ntohl(action); + struct Observation obs; + Step(&env, action, &obs); + + //printf("Action: %i \n", action); + //printf("-- Observation --\n"); + //printf("Player HP: %i Player MP: %i\n", obs.state.player_hp, obs.state.player_mp); + //printf("Enemy HP: %i Enemy MP: %i\n", obs.state.enemy_hp, obs.state.enemy_mp); + //printf("Steps: %i Reward: %i Done: %d\n", obs.state.steps, obs.reward, obs.done); + //printf("Action: %i\n", action); + + char data[obs_size]; + memcpy(&data, &obs, obs_size); + send(client_sock, data, obs_size, 0); + } else if(buffer[0] == 0x1) { // Reset + struct State state; + Reset(&env, &state); + char data[sizeof(state)]; + memcpy(&data, &state, sizeof(state)); + send(client_sock, data, obs_size, 0); + } + } + shutdown(client_sock, SHUT_RDWR); + close(client_sock); +} + +int main(int argc, char* argv[]) { + int env = StartEnv(atoi(argv[1])); + if(env < 0) { + printf("Error starting environment"); + return 1; + } + return 0; +}