Skip to content

Commit 7040319

Browse files
authored
Merge pull request #165 from OpenBrickProtocolFoundation/c_lib_wrapper
Add C wrapper
2 parents 7a2692a + 448a3c7 commit 7040319

21 files changed

+3334
-5
lines changed

src/libs/core/helper/input_event.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
#include "./types.hpp"
44

55
enum class InputEvent : u8 {
6-
RotateLeftPressed,
6+
RotateLeftPressed = 0,
77
RotateRightPressed,
88
MoveLeftPressed,
99
MoveRightPressed,

src/libs/core/helper/versions.hpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,7 @@ namespace utils {
1313
#endif
1414

1515

16-
[[nodiscard]] inline std::string version() {
17-
18-
16+
[[nodiscard]] inline const char* version() {
1917
return STRINGIFY(OOPETRIS_VERSION);
2018
}
2119

wrapper/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,12 @@ Planned:
1515

1616
Current:
1717
- Node.js
18+
- C
1819

1920
Planned:
2021
- Python
2122
- Lua
23+
- Haskell
2224

2325
## Other
2426

wrapper/c/README.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# OOpetris C Wrapper
2+
3+
4+
## What is this?
5+
6+
This wraps oopetris functionality for C
7+
8+
9+
10+
11+
12+
## Platform support
13+
14+
We officially support Linux, Windows and MacOS, if any error occurs regarding those platform, feel free to open an issue
15+
16+
## How to obtain
17+
18+
You have to compile it yourself, we don't provide prebuilt-packages atm. The Ci may produce some artifacts, that are useable, but not optimized for installation or usage.
19+
20+
## How to build it yourself
21+
22+
This uses meson to build the wrapper, you need to install `libboopetris_recordings` to be able to use this.
23+
24+
Than you just can invoke `meson setup build` and `meson compile -C build` to build the library.
25+
26+
You can install this library by using `meson install -C build`. It comes with a pkg-config file, so it is usable for usage with other build systems.

wrapper/c/example/main.c

Lines changed: 298 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,298 @@
1+
2+
#include "oopetris_wrapper.h"
3+
#include <assert.h>
4+
#include <inttypes.h>
5+
#include <stdio.h>
6+
#include <stdlib.h>
7+
#include <unistd.h>
8+
9+
#include "oopetris_wrapper.h"
10+
11+
12+
// usage of a "typeof c++ operator in C, it's not the same, but it can do some stuff, first seen
13+
// this in VO Eidp (Einführung in die Programmierung - PS 11)", _Generic makes this possible :)
14+
15+
void print_bool(bool val) {
16+
printf("%s", val ? "true" : "false");
17+
}
18+
19+
20+
void print_u8(uint8_t x) {
21+
printf("%" PRIu8, x);
22+
}
23+
24+
void print_i8(int8_t x) {
25+
printf("%" PRIi8, x);
26+
}
27+
28+
void print_u32(uint32_t x) {
29+
printf("%" PRIu32, x);
30+
}
31+
32+
void print_i32(int32_t x) {
33+
printf("%" PRIi32, x);
34+
}
35+
36+
void print_u64(uint64_t x) {
37+
printf("%" PRIu64, x);
38+
}
39+
40+
void print_i64(int64_t x) {
41+
printf("%" PRIi64, x);
42+
}
43+
44+
void print_float(float x) {
45+
printf("%f", x);
46+
}
47+
48+
void print_double(double x) {
49+
printf("%f", x);
50+
}
51+
52+
void print_string(const char* x) {
53+
printf("%s", x);
54+
}
55+
56+
57+
void print_field(const OOPetrisAdditionalInformationField* const field);
58+
59+
void print_vector(const OOPetrisAdditionalInformationField* const* const field) {
60+
61+
printf("\n");
62+
for (size_t i = 0; i < stbds_arrlenu(field); ++i) {
63+
print_field(field[i]);
64+
printf("\n");
65+
}
66+
}
67+
68+
// clang-format off
69+
#define PRINT_VALUE(val) \
70+
_Generic((val),\
71+
_Bool : print_bool,\
72+
uint8_t : print_u8, \
73+
int8_t : print_i8,\
74+
uint32_t : print_u32,\
75+
int32_t : print_i32,\
76+
uint64_t : print_u64,\
77+
int64_t : print_i64,\
78+
float : print_float,\
79+
double : print_double,\
80+
const char* : print_string,\
81+
const OOPetrisAdditionalInformationField* const* : print_vector)(val)
82+
// clang-format on
83+
84+
85+
void print_field(const OOPetrisAdditionalInformationField* const field) {
86+
switch (oopetris_additional_information_field_get_type(field)) {
87+
case OOPetrisAdditionalInformationType_String:
88+
PRINT_VALUE(oopetris_additional_information_field_get_string(field));
89+
return;
90+
case OOPetrisAdditionalInformationType_Float:
91+
PRINT_VALUE(oopetris_additional_information_field_get_float(field));
92+
return;
93+
case OOPetrisAdditionalInformationType_Double:
94+
PRINT_VALUE(oopetris_additional_information_field_get_double(field));
95+
return;
96+
case OOPetrisAdditionalInformationType_Bool:
97+
PRINT_VALUE(oopetris_additional_information_field_get_bool(field));
98+
return;
99+
case OOPetrisAdditionalInformationType_U8:
100+
PRINT_VALUE(oopetris_additional_information_field_get_u8(field));
101+
return;
102+
case OOPetrisAdditionalInformationType_I8:
103+
PRINT_VALUE(oopetris_additional_information_field_get_i8(field));
104+
return;
105+
case OOPetrisAdditionalInformationType_U32:
106+
PRINT_VALUE(oopetris_additional_information_field_get_u32(field));
107+
return;
108+
case OOPetrisAdditionalInformationType_I32:
109+
PRINT_VALUE(oopetris_additional_information_field_get_i32(field));
110+
return;
111+
case OOPetrisAdditionalInformationType_U64:
112+
PRINT_VALUE(oopetris_additional_information_field_get_u64(field));
113+
return;
114+
case OOPetrisAdditionalInformationType_I64:
115+
PRINT_VALUE(oopetris_additional_information_field_get_i64(field));
116+
return;
117+
case OOPetrisAdditionalInformationType_Vector:
118+
PRINT_VALUE(oopetris_additional_information_field_get_vector(field));
119+
return;
120+
121+
default:
122+
assert(false && "UNREACHABLE");
123+
return;
124+
}
125+
}
126+
127+
void print_tetrion_header(const OOPetrisTetrionHeader* const header) {
128+
129+
printf("seed: %" PRIu64 "\tstarting_level: %" PRIu32 "\n", header->seed, header->starting_level);
130+
}
131+
132+
const char* input_event_string(OOPetrisInputEvent event) {
133+
switch (event) {
134+
case OOPetrisInputEvent_RotateLeftPressed:
135+
return "RotateLeftPressed";
136+
case OOPetrisInputEvent_RotateRightPressed:
137+
return "RotateRightPressed";
138+
case OOPetrisInputEvent_MoveLeftPressed:
139+
return "MoveLeftPressed";
140+
case OOPetrisInputEvent_MoveRightPressed:
141+
return "MoveRightPressed";
142+
case OOPetrisInputEvent_MoveDownPressed:
143+
return "MoveDownPressed";
144+
case OOPetrisInputEvent_DropPressed:
145+
return "DropPressed";
146+
case OOPetrisInputEvent_HoldPressed:
147+
return "HoldPressed";
148+
case OOPetrisInputEvent_RotateLeftReleased:
149+
return "RotateLeftReleased";
150+
case OOPetrisInputEvent_RotateRightReleased:
151+
return "RotateRightReleased";
152+
case OOPetrisInputEvent_MoveLeftReleased:
153+
return "MoveLeftReleased";
154+
case OOPetrisInputEvent_MoveRightReleased:
155+
return "MoveRightReleased";
156+
case OOPetrisInputEvent_MoveDownReleased:
157+
return "MoveDownReleased";
158+
case OOPetrisInputEvent_DropReleased:
159+
return "DropReleased";
160+
case OOPetrisInputEvent_HoldReleased:
161+
return "HoldReleased";
162+
default:
163+
assert(false && "UNREACHABLE");
164+
return "<ERROR>";
165+
}
166+
}
167+
168+
void print_record(const OOPetrisTetrionRecord* const record) {
169+
printf("simulation_step_index: %" PRIu64 "\ttetrion_index: %" PRIu8 "\tevent: %s\n", record->simulation_step_index,
170+
record->tetrion_index, input_event_string(record->event));
171+
}
172+
173+
void print_mino_stack(const OOPetrisMino* const stack) {
174+
175+
OOPetrisGridProperties* properties = oopetris_get_grid_properties();
176+
177+
if (properties == NULL) {
178+
return;
179+
}
180+
181+
const size_t buffer_size = properties->height * properties->width;
182+
183+
char* buffer = malloc(buffer_size);
184+
185+
if (buffer == NULL) {
186+
return;
187+
}
188+
189+
memset(buffer, '.', buffer_size);
190+
191+
for (size_t i = 0; i < stbds_arrlenu(stack); ++i) {
192+
const OOpetrisMinoPosition position = stack[i].position;
193+
buffer[position.x + (position.y * properties->width)] = '#';
194+
}
195+
196+
197+
for (size_t y = 0; y < properties->height; ++y) {
198+
int result = write(STDOUT_FILENO, buffer + (y * properties->width), properties->width);
199+
if (result < 0) {
200+
free(buffer);
201+
return;
202+
}
203+
printf("\n");
204+
}
205+
206+
free(buffer);
207+
oopetris_free_grid_properties(&properties);
208+
}
209+
210+
void print_snapshot(const OOpetrisTetrionSnapshot* const snapshot) {
211+
printf("\tsimulation_step_index: %" PRIu64 "\ttetrion_index: %" PRIu8 "\n", snapshot->simulation_step_index,
212+
snapshot->tetrion_index);
213+
214+
printf("\tlevel: %" PRIu32 "\tscore: %" PRIu64 "\tlines_cleared: %" PRIu32 "\n", snapshot->level, snapshot->score,
215+
snapshot->lines_cleared);
216+
217+
print_mino_stack(snapshot->mino_stack);
218+
}
219+
220+
221+
void print_recording_information(const OOPetrisRecordingInformation* const information) {
222+
223+
printf("Version: %d\n\n", information->version);
224+
printf("Additional Information:\n");
225+
226+
const char** keys = oopetris_additional_information_get_keys(information->information);
227+
228+
for (size_t i = 0; i < stbds_arrlenu(keys); ++i) {
229+
printf("\t%s: ", keys[i]);
230+
print_field(oopetris_additional_information_get_field(information->information, keys[i]));
231+
printf("\n");
232+
}
233+
printf("\n");
234+
235+
oopetris_additional_information_keys_free(&keys);
236+
237+
printf("Headers:\n");
238+
239+
for (size_t i = 0; i < stbds_arrlenu(information->tetrion_headers); ++i) {
240+
printf("\t");
241+
print_tetrion_header(&(information->tetrion_headers[i]));
242+
}
243+
printf("\n");
244+
245+
printf("Records:\n");
246+
247+
for (size_t i = 0; i < stbds_arrlenu(information->records); ++i) {
248+
printf("\t");
249+
print_record(&(information->records[i]));
250+
}
251+
printf("\n");
252+
253+
printf("Snapshots:\n");
254+
255+
for (size_t i = 0; i < stbds_arrlenu(information->snapshots); ++i) {
256+
print_snapshot(&(information->snapshots[i]));
257+
}
258+
printf("\n");
259+
}
260+
261+
int main(int argc, char** argv) {
262+
263+
264+
if (argc != 2) {
265+
fprintf(stderr, "usage: %s <file>\n", argv[0]);
266+
return EXIT_FAILURE;
267+
}
268+
269+
const char* file = argv[1];
270+
271+
const bool is_recordings_file = oopetris_is_recording_file(file);
272+
273+
if (!is_recordings_file) {
274+
fprintf(stderr, "Input file is no recordings file!\n");
275+
return EXIT_FAILURE;
276+
}
277+
278+
OOPetrisRecordingReturnValue* return_value = oopetris_get_recording_information(file);
279+
280+
const bool is_error = oopetris_is_error(return_value);
281+
282+
if (is_error) {
283+
const char* error = oopetris_get_error(return_value);
284+
fprintf(stderr, "An error occured: %s\n", error);
285+
oopetris_free_recording_value_whole(&return_value);
286+
return EXIT_FAILURE;
287+
}
288+
289+
OOPetrisRecordingInformation* information = oopetris_get_information(return_value);
290+
291+
oopetris_free_recording_value_only(&return_value);
292+
293+
print_recording_information(information);
294+
295+
oopetris_free_recording_information(&information);
296+
297+
return EXIT_SUCCESS;
298+
}

wrapper/c/example/meson.build

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
2+
example = executable(
3+
'example',
4+
files(
5+
'main.c',
6+
),
7+
dependencies: [liboopetris_c_wrapper_dep],
8+
override_options: {
9+
'warning_level': '3',
10+
'werror': true,
11+
'b_coverage': false,
12+
},
13+
)

0 commit comments

Comments
 (0)