summaryrefslogtreecommitdiff
path: root/src/puzzles
diff options
context:
space:
mode:
authorphysick <mynameisgennadiy@vk.com>2026-07-15 17:46:13 +0500
committerphysick <mynameisgennadiy@vk.com>2026-07-15 17:46:13 +0500
commit8b79b8149d1e23d90b5871f980aec65d8aa7ae23 (patch)
tree88a8788b75270dba53a15cbc2b6e0916f05301c6 /src/puzzles
parentf314b56da42e1ead200e2373e9b214f77290d03b (diff)
Puzzle infrastructure pt 1.
Diffstat (limited to 'src/puzzles')
-rw-r--r--src/puzzles/puzzle.c104
-rw-r--r--src/puzzles/puzzle.h32
2 files changed, 133 insertions, 3 deletions
diff --git a/src/puzzles/puzzle.c b/src/puzzles/puzzle.c
index cbad998..22f7a4d 100644
--- a/src/puzzles/puzzle.c
+++ b/src/puzzles/puzzle.c
@@ -1,21 +1,121 @@
#include "puzzle.h"
+#include "../wren_inter/wren_inter.h"
#include <stdlib.h>
#include <string.h>
+#include <wren.h>
+
+/// Returns 1 test puzzle for the GetTestPuzzle segment
+Test *getTestPuzzleTests() {
+ Test *outp = malloc(sizeof(Test));
+ outp->RecieverName = strdup("main");
+ outp->MainMethodSignature = strdup("call(_)");
+
+ outp->argc = 1;
+ outp->argv = malloc(sizeof(PuzzleIO));
+ outp->argv->type = WREN_TYPE_STRING;
+ outp->argv->value = strdup("Hello");
+
+ outp->ExpectedResult.type = WREN_TYPE_STRING;
+ outp->ExpectedResult.value = strdup("Hello");
+ return outp;
+}
Puzzle *GetTestPuzzle() {
Puzzle *outp = malloc(sizeof(Puzzle));
if (outp == NULL) return NULL;
outp->Name = strdup("Test puzzle");
- outp->Description = strdup("In this puzzle you will have to return the input string\n-\n-\n-\n-\n-\n-\n-\n-\n-\n-\n-\n-\n-\n-\n-\n-\n-\n-\n-\n-\n-\n-\n-\n-\n-\n-\n-\n-\n-\n-\n-\n-\n-\n-\n-\nThis is a line that should be somewhere down");
+ outp->Description = strdup("In this puzzle you will have to return the input string");
+ outp->InitialCode = strdup( "var main = Fn.new { |name| \n System.print(\"Hello, %(name)!\")\n}\n\nmain.call(\"world\")");
+ outp->TestC = 1;
+ outp->Tests = getTestPuzzleTests();
return outp;
}
+void FreeTests(Test *Tests, size_t TestC) {
+ if (TestC == 0 || Tests == NULL) return;
+ for (size_t i = 0; i < TestC; i++) {
+ Test *t = &Tests[i];
+ free(t->RecieverName);
+ free(t->MainMethodSignature);
+ free(t->argv);
+ }
+ free(Tests);
+}
+
void FreePuzzle(Puzzle *self) {
if (self == NULL) return;
if (self->Name != NULL) free(self->Name);
if (self->Description != NULL) free(self->Description);
- if (self->Tests != NULL) free(self->Tests);
+ if (self->InitialCode != NULL) free(self->InitialCode);
+ FreeTests(self->Tests, self->TestC);
free(self);
}
+
+
+enum PUZZLE_TEST_RESULT RunTest(Test *test, WrenVM *vm) {
+ // TODO: finish this
+ return RESULT_OK;
+}
+
+// Returns the res ptr. Does not modify the address
+SubmitionResult *TryEvaluateUserCode(WrenVM *vm, char *script, SubmitionResult *res) {
+ WrenInterpretResult result = wrenInterpret(vm, "main", script);
+ res->result = RESULT_OK;
+ switch (result) {
+ case WREN_RESULT_COMPILE_ERROR:
+ res->result = RESULT_COMPTIME_ERR;
+ return res;
+ case WREN_RESULT_RUNTIME_ERROR:
+ res->result = RESULT_RUNTIME_ERR;
+ return res;
+ default: break;
+ }
+ return res;
+}
+
+// Frees the vm. Does not modify the self address.
+SubmitionResult *PrepareResult(SubmitionResult *self,
+ WrenVM *vm,
+ enum PUZZLE_TEST_RESULT result) {
+ if (vm == NULL || self == NULL) return self;
+ self->result = result;
+ self->stdout = GetMachineOutput(vm);
+ InterpreterFreeMachine(vm);
+ return self;
+}
+
+SubmitionResult *SubmitSolution(Puzzle *self, char *script) {
+ if (self == NULL || script == NULL) return NULL;
+ SubmitionResult *res = malloc(sizeof(SubmitionResult));
+
+ WrenVM *vm = InterpreterPrepareMachine();
+ if (vm == NULL) {
+ res->result = RESULT_INIT_ERROR;
+ return res;
+ }
+
+ res = TryEvaluateUserCode(vm, script, res);
+ 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);
+ switch (test_res) {
+ case WREN_RESULT_COMPILE_ERROR:
+ return PrepareResult(res, vm, RESULT_COMPTIME_ERR);
+ case WREN_RESULT_RUNTIME_ERROR:
+ return PrepareResult(res, vm, RESULT_RUNTIME_ERR);
+ default: break;
+ }
+ }
+
+ return PrepareResult(res, vm, RESULT_OK);
+}
+
+void FreeSunmitionResult(SubmitionResult *res) {
+ if (res->stdout != NULL) free(res->stdout);
+ free(res);
+}
diff --git a/src/puzzles/puzzle.h b/src/puzzles/puzzle.h
index d530a89..6c72a18 100644
--- a/src/puzzles/puzzle.h
+++ b/src/puzzles/puzzle.h
@@ -3,6 +3,16 @@
#ifndef PUZZLE_H
+enum PUZZLE_TEST_RESULT : char {
+ RESULT_OK = 0,
+ RESULT_COMPTIME_NO_ENTRY,
+ RESULT_COMPTIME_ERR,
+ RESULT_RUNTIME_ERR,
+ // TODO: add async evaluation to prevent `while (true)` situation
+ RESULT_TIMEOUT,
+ RESULT_INIT_ERROR,
+};
+
// This is a param that would be placed in a slot
// https://wren.io/embedding/slots-and-handles.html#writing-slots
typedef struct {
@@ -13,22 +23,32 @@ typedef struct {
} PuzzleIO;
typedef struct {
+ // https://wren.io/embedding/calling-wren-from-c.html#setting-up-a-receiver
+ char *RecieverName;
// https://wren.io/embedding/calling-wren-from-c.html#getting-a-method-handle
char *MainMethodSignature;
size_t argc;
PuzzleIO *argv;
+ PuzzleIO ExpectedResult;
} Test;
+
+/// 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);
+
typedef struct {
char *Name;
char *Description;
+ char *InitialCode;
/// The tests that are accessible for an end user
size_t TestC;
Test *Tests;
} Puzzle;
-
+
// TODO
void ReadPuzzleFromFile(const char *path);
@@ -36,5 +56,15 @@ void FreePuzzle(Puzzle *self);
/// A prebuilt puzzle. Used for debuging
Puzzle *GetTestPuzzle();
+typedef struct {
+ char *stdout;
+ enum PUZZLE_TEST_RESULT result;
+} SubmitionResult;
+
+// Don't put anything in out_res, it will be overriten.
+// The stdout of the VM will be there
+SubmitionResult *SubmitSolution(Puzzle *self, char *script);
+void FreeSunmitionResult(SubmitionResult *res);
+
#define PUZZLE_H
#endif // PUZZLE_H