summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main.c4
-rw-r--r--src/puzzles/puzzle.c22
-rw-r--r--src/puzzles/puzzle.h2
-rw-r--r--src/resources/config.c100
-rw-r--r--src/resources/resources.h16
5 files changed, 136 insertions, 8 deletions
diff --git a/src/main.c b/src/main.c
index 04e857c..e83454e 100644
--- a/src/main.c
+++ b/src/main.c
@@ -5,6 +5,10 @@
int main(void) {
+ if (!ReadConfig(DEFAULT_CONFIG_LOCATION)) {
+ return 1;
+ }
+
if (!InitSceneStack()) {
printf("Failed to create a scene stack\n");
return 1;
diff --git a/src/puzzles/puzzle.c b/src/puzzles/puzzle.c
index fad3f00..11328a8 100644
--- a/src/puzzles/puzzle.c
+++ b/src/puzzles/puzzle.c
@@ -1,5 +1,7 @@
+#include "../resources/resources.h"
#include "puzzle.h"
#include "../wren_inter/wren_inter.h"
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wren.h>
@@ -116,7 +118,7 @@ bool CheckResult(PuzzleIO *io, WrenVM *vm) {
}
}
-enum PUZZLE_TEST_RESULT RunTest(Test *test, WrenVM *vm) {
+enum PUZZLE_TEST_RESULT RunTest(Test *test, WrenVM *vm, size_t max_op) {
wrenEnsureSlots(vm, test->argc + 1); // finction handle + arguments
wrenGetVariable(vm, USER_MODULE_NAME, test->RecieverName, 0);
@@ -136,14 +138,15 @@ enum PUZZLE_TEST_RESULT RunTest(Test *test, WrenVM *vm) {
PutIOIntoSlot(i+1, &test->argv[i], vm);
}
- WrenInterpretResult call_result = wrenCall(vm, fn_handle);
-
+ WrenInterpretResult call_result = wrenCallLim(vm, fn_handle, max_op);
switch (call_result) {
case WREN_RESULT_COMPILE_ERROR:
return RESULT_COMPTIME_ERR;
case WREN_RESULT_RUNTIME_ERROR:
return RESULT_RUNTIME_ERR;
+ case WREN_RESULT_RUNTIME_LIMIT:
+ return RESULT_TIMEOUT;
default: break;
}
@@ -160,8 +163,8 @@ enum PUZZLE_TEST_RESULT RunTest(Test *test, WrenVM *vm) {
}
// Returns the res ptr. Does not modify the address
-SubmitionResult *TryEvaluateUserCode(WrenVM *vm, char *script, SubmitionResult *res) {
- WrenInterpretResult result = wrenInterpret(vm, "main", script);
+SubmitionResult *TryEvaluateUserCode(WrenVM *vm, char *script, SubmitionResult *res, size_t max_op) {
+ WrenInterpretResult result = wrenInterpretLim(vm, "main", script, max_op);
res->result = RESULT_OK;
switch (result) {
case WREN_RESULT_COMPILE_ERROR:
@@ -170,6 +173,10 @@ SubmitionResult *TryEvaluateUserCode(WrenVM *vm, char *script, SubmitionResult *
case WREN_RESULT_RUNTIME_ERROR:
res->result = RESULT_RUNTIME_ERR;
return res;
+ case WREN_RESULT_RUNTIME_LIMIT:
+ res->result = RESULT_TIMEOUT;
+ printf("Timeout with max_op %zu\n", max_op);
+ return res;
default: break;
}
return res;
@@ -187,6 +194,7 @@ SubmitionResult *PrepareResult(SubmitionResult *self,
}
SubmitionResult *SubmitSolution(Puzzle *self, char *script) {
+ Config *cfg = GetConfig();
if (self == NULL || script == NULL) return NULL;
SubmitionResult *res = malloc(sizeof(SubmitionResult));
@@ -196,13 +204,13 @@ SubmitionResult *SubmitSolution(Puzzle *self, char *script) {
return res;
}
- res = TryEvaluateUserCode(vm, script, res);
+ res = TryEvaluateUserCode(vm, script, res, cfg->MaxOperations);
if (res->result != RESULT_OK) {
return PrepareResult(res, vm, res->result);
}
for (size_t i = 0; i < self->TestC; i++) {
- enum PUZZLE_TEST_RESULT test_res = RunTest(&self->Tests[i], vm);
+ enum PUZZLE_TEST_RESULT test_res = RunTest(&self->Tests[i], vm, cfg->MaxOperations);
switch (test_res) {
case WREN_RESULT_COMPILE_ERROR:
return PrepareResult(res, vm, RESULT_COMPTIME_ERR);
diff --git a/src/puzzles/puzzle.h b/src/puzzles/puzzle.h
index 28ab6ca..4dfd0f8 100644
--- a/src/puzzles/puzzle.h
+++ b/src/puzzles/puzzle.h
@@ -29,7 +29,7 @@ typedef struct {
/// The user submitted code should be evaluated by this point.
/// The entry point should be registered and the absence of the
/// Main method signatire will be concidered an error
-enum PUZZLE_TEST_RESULT RunTest(Test *test, WrenVM *vm);
+enum PUZZLE_TEST_RESULT RunTest(Test *test, WrenVM *vm, size_t max_op);
typedef struct {
char *Name;
diff --git a/src/resources/config.c b/src/resources/config.c
new file mode 100644
index 0000000..05b80cd
--- /dev/null
+++ b/src/resources/config.c
@@ -0,0 +1,100 @@
+#include "resources.h"
+#include <stdlib.h>
+#include <stddef.h>
+#include <raylib.h>
+#include <stdio.h>
+#include <string.h>
+
+Config config = {
+ .MaxOperations = DEFAULT_MAX_OPS,
+};
+
+bool startsWith(const char *str, const char *prefix) {
+ if (str == NULL || prefix == NULL) {
+ return false;
+ }
+
+ size_t prefix_len = strlen(prefix);
+
+ if (strlen(str) < prefix_len) {
+ return false;
+ }
+
+ return strncmp(str, prefix, prefix_len) == 0;
+}
+
+// Strips everything before '=' (including). Does not allocate.
+char *stripName(char *line, size_t len) {
+ if (line == NULL) {
+ return NULL;
+ }
+
+ for (size_t ptr = 0; ptr < len; ptr++) {
+ if (line[ptr] == '\0') {
+ return NULL;
+ }
+ if (line[ptr] == '=') {
+ return &line[ptr + 1];
+ }
+ }
+
+ return NULL;
+}
+
+// Reads one line and assigns the param if found
+void evaluateConfigLive(char *line) {
+ size_t len = strlen(line);
+ // Empty lines and comments
+ if (len <= 1 || line[0] == '#') return;
+ // Removing a new line
+ if (line[len-1] == '\n') {
+ line[len-1] = 0x0;
+ len -= 1;
+ }
+
+ if (startsWith(line, "MaxOperations")) {
+ char *value = stripName(line, len);
+
+ char *endptr;
+ unsigned long long parsed = strtoull(value, &endptr, 10);
+ if (value == endptr || *endptr != '\0') {
+ TraceLog(LOG_WARNING, "Failed to parse the value for MaxOperations. Provided value: '%s'", value);
+ return;
+ }
+ config.MaxOperations = parsed;
+ return;
+ }
+
+}
+
+bool ReadConfig(const char *location) {
+ FILE *file = fopen(location, "r");
+ if (file == NULL) {
+ perror("Failed to open the config file");
+ return false;
+ }
+
+ fseek(file, 0, SEEK_END);
+ long size = ftell(file);
+ rewind(file);
+
+ char* buffer = malloc(size + 1);
+ if (buffer == NULL) {
+ fclose(file);
+ perror("Failed to load the config file");
+ return false;
+ }
+
+
+ while (fgets(buffer, size, file)) {
+ evaluateConfigLive(buffer);
+ }
+
+ free(buffer);
+ fclose(file);
+ return true;
+}
+
+Config *GetConfig() {
+ return &config;
+}
diff --git a/src/resources/resources.h b/src/resources/resources.h
index d3ad840..8f6cd1d 100644
--- a/src/resources/resources.h
+++ b/src/resources/resources.h
@@ -1,8 +1,21 @@
+#include <stddef.h>
#include <raylib.h>
#ifndef RESOURCES_H
#define RESOURCES_H
+static const size_t DEFAULT_MAX_OPS = 2 * 1000 * 1000;
+static const char *DEFAULT_CONFIG_LOCATION = "config.conf";
+
+typedef struct {
+ // The maximum amount of operations performed by a VM on each check.
+ //
+ // Keep in mind that setting this parameter higher will make the infinite
+ // loops in your submission longer to detect. Lowering this parameter will make
+ // the limitation on the code runtime stricter.
+ size_t MaxOperations;
+} Config;
+
void DrawBackground();
/// #670916 as RGBA
@@ -18,6 +31,9 @@ static const Color COLORSCHEME_WHITE = { 233, 225, 185, 255 };
/// #48A56A as RGBA
static const Color COLORSCHEME_GREEN = { 72, 165, 106, 255 };
+bool ReadConfig(const char *location);
+Config *GetConfig();
+
void LoadResources();
Font *GetMainFont();
Font *GetMonoFont();