diff options
-rw-r--r-- | Makefile | 33 | ||||
-rw-r--r-- | README.md | 2 | ||||
-rw-r--r-- | README.txt | 3 | ||||
-rw-r--r-- | color_game.3 | 27 | ||||
-rw-r--r-- | color_game.desktop | 9 | ||||
-rw-r--r-- | example.txt | 31 | ||||
-rw-r--r-- | icon.png | bin | 0 -> 9067 bytes | |||
-rwxr-xr-x | icons.windows/icon.ico | bin | 0 -> 93062 bytes | |||
-rwxr-xr-x | json/.github/workflows/main.yml | 57 | ||||
-rwxr-xr-x | json/.gitignore | 7 | ||||
-rwxr-xr-x | json/AUTHORS | 20 | ||||
-rwxr-xr-x | json/LICENSE | 25 | ||||
-rwxr-xr-x | json/README.md | 95 | ||||
-rwxr-xr-x | json/examples/test_json.c | 133 | ||||
-rwxr-xr-x | json/json.c | 1038 | ||||
-rwxr-xr-x | json/json.h | 281 | ||||
-rw-r--r-- | maps/default.json | 14 | ||||
-rw-r--r-- | maps/map2.json | 10 | ||||
-rw-r--r-- | src/color_box.h | 351 | ||||
-rw-r--r-- | src/color_game.cpp | 189 | ||||
-rw-r--r-- | src/handle_json.h | 58 | ||||
-rw-r--r-- | src/icon.rc | 1 | ||||
-rw-r--r-- | src/icon.res | bin | 0 -> 93326 bytes | |||
-rw-r--r-- | src/input.h | 253 | ||||
-rw-r--r-- | src/map.h | 141 | ||||
-rw-r--r-- | src/window.h | 166 |
26 files changed, 2944 insertions, 0 deletions
diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..ee19803 --- /dev/null +++ b/Makefile @@ -0,0 +1,33 @@ +flcon = fltk-config +compiler = $(shell $(flcon) --cxx) +flags = $(shell $(flcon) --use-images --cxxflags) -Ijson -Isrc +ldflags = $(shell $(flcon) --use-images --ldstaticflags) \ +json/json.c -static-libstdc++ -static-libgcc + +files = src/color_game.cpp src/*.h +target = -o color_game src/color_game.cpp + +color_game: $(files) + $(compiler) $(flags) $(target) $(ldflags) +icon: + echo 101 ICON DISCARDABLE "icons.windows/icon.ico" > src/icon.rc + windres src/icon.rc -O coff -o src/icon.res +g: + $(compiler) $(flags) -g $(target) $(ldflags) + gdb color_game +install: + sudo cp color_game.desktop \ + /usr/share/applications/color\ game.desktop + sudo mkdir /usr/local/share/color_game + sudo cp icon.png /usr/local/share/color_game/ + sudo cp -rf maps /usr/local/share/color_game/ + sudo cp color_game /usr/local/games/ + sudo cp example.txt /usr/local/share/color_game/ + sudo cp color_game.3 /usr/local/man/man3/ +uninstall: + sudo rm /usr/share/applications/color\ game.desktop + sudo rm -rf /usr/local/share/color_game + sudo rm /usr/local/games/color_game + sudo rm /usr/local/man/man3/color_game.3 +clean: + rm color_game diff --git a/README.md b/README.md new file mode 100644 index 0000000..e637eb5 --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# Color Game +The thing you get during a time of misunderstanding. I Wrote this a while back but now its on github (-: diff --git a/README.txt b/README.txt new file mode 100644 index 0000000..924ca74 --- /dev/null +++ b/README.txt @@ -0,0 +1,3 @@ +Framework and libarys. +https://github.com/json-parser/json-parser +https://www.fltk.org diff --git a/color_game.3 b/color_game.3 new file mode 100644 index 0000000..1b2a225 --- /dev/null +++ b/color_game.3 @@ -0,0 +1,27 @@ +./" color_game +.TH color_game 3 "2021" "file_view" + +.SH NAME + color_game +.SH DESCRIPTION + color_game is a game where you match colors. +.SH RULES + You win by filling the whole map with one color. + + -Red eats yellow. + + -Yellow eats blue. + + -Green eats red. + + -blue eats green. + + -Black becomes the eater of what touches it. + + -White becomes the opposite of what touches it. + + -All browns become the first color to go extinct. +.SH MAPS + You can add maps by adding a .json file to your map folder in /usr/local/share/color_game/ + + Use the example.txt file to learn how to make a map. diff --git a/color_game.desktop b/color_game.desktop new file mode 100644 index 0000000..68f2d61 --- /dev/null +++ b/color_game.desktop @@ -0,0 +1,9 @@ +[Desktop Entry] +Encoding=UTF-8 +Version=1.0 +Type=Application +Terminal=false +Exec=/usr/local/games/color_game +Name=color game +Icon=/usr/local/share/color_game/icon.png +Categories=Game; diff --git a/example.txt b/example.txt new file mode 100644 index 0000000..c7b119f --- /dev/null +++ b/example.txt @@ -0,0 +1,31 @@ +0 = not on the map +1 = red +2 = yellow +3 = green +4 = blue +5 = white +6 = black +7 = brown +8 = blank + +Make the 2d array the size of the map. +Your .json file goes in the map folder. + +linux: + /usr/local/share/color_game/maps + +Start of .json. +{ + "size": {"w": 8, "h": 9}, + "map": [ + [0, 0, 0, 0, 0, 0, 8, 8], + [0, 0, 4, 3, 2, 0, 8, 4], + [6, 8, 8, 8, 8, 8, 8, 0], + [0, 8, 0, 8, 0, 8, 8, 0], + [0, 1, 8, 8, 8, 8, 0, 0], + [0, 0, 8, 0, 8, 8, 8, 8], + [0, 8, 8, 0, 8, 8, 8, 5], + [0, 0, 8, 0, 8, 0, 0, 0], + [0, 0, 2, 7, 8, 0, 0, 0] + ] +} diff --git a/icon.png b/icon.png Binary files differnew file mode 100644 index 0000000..ac11cfa --- /dev/null +++ b/icon.png diff --git a/icons.windows/icon.ico b/icons.windows/icon.ico Binary files differnew file mode 100755 index 0000000..15e4e18 --- /dev/null +++ b/icons.windows/icon.ico diff --git a/json/.github/workflows/main.yml b/json/.github/workflows/main.yml new file mode 100755 index 0000000..2815f72 --- /dev/null +++ b/json/.github/workflows/main.yml @@ -0,0 +1,57 @@ +name: CI +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + # Allows running this workflow manually from the Actions tab + workflow_dispatch: + +jobs: + build: + runs-on: ubuntu-latest + steps: + # Checks-out repository under $GITHUB_WORKSPACE + - uses: actions/checkout@v2 + + - name: Build json.c as ANSI C89 without JSON_TRACK_SOURCE + run: c89 -ansi -Wall -Wpedantic -Werror -pedantic -pedantic-errors -D_ANSI_SOURCE -shared json.c -lm -o json-c89-notrack + + - name: Build json.c as ANSI C89 + run: c89 -ansi -Wall -Wpedantic -Werror -pedantic -pedantic-errors -D_ANSI_SOURCE -DJSON_TRACK_SOURCE -shared json.c -lm -o json-c89 + + - name: Build json.c as C99 + run: gcc -std=c99 -Wall -Wpedantic -Werror -pedantic -pedantic-errors -DJSON_TRACK_SOURCE -shared json.c -lm -o json-c99 + + - name: Build json.c as C11 + run: gcc -std=c11 -Wall -Wpedantic -Werror -pedantic -pedantic-errors -DJSON_TRACK_SOURCE -shared json.c -lm -o json-c11 + + - name: Build json.c as C17 + run: gcc -std=c17 -Wall -Wpedantic -Werror -pedantic -pedantic-errors -DJSON_TRACK_SOURCE -shared json.c -lm -o json-c17 + + - name: Build json.c as C2x + run: gcc -std=c2x -Wall -Wpedantic -Werror -pedantic -pedantic-errors -DJSON_TRACK_SOURCE -shared json.c -lm -o json-c2x + + - name: Build json.c as C++98 + run: g++ -std=c++98 -Wall -Wpedantic -Werror -pedantic -pedantic-errors -DJSON_TRACK_SOURCE -shared -fPIC -x c++ json.c -lm -o json-cpp98 + + - name: Build json.c as C++11 + run: g++ -std=c++11 -Wall -Wpedantic -Werror -pedantic -pedantic-errors -DJSON_TRACK_SOURCE -shared -fPIC -x c++ json.c -lm -o json-cpp11 + + - name: Build json.c as C++14 + run: g++ -std=c++14 -Wall -Wpedantic -Werror -pedantic -pedantic-errors -DJSON_TRACK_SOURCE -shared -fPIC -x c++ json.c -lm -o json-cpp14 + + - name: Build json.c as C++17 + run: g++ -std=c++17 -Wall -Wpedantic -Werror -pedantic -pedantic-errors -DJSON_TRACK_SOURCE -shared -fPIC -x c++ json.c -lm -o json-cpp17 + + - name: Build json.c as C++2a + run: g++ -std=c++2a -Wall -Wpedantic -Werror -pedantic -pedantic-errors -DJSON_TRACK_SOURCE -shared -fPIC -x c++ json.c -lm -o json-cpp2a + + - name: Build examples + run: | + c89 -ansi -Wall -Wpedantic -Werror -pedantic -pedantic-errors -D_ANSI_SOURCE -DJSON_TRACK_SOURCE -I. json.c examples/test_json.c -lm -o json-example0 + + - name: Build with configure script + run: | + ./configure + make diff --git a/json/.gitignore b/json/.gitignore new file mode 100755 index 0000000..8352bae --- /dev/null +++ b/json/.gitignore @@ -0,0 +1,7 @@ +Makefile +config.log +config.status +json.o +libjsonparser.a +libjsonparser.so +test_json diff --git a/json/AUTHORS b/json/AUTHORS new file mode 100755 index 0000000..287e303 --- /dev/null +++ b/json/AUTHORS @@ -0,0 +1,20 @@ +All contributors arranged by first commit: + +James McLaughlin +Alex Gartrell +Peter Scott +Mathias Kaerlev +Emiel Mols +Czarek Tomczak +Nicholas Braden +Ivan Kozub +Árpád Goretity +Igor Gnatenko +Haïkel Guémar +Tobias Waldekranz +Patrick Donnelly +Wilmer van der Gaast +Jin Wei +François Cartegnie +Matthijs Boelstra +Richard Selneck diff --git a/json/LICENSE b/json/LICENSE new file mode 100755 index 0000000..9508e30 --- /dev/null +++ b/json/LICENSE @@ -0,0 +1,25 @@ + + Copyright (C) 2012, 2013 James McLaughlin et al. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. diff --git a/json/README.md b/json/README.md new file mode 100755 index 0000000..700d0b3 --- /dev/null +++ b/json/README.md @@ -0,0 +1,95 @@ +Very low footprint JSON parser written in portable ANSI C. + +* BSD licensed with no dependencies (i.e. just drop the C file into your project) +* Never recurses or allocates more memory than it needs +* Very simple API with operator sugar for C++ + +[](https://github.com/json-parser/json-parser/actions) + +_Want to serialize? Check out [json-builder](https://github.com/udp/json-builder)!_ + +Installing +---------- + +There is now a makefile which will produce a libjsonparser static and dynamic library. However, this +is _not_ required to build json-parser, and the source files (`json.c` and `json.h`) should be happy +in any build system you already have in place. + + +API +--- + + json_value * json_parse (const json_char * json, + size_t length); + + json_value * json_parse_ex (json_settings * settings, + const json_char * json, + size_t length, + char * error); + + void json_value_free (json_value *); + +The `type` field of `json_value` is one of: + +* `json_object` (see `u.object.length`, `u.object.values[x].name`, `u.object.values[x].value`) +* `json_array` (see `u.array.length`, `u.array.values`) +* `json_integer` (see `u.integer`) +* `json_double` (see `u.dbl`) +* `json_string` (see `u.string.ptr`, `u.string.length`) +* `json_boolean` (see `u.boolean`) +* `json_null` + + +Compile-Time Options +-------------------- + + -DJSON_TRACK_SOURCE + +Stores the source location (line and column number) inside each `json_value`. + +This is useful for application-level error reporting. + + +Runtime Options +--------------- + + settings |= json_enable_comments; + +Enables C-style `// line` and `/* block */` comments. + + size_t value_extra + +The amount of space (if any) to allocate at the end of each `json_value`, in +order to give the application space to add metadata. + + void * (* mem_alloc) (size_t, int zero, void * user_data); + void (* mem_free) (void *, void * user_data); + +Custom allocator routines. If NULL, the default `malloc` and `free` will be used. + +The `user_data` pointer will be forwarded from `json_settings` to allow application +context to be passed. + + +Changes in version 1.1.0 +------------------------ + +* UTF-8 byte order marks are now skipped if present + +* Allows cross-compilation by honoring --host if given (@wkz) + +* Maximum size for error buffer is now exposed in header (@LB--) + +* GCC warning for `static` after `const` fixed (@batrick) + +* Optional support for C-style line and block comments added (@Jin-W-FS) + +* `name_length` field added to object values + +* It is now possible to retrieve the source line/column number of a parsed `json_value` when `JSON_TRACK_SOURCE` is enabled + +* The application may now extend `json_value` using the `value_extra` setting + +* Un-ambiguate pow call in the case of C++ overloaded pow (@fcartegnie) + +* Fix null pointer de-reference when a non-existing array is closed and no root value is present diff --git a/json/examples/test_json.c b/json/examples/test_json.c new file mode 100755 index 0000000..0545c7c --- /dev/null +++ b/json/examples/test_json.c @@ -0,0 +1,133 @@ +/* vim: set et ts=4 + * + * Copyright (C) 2015 Mirko Pasqualetti All rights reserved. + * https://github.com/udp/json-parser + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <sys/stat.h> + +#include "json.h" + +static void process_value(json_value* value) +{ + if (value == NULL) { + return; + } + if (value->type != json_object) { + print_depth_shift(depth); + } + switch (value->type) { + case json_none: + printf("none\n"); + break; + case json_null: + printf("null\n"); + break; + case json_object: + process_object(value, depth+1); + break; + case json_array: + process_array(value, depth+1); + break; + case json_integer: + printf("int: %10" PRId64 "\n", value->u.integer); + break; + case json_double: + printf("double: %f\n", value->u.dbl); + break; + case json_string: + printf("string: %s\n", value->u.string.ptr); + break; + case json_boolean: + printf("bool: %d\n", value->u.boolean); + break; + } +} + +int main(int argc, char** argv) +{ + char* filename; + FILE *fp; + struct stat filestatus; + int file_size; + char* file_contents; + json_char* json; + json_value* value; + + if (argc != 2) { + fprintf(stderr, "%s <file_json>\n", argv[0]); + return 1; + } + filename = argv[1]; + + if ( stat(filename, &filestatus) != 0) { + fprintf(stderr, "File %s not found\n", filename); + return 1; + } + file_size = filestatus.st_size; + file_contents = (char*)malloc(filestatus.st_size); + if ( file_contents == NULL) { + fprintf(stderr, "Memory error: unable to allocate %d bytes\n", file_size); + return 1; + } + + fp = fopen(filename, "rt"); + if (fp == NULL) { + fprintf(stderr, "Unable to open %s\n", filename); + fclose(fp); + free(file_contents); + return 1; + } + if ( fread(file_contents, file_size, 1, fp) != 1 ) { + fprintf(stderr, "Unable to read content of %s\n", filename); + fclose(fp); + free(file_contents); + return 1; + } + fclose(fp); + + printf("%s\n", file_contents); + + printf("--------------------------------\n\n"); + + json = (json_char*)file_contents; + + value = json_parse(json,file_size); + + if (value == NULL) { + fprintf(stderr, "Unable to parse data\n"); + free(file_contents); + exit(1); + } + + process_value(value); + + json_value_free(value); + free(file_contents); + return 0; +} diff --git a/json/json.c b/json/json.c new file mode 100755 index 0000000..a165b3d --- /dev/null +++ b/json/json.c @@ -0,0 +1,1038 @@ +/* vim: set et ts=3 sw=3 sts=3 ft=c: + * + * Copyright (C) 2012, 2013, 2014 James McLaughlin et al. All rights reserved. + * https://github.com/udp/json-parser + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "json.h" + +#ifdef _MSC_VER + #ifndef _CRT_SECURE_NO_WARNINGS + #define _CRT_SECURE_NO_WARNINGS + #endif + #include <stdint.h> +#endif + +const struct _json_value json_value_none; + +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <math.h> + +typedef unsigned int json_uchar; + +/* There has to be a better way to do this */ +static const json_int_t JSON_INT_MAX = sizeof(json_int_t) == 1 + ? INT8_MAX + : (sizeof(json_int_t) == 2 + ? INT16_MAX + : (sizeof(json_int_t) == 4 + ? INT32_MAX + : INT64_MAX)); + +static unsigned char hex_value (json_char c) +{ + if (isdigit(c)) + return c - '0'; + + switch (c) { + case 'a': case 'A': return 0x0A; + case 'b': case 'B': return 0x0B; + case 'c': case 'C': return 0x0C; + case 'd': case 'D': return 0x0D; + case 'e': case 'E': return 0x0E; + case 'f': case 'F': return 0x0F; + default: return 0xFF; + } +} + +static int would_overflow (json_int_t value, json_char b) +{ + return ((JSON_INT_MAX - (b - '0')) / 10 ) < value; +} + +typedef struct +{ + unsigned long used_memory; + + unsigned int uint_max; + unsigned long ulong_max; + + json_settings settings; + int first_pass; + + const json_char * ptr; + unsigned int cur_line, cur_col; + +} json_state; + +static void * default_alloc (size_t size, int zero, void * user_data) +{ + return zero ? calloc (1, size) : malloc (size); +} + +static void default_free (void * ptr, void * user_data) +{ + free (ptr); +} + +static void * json_alloc (json_state * state, unsigned long size, int zero) +{ + if ((state->ulong_max - state->used_memory) < size) + return 0; + + if (state->settings.max_memory + && (state->used_memory += size) > state->settings.max_memory) + { + return 0; + } + + return state->settings.mem_alloc (size, zero, state->settings.user_data); +} + +static int new_value (json_state * state, + json_value ** top, json_value ** root, json_value ** alloc, + json_type type) +{ + json_value * value; + int values_size; + + if (!state->first_pass) + { + value = *top = *alloc; + *alloc = (*alloc)->_reserved.next_alloc; + + if (!*root) + *root = value; + + switch (value->type) + { + case json_array: + + if (value->u.array.length == 0) + break; + + if (! (value->u.array.values = (json_value **) json_alloc + (state, value->u.array.length * sizeof (json_value *), 0)) ) + { + return 0; + } + + value->u.array.length = 0; + break; + + case json_object: + + if (value->u.object.length == 0) + break; + + values_size = sizeof (*value->u.object.values) * value->u.object.length; + + if (! (value->u.object.values = (json_object_entry *) json_alloc + (state, values_size + ((unsigned long) value->u.object.values), 0)) ) + { + return 0; + } + + value->_reserved.object_mem = (*(char **) &value->u.object.values) + values_size; + + value->u.object.length = 0; + break; + + case json_string: + + if (! (value->u.string.ptr = (json_char *) json_alloc + (state, (value->u.string.length + 1) * sizeof (json_char), 0)) ) + { + return 0; + } + + value->u.string.length = 0; + break; + + default: + break; + }; + + return 1; + } + + if (! (value = (json_value *) json_alloc + (state, sizeof (json_value) + state->settings.value_extra, 1))) + { + return 0; + } + + if (!*root) + *root = value; + + value->type = type; + value->parent = *top; + + #ifdef JSON_TRACK_SOURCE + value->line = state->cur_line; + value->col = state->cur_col; + #endif + + if (*alloc) + (*alloc)->_reserved.next_alloc = value; + + *alloc = *top = value; + + return 1; +} + +#define whitespace \ + case '\n': ++ state.cur_line; state.cur_col = 0; /* FALLTHRU */ \ + case ' ': /* FALLTHRU */ case '\t': /* FALLTHRU */ case '\r' + +#define string_add(b) \ + do { if (!state.first_pass) string [string_length] = b; ++ string_length; } while (0); + +#define line_and_col \ + state.cur_line, state.cur_col + +static const long + flag_next = 1 << 0, + flag_reproc = 1 << 1, + flag_need_comma = 1 << 2, + flag_seek_value = 1 << 3, + flag_escaped = 1 << 4, + flag_string = 1 << 5, + flag_need_colon = 1 << 6, + flag_done = 1 << 7, + flag_num_negative = 1 << 8, + flag_num_zero = 1 << 9, + flag_num_e = 1 << 10, + flag_num_e_got_sign = 1 << 11, + flag_num_e_negative = 1 << 12, + flag_line_comment = 1 << 13, + flag_block_comment = 1 << 14, + flag_num_got_decimal = 1 << 15; + +json_value * json_parse_ex (json_settings * settings, + const json_char * json, + size_t length, + char * error_buf) +{ + json_char error [json_error_max]; + const json_char * end; + json_value * top, * root, * alloc = 0; + json_state state = { 0 }; + long flags = 0; + double num_digits = 0, num_e = 0; + double num_fraction = 0; + + /* Skip UTF-8 BOM + */ + if (length >= 3 && ((unsigned char) json [0]) == 0xEF + && ((unsigned char) json [1]) == 0xBB + && ((unsigned char) json [2]) == 0xBF) + { + json += 3; + length -= 3; + } + + error[0] = '\0'; + end = (json + length); + + memcpy (&state.settings, settings, sizeof (json_settings)); + + if (!state.settings.mem_alloc) + state.settings.mem_alloc = default_alloc; + + if (!state.settings.mem_free) + state.settings.mem_free = default_free; + + memset (&state.uint_max, 0xFF, sizeof (state.uint_max)); + memset (&state.ulong_max, 0xFF, sizeof (state.ulong_max)); + + state.uint_max -= 8; /* limit of how much can be added before next check */ + state.ulong_max -= 8; + + for (state.first_pass = 1; state.first_pass >= 0; -- state.first_pass) + { + json_uchar uchar; + unsigned char uc_b1, uc_b2, uc_b3, uc_b4; + json_char * string = 0; + unsigned int string_length = 0; + + top = root = 0; + flags = flag_seek_value; + + state.cur_line = 1; + + for (state.ptr = json ;; ++ state.ptr) + { + json_char b = (state.ptr == end ? 0 : *state.ptr); + + if (flags & flag_string) + { + if (!b) + { sprintf (error, "Unexpected EOF in string (at %u:%u)", line_and_col); + goto e_failed; + } + + if (string_length > state.uint_max) + goto e_overflow; + + if (flags & flag_escaped) + { + flags &= ~ flag_escaped; + + switch (b) + { + case 'b': string_add ('\b'); break; + case 'f': string_add ('\f'); break; + case 'n': string_add ('\n'); break; + case 'r': string_add ('\r'); break; + case 't': string_add ('\t'); break; + case 'u': + + if (end - state.ptr <= 4 || + (uc_b1 = hex_value (*++ state.ptr)) == 0xFF || + (uc_b2 = hex_value (*++ state.ptr)) == 0xFF || + (uc_b3 = hex_value (*++ state.ptr)) == 0xFF || + (uc_b4 = hex_value (*++ state.ptr)) == 0xFF) + { + sprintf (error, "Invalid character value `%c` (at %u:%u)", b, line_and_col); + goto e_failed; + } + + uc_b1 = (uc_b1 << 4) | uc_b2; + uc_b2 = (uc_b3 << 4) | uc_b4; + uchar = (uc_b1 << 8) | uc_b2; + + if ((uchar & 0xF800) == 0xD800) { + json_uchar uchar2; + + if (end - state.ptr <= 6 || (*++ state.ptr) != '\\' || (*++ state.ptr) != 'u' || + (uc_b1 = hex_value (*++ state.ptr)) == 0xFF || + (uc_b2 = hex_value (*++ state.ptr)) == 0xFF || + (uc_b3 = hex_value (*++ state.ptr)) == 0xFF || + (uc_b4 = hex_value (*++ state.ptr)) == 0xFF) + { + sprintf (error, "Invalid character value `%c` (at %u:%u)", b, line_and_col); + goto e_failed; + } + + uc_b1 = (uc_b1 << 4) | uc_b2; + uc_b2 = (uc_b3 << 4) | uc_b4; + uchar2 = (uc_b1 << 8) | uc_b2; + + uchar = 0x010000 | ((uchar & 0x3FF) << 10) | (uchar2 & 0x3FF); + } + + if (sizeof (json_char) >= sizeof (json_uchar) || (uchar <= 0x7F)) + { + string_add ((json_char) uchar); + break; + } + + if (uchar <= 0x7FF) + { + if (state.first_pass) + string_length += 2; + else + { string [string_length ++] = 0xC0 | (uchar >> 6); + string [string_length ++] = 0x80 | (uchar & 0x3F); + } + + break; + } + + if (uchar <= 0xFFFF) { + if (state.first_pass) + string_length += 3; + else + { string [string_length ++] = 0xE0 | (uchar >> 12); + string [string_length ++] = 0x80 | ((uchar >> 6) & 0x3F); + string [string_length ++] = 0x80 | (uchar & 0x3F); + } + + break; + } + + if (state.first_pass) + string_length += 4; + else + { string [string_length ++] = 0xF0 | (uchar >> 18); + string [string_length ++] = 0x80 | ((uchar >> 12) & 0x3F); + string [string_length ++] = 0x80 | ((uchar >> 6) & 0x3F); + string [string_length ++] = 0x80 | (uchar & 0x3F); + } + + break; + + default: + string_add (b); + }; + + continue; + } + + if (b == '\\') + { + flags |= flag_escaped; + continue; + } + + if (b == '"') + { + if (!state.first_pass) + string [string_length] = 0; + + flags &= ~ flag_string; + string = 0; + + switch (top->type) + { + case json_string: + + top->u.string.length = string_length; + flags |= flag_next; + + break; + + case json_object: + + if (state.first_pass) + (*(json_char **) &top->u.object.values) += string_length + 1; + else + { + top->u.object.values [top->u.object.length].name + = (json_char *) top->_reserved.object_mem; + + top->u.object.values [top->u.object.length].name_length + = string_length; + + (*(json_char **) &top->_reserved.object_mem) += string_length + 1; + } + + flags |= flag_seek_value | flag_need_colon; + continue; + + default: + break; + }; + } + else + { + string_add (b); + continue; + } + } + + if (state.settings.settings & json_enable_comments) + { + if (flags & (flag_line_comment | flag_block_comment)) + { + if (flags & flag_line_comment) + { + if (b == '\r' || b == '\n' || !b) + { + flags &= ~ flag_line_comment; + -- state.ptr; /* so null can be reproc'd */ + } + + continue; + } + + if (flags & flag_block_comment) + { + if (!b) + { sprintf (error, "%u:%u: Unexpected EOF in block comment", line_and_col); + goto e_failed; + } + + if (b == '*' && state.ptr < (end - 1) && state.ptr [1] == '/') + { + flags &= ~ flag_block_comment; + ++ state.ptr; /* skip closing sequence */ + } + + continue; + } + } + else if (b == '/') + { + if (! (flags & (flag_seek_value | flag_done)) && top->type != json_object) + { sprintf (error, "%u:%u: Comment not allowed here", line_and_col); + goto e_failed; + } + + if (++ state.ptr == end) + { sprintf (error, "%u:%u: EOF unexpected", line_and_col); + goto e_failed; + } + + switch (b = *state.ptr) + { + case '/': + flags |= flag_line_comment; + continue; + + case '*': + flags |= flag_block_comment; + continue; + + default: + sprintf (error, "%u:%u: Unexpected `%c` in comment opening sequence", line_and_col, b); + goto e_failed; + }; + } + } + + if (flags & flag_done) + { + if (!b) + break; + + switch (b) + { + whitespace: + continue; + + default: + + sprintf (error, "%u:%u: Trailing garbage: `%c`", + state.cur_line, state.cur_col, b); + + goto e_failed; + }; + } + + if (flags & flag_seek_value) + { + switch (b) + { + whitespace: + continue; + + case ']': + + if (top && top->type == json_array) + flags = (flags & ~ (flag_need_comma | flag_seek_value)) | flag_next; + else + { sprintf (error, "%u:%u: Unexpected ]", line_and_col); + goto e_failed; + } + + break; + + default: + + if (flags & flag_need_comma) + { + if (b == ',') + { flags &= ~ flag_need_comma; + continue; + } + else + { + sprintf (error, "%u:%u: Expected , before %c", + state.cur_line, state.cur_col, b); + + goto e_failed; + } + } + + if (flags & flag_need_colon) + { + if (b == ':') + { flags &= ~ flag_need_colon; + continue; + } + else + { + sprintf (error, "%u:%u: Expected : before %c", + state.cur_line, state.cur_col, b); + + goto e_failed; + } + } + + flags &= ~ flag_seek_value; + + switch (b) + { + case '{': + + if (!new_value (&state, &top, &root, &alloc, json_object)) + goto e_alloc_failure; + + continue; + + case '[': + + if (!new_value (&state, &top, &root, &alloc, json_array)) + goto e_alloc_failure; + + flags |= flag_seek_value; + continue; + + case '"': + + if (!new_value (&state, &top, &root, &alloc, json_string)) + goto e_alloc_failure; + + flags |= flag_string; + + string = top->u.string.ptr; + string_length = 0; + + continue; + + case 't': + + if ((end - state.ptr) < 3 || *(++ state.ptr) != 'r' || + *(++ state.ptr) != 'u' || *(++ state.ptr) != 'e') + { + goto e_unknown_value; + } + + if (!new_value (&state, &top, &root, &alloc, json_boolean)) + goto e_alloc_failure; + + top->u.boolean = 1; + + flags |= flag_next; + break; + + case 'f': + + if ((end - state.ptr) < 4 || *(++ state.ptr) != 'a' || + *(++ state.ptr) != 'l' || *(++ state.ptr) != 's' || + *(++ state.ptr) != 'e') + { + goto e_unknown_value; + } + + if (!new_value (&state, &top, &root, &alloc, json_boolean)) + goto e_alloc_failure; + + flags |= flag_next; + break; + + case 'n': + + if ((end - state.ptr) < 3 || *(++ state.ptr) != 'u' || + *(++ state.ptr) != 'l' || *(++ state.ptr) != 'l') + { + goto e_unknown_value; + } + + if (!new_value (&state, &top, &root, &alloc, json_null)) + goto e_alloc_failure; + + flags |= flag_next; + break; + + default: + + if (isdigit (b) || b == '-') + { + if (!new_value (&state, &top, &root, &alloc, json_integer)) + goto e_alloc_failure; + + if (!state.first_pass) + { + while (isdigit (b) || b == '+' || b == '-' + || b == 'e' || b == 'E' || b == '.') + { + if ( (++ state.ptr) == end) + { + b = 0; + break; + } + + b = *state.ptr; + } + + flags |= flag_next | flag_reproc; + break; + } + + flags &= ~ (flag_num_negative | flag_num_e | + flag_num_e_got_sign | flag_num_e_negative | + flag_num_zero); + + num_digits = 0; + num_fraction = 0; + num_e = 0; + + if (b != '-') + { + flags |= flag_reproc; + break; + } + + flags |= flag_num_negative; + continue; + } + else + { sprintf (error, "%u:%u: Unexpected %c when seeking value", line_and_col, b); + goto e_failed; + } + }; + }; + } + else + { + switch (top->type) + { + case json_object: + + switch (b) + { + whitespace: + continue; + + case '"': + + if (flags & flag_need_comma) + { sprintf (error, "%u:%u: Expected , before \"", line_and_col); + goto e_failed; + } + + flags |= flag_string; + + string = (json_char *) top->_reserved.object_mem; + string_length = 0; + + break; + + case '}': + + flags = (flags & ~ flag_need_comma) | flag_next; + break; + + case ',': + + if (flags & flag_need_comma) + { + flags &= ~ flag_need_comma; + break; + } /* FALLTHRU */ + + default: + sprintf (error, "%u:%u: Unexpected `%c` in object", line_and_col, b); + goto e_failed; + }; + + break; + + case json_integer: + case json_double: + + if (isdigit (b)) + { + ++ num_digits; + + if (top->type == json_integer || flags & flag_num_e) + { + if (! (flags & flag_num_e)) + { + if (flags & flag_num_zero) + { sprintf (error, "%u:%u: Unexpected `0` before `%c`", line_and_col, b); + goto e_failed; + } + + if (num_digits == 1 && b == '0') + flags |= flag_num_zero; + } + else + { + flags |= flag_num_e_got_sign; + num_e = (num_e * 10) + (b - '0'); + continue; + } + + if (would_overflow(top->u.integer, b)) + { -- num_digits; + -- state.ptr; + top->type = json_double; + top->u.dbl = (double)top->u.integer; + continue; + } + + top->u.integer = (top->u.integer * 10) + (b - '0'); + continue; + } + + if (flags & flag_num_got_decimal) + num_fraction = (num_fraction * 10) + (b - '0'); + else + top->u.dbl = (top->u.dbl * 10) + (b - '0'); + + continue; + } + + if (b == '+' || b == '-') + { + if ( (flags & flag_num_e) && !(flags & flag_num_e_got_sign)) + { + flags |= flag_num_e_got_sign; + + if (b == '-') + flags |= flag_num_e_negative; + + continue; + } + } + else if (b == '.' && top->type == json_integer) + { + if (!num_digits) + { sprintf (error, "%u:%u: Expected digit before `.`", line_and_col); + goto e_failed; + } + + top->type = json_double; + top->u.dbl = (double) top->u.integer; + + flags |= flag_num_got_decimal; + num_digits = 0; + continue; + } + + if (! (flags & flag_num_e)) + { + if (top->type == json_double) + { + if (!num_digits) + { sprintf (error, "%u:%u: Expected digit after `.`", line_and_col); + goto e_failed; + } + + top->u.dbl += num_fraction / pow (10.0, num_digits); + } + + if (b == 'e' || b == 'E') + { + flags |= flag_num_e; + + if (top->type == json_integer) + { + top->type = json_double; + top->u.dbl = (double) top->u.integer; + } + + num_digits = 0; + flags &= ~ flag_num_zero; + + continue; + } + } + else + { + if (!num_digits) + { sprintf (error, "%u:%u: Expected digit after `e`", line_and_col); + goto e_failed; + } + + top->u.dbl *= pow (10.0, (flags & flag_num_e_negative ? - num_e : num_e)); + } + + if (flags & flag_num_negative) + { + if (top->type == json_integer) + top->u.integer = - top->u.integer; + else + top->u.dbl = - top->u.dbl; + } + + flags |= flag_next | flag_reproc; + break; + + default: + break; + }; + } + + if (flags & flag_reproc) + { + flags &= ~ flag_reproc; + -- state.ptr; + } + + if (flags & flag_next) + { + flags = (flags & ~ flag_next) | flag_need_comma; + + if (!top->parent) + { + /* root value done */ + + flags |= flag_done; + continue; + } + + if (top->parent->type == json_array) + flags |= flag_seek_value; + + if (!state.first_pass) + { + json_value * parent = top->parent; + + switch (parent->type) + { + case json_object: + + parent->u.object.values + [parent->u.object.length].value = top; + + break; + + case json_array: + + parent->u.array.values + [parent->u.array.length] = top; + + break; + + default: + break; + }; + } + + if ( (++ top->parent->u.array.length) > state.uint_max) + goto e_overflow; + + top = top->parent; + + continue; + } + } + + alloc = root; + } + + return root; + +e_unknown_value: + + sprintf (error, "%u:%u: Unknown value", line_and_col); + goto e_failed; + +e_alloc_failure: + + strcpy (error, "Memory allocation failure"); + goto e_failed; + +e_overflow: + + sprintf (error, "%u:%u: Too long (caught overflow)", line_and_col); + goto e_failed; + +e_failed: + + if (error_buf) + { + if (*error) + strcpy (error_buf, error); + else + strcpy (error_buf, "Unknown error"); + } + + if (state.first_pass) + alloc = root; + + while (alloc) + { + top = alloc->_reserved.next_alloc; + state.settings.mem_free (alloc, state.settings.user_data); + alloc = top; + } + + if (!state.first_pass) + json_value_free_ex (&state.settings, root); + + return 0; +} + +json_value * json_parse (const json_char * json, size_t length) +{ + json_settings settings = { 0 }; + return json_parse_ex (&settings, json, length, 0); +} + +void json_value_free_ex (json_settings * settings, json_value * value) +{ + json_value * cur_value; + + if (!value) + return; + + value->parent = 0; + + while (value) + { + switch (value->type) + { + case json_array: + + if (!value->u.array.length) + { + settings->mem_free (value->u.array.values, settings->user_data); + break; + } + + value = value->u.array.values [-- value->u.array.length]; + continue; + + case json_object: + + if (!value->u.object.length) + { + settings->mem_free (value->u.object.values, settings->user_data); + break; + } + + value = value->u.object.values [-- value->u.object.length].value; + continue; + + case json_string: + + settings->mem_free (value->u.string.ptr, settings->user_data); + break; + + default: + break; + }; + + cur_value = value; + value = value->parent; + settings->mem_free (cur_value, settings->user_data); + } +} + +void json_value_free (json_value * value) +{ + json_settings settings = { 0 }; + settings.mem_free = default_free; + json_value_free_ex (&settings, value); +} diff --git a/json/json.h b/json/json.h new file mode 100755 index 0000000..dd56553 --- /dev/null +++ b/json/json.h @@ -0,0 +1,281 @@ + +/* vim: set et ts=3 sw=3 sts=3 ft=c: + * + * Copyright (C) 2012, 2013, 2014 James McLaughlin et al. All rights reserved. + * https://github.com/udp/json-parser + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _JSON_H +#define _JSON_H + +#ifndef json_char + #define json_char char +#endif + +#ifndef json_int_t + #ifndef _MSC_VER + #include <inttypes.h> + #define json_int_t int64_t + #else + #define json_int_t __int64 + #endif +#endif + +#include <stdlib.h> + +#ifdef __cplusplus + + #include <string.h> + + extern "C" + { + +#endif + +typedef struct +{ + unsigned long max_memory; + int settings; + + /* Custom allocator support (leave null to use malloc/free) + */ + + void * (* mem_alloc) (size_t, int zero, void * user_data); + void (* mem_free) (void *, void * user_data); + + void * user_data; /* will be passed to mem_alloc and mem_free */ + + size_t value_extra; /* how much extra space to allocate for values? */ + +} json_settings; + +#define json_enable_comments 0x01 + +typedef enum +{ + json_none, + json_object, + json_array, + json_integer, + json_double, + json_string, + json_boolean, + json_null + +} json_type; + +extern const struct _json_value json_value_none; + +typedef struct _json_object_entry +{ + json_char * name; + unsigned int name_length; + + struct _json_value * value; + +} json_object_entry; + +typedef struct _json_value +{ + struct _json_value * parent; + + json_type type; + + union + { + int boolean; + json_int_t integer; + double dbl; + + struct + { + unsigned int length; + json_char * ptr; /* null terminated */ + + } string; + + struct + { + unsigned int length; + + json_object_entry * values; + + #if defined(__cplusplus) + json_object_entry * begin () const + { return values; + } + json_object_entry * end () const + { return values + length; + } + #endif + + } object; + + struct + { + unsigned int length; + struct _json_value ** values; + + #if defined(__cplusplus) + _json_value ** begin () const + { return values; + } + _json_value ** end () const + { return values + length; + } + #endif + + } array; + + } u; + + union + { + struct _json_value * next_alloc; + void * object_mem; + + } _reserved; + + #ifdef JSON_TRACK_SOURCE + + /* Location of the value in the source JSON + */ + unsigned int line, col; + + #endif + + + /* Some C++ operator sugar */ + + #ifdef __cplusplus + + public: + + inline _json_value () + { memset (this, 0, sizeof (_json_value)); + } + + inline const struct _json_value &operator [] (int index) const + { + if (type != json_array || index < 0 + || ((unsigned int) index) >= u.array.length) + { + return json_value_none; + } + + return *u.array.values [index]; + } + + inline const struct _json_value &operator [] (const char * index) const + { + if (type != json_object) + return json_value_none; + + for (unsigned int i = 0; i < u.object.length; ++ i) + if (!strcmp (u.object.values [i].name, index)) + return *u.object.values [i].value; + + return json_value_none; + } + + inline operator const char * () const + { + switch (type) + { + case json_string: + return u.string.ptr; + + default: + return ""; + }; + } + + inline operator json_int_t () const + { + switch (type) + { + case json_integer: + return u.integer; + + case json_double: + return (json_int_t) u.dbl; + + default: + return 0; + }; + } + + inline operator bool () const + { + if (type != json_boolean) + return false; + + return u.boolean != 0; + } + + inline operator double () const + { + switch (type) + { + case json_integer: + return (double) u.integer; + + case json_double: + return u.dbl; + + default: + return 0; + }; + } + + #endif + +} json_value; + +json_value * json_parse (const json_char * json, + size_t length); + +#define json_error_max 128 +json_value * json_parse_ex (json_settings * settings, + const json_char * json, + size_t length, + char * error); + +void json_value_free (json_value *); + + +/* Not usually necessary, unless you used a custom mem_alloc and now want to + * use a custom mem_free. + */ +void json_value_free_ex (json_settings * settings, + json_value *); + + +#ifdef __cplusplus + } /* extern "C" */ +#endif + +#endif diff --git a/maps/default.json b/maps/default.json new file mode 100644 index 0000000..2b17099 --- /dev/null +++ b/maps/default.json @@ -0,0 +1,14 @@ +{ + "size": {"w": 8, "h": 9}, + "map": [ + [0, 0, 0, 0, 0, 0, 8, 8], + [0, 0, 4, 3, 2, 0, 8, 4], + [6, 8, 8, 8, 8, 8, 8, 0], + [0, 8, 0, 8, 0, 8, 8, 0], + [0, 1, 8, 8, 8, 8, 0, 0], + [0, 0, 8, 0, 8, 8, 8, 8], + [0, 8, 8, 0, 8, 8, 8, 5], + [0, 0, 8, 0, 8, 0, 0, 0], + [0, 0, 2, 7, 8, 0, 0, 0] + ] +} diff --git a/maps/map2.json b/maps/map2.json new file mode 100644 index 0000000..4b814e6 --- /dev/null +++ b/maps/map2.json @@ -0,0 +1,10 @@ +{
+ "size": {"w": 8, "h": 5},
+ "map": [
+ [1, 8, 8, 8, 8, 8, 8, 2],
+ [8, 8, 0, 0, 0, 0, 8, 8],
+ [8, 8, 7, 0, 0, 5, 8, 8],
+ [8, 8, 0, 0, 0, 0, 8, 8],
+ [3, 8, 8, 8, 8, 8, 8, 4]
+ ]
+}
diff --git a/src/color_box.h b/src/color_box.h new file mode 100644 index 0000000..8162640 --- /dev/null +++ b/src/color_box.h @@ -0,0 +1,351 @@ +class ColorBox : public Fl_Box { + public: + ColorBox(int _x, int _y, int _w, int _h, const char * l=0) : + Fl_Box(_x, _y, _w, _h, l) { + box(FL_UP_BOX); + labeltype(FL_SHADOW_LABEL); + } + + int handle(int event); + + void xy_vars(int _x, int _y) { + this->_x = _x; + this->_y = _y; + } + + void set_overlap(bool overlap) { + this->overlap = overlap; + } + + bool set_overlap() { + return overlap; + } + + void setbox(); + private: + int _x, _y; + bool overlap; + int old_x, old_y; +}; + +void add_boxs() { + int _y, _x, _font_size; + memset(all_colors, 0, sizeof(all_colors)); + + bside = (_window->w() - _window->h()) / 2; + bsize = _window->h() / MBLOCKS; + _font_size = bsize / 2; + + for (_y = 0; _y < 50; _y++) + for (_x = 0; _x < 50; _x++) { + + if (_y + map_y_offset >= MBLOCKS || + _x + map_x_offset >= MBLOCKS) { + if (boxs[_y][_x]) + boxs[_y][_x]->hide(); + continue; + } + + all_colors[color_map[_y][_x]]++; + + // Add boxes. + if (!boxs[_y][_x]) + boxs[_y][_x] = new ColorBox(0, 0, 0, 0); + + boxs[_y][_x]->resize((_x * bsize) + bside, _y * + bsize, bsize, bsize); + + // Activate. + if (g_active) + boxs[_y][_x]->activate(); + + // Hide some boxes. + if (color_map[_y][_x] == 0) { + boxs[_y][_x]->hide(); + continue; + } + + boxs[_y][_x]->show(); + + // Adding color and label to boxes. + boxs[_y][_x]->label(color_to_label(color_map[_y][_x])); + boxs[_y][_x]->labelsize(_font_size); + boxs[_y][_x]->color(color_to_flcolor(color_map[_y][_x])); + boxs[_y][_x]->xy_vars(_x, _y); + boxs[_y][_x]->set_overlap(false); + + if (color_map[_y][_x] == BLACK) + boxs[_y][_x]->labelcolor(FL_GRAY); + else + boxs[_y][_x]->labelcolor(FL_BLACK); + } + + _window->redraw(); +} + +void act_boxs(bool act) { + int x, y; + + for (y = 0; y < MBLOCKS; y++) + for (x = 0; x < MBLOCKS; x++) { + if (boxs[y][x]) { + if (act) + boxs[y][x]->activate(); + else + boxs[y][x]->deactivate(); + } + } + + if (overlap_wid) + overlap_wid->resize(0, 0, 0, 0); +} + +int ColorBox::handle(int event) { + int i, the_x, the_y, real_x, real_y; + + switch(event) { + case FL_ENTER: + if (!g_active || !active_r()) + return 1; + + if (!overlap && color() != FL_GRAY && color() != FL_WHITE && + color() != FL_BLACK && color() != FL_BROWN) { + int _font_size = bsize / 2; + + overlap_wid->labelsize(_font_size); + overlap_wid->xy_vars(_x, _y); + overlap_wid->resize((_x * bsize) + bside, _y * + bsize, bsize, bsize); + + overlap_wid->set_overlap(true); + overlap_wid->color(color()); + overlap_wid->labelcolor(labelcolor()); + + overlap_wid->label(label()); + } + + return 1; + case FL_PUSH: + return 1; + case FL_DRAG: + if (!g_active || !active_r()) + return 1; + + switch(Fl::event_button()) { + case FL_LEFT_MOUSE: + + if (!overlap) + break; + + position(Fl::event_x(), Fl::event_y()); + + // Stop box from leaving window. + real_x = x() + (w() / 2); + real_y = y() + (h() / 2); + + if (real_x <= 0) + position(3, y()); + if (real_x >= _window->w()) + position(_window->w() - (w() + 3), y()); + if (real_y <= 0) + position(x(), 3); + if (real_y >= _window->h()) + position(x(), _window->h() - (h() + 3)); + + // Drawing. + if (old_x && old_y) { + old_x = (old_x - x()) * 3; + old_y = (old_y - y()) * 3; + + if (old_x < 0) + old_x *= -1; + if (old_y < 0) + old_y *= -1; + + if (old_x == 0) + old_x = 100; + if (old_y == 0) + old_y = 100; + + _window->damage(FL_DAMAGE_ALL, x() - old_x, + y() - old_y, w() + (old_x * 2), h() + + (old_y * 2)); + } else + _window->redraw(); + + old_x = x(); + old_y = y(); + + break; + default: + break; + } + + return 1; + case FL_RELEASE: + + if (Fl::event_button() == FL_LEFT_MOUSE) + setbox(); + + return 1; + default: + return 0; + } +} + +void ColorBox::setbox() { + int x_block = (x() - bside) / bsize; + int y_block = y() / bsize; + int _font_size, repos_t = 0; + unsigned char ccolor = color_map[_y][_x], chc = 0; + bool repos = false; + + if (!overlap) + return; + else if (!boxs[y_block][x_block]) { + resize(0, 0, 0, 0); + _window->redraw(); + return; + } + + resize(0, 0, 0, 0); + + // Color combo. + switch (color_map[y_block][x_block]) { + case BLANK: + repos = true; + break; + case RED: + if (ccolor == GREEN) + repos = true; + break; + case YELLOW: + if (ccolor == RED) + repos = true; + break; + case GREEN: + if (ccolor == BLUE) + repos = true; + break; + case BLUE: + if (ccolor == YELLOW) + repos = true; + break; + case WHITE: + chc = 1; + repos = true; + break; + case BLACK: + chc = 2; + repos = true; + break; + default: + break; + } + + if (!repos) { + _window->redraw(); + return; + } + + // Distances. + if (x_block > _x) { + if (x_block - _x == 1) + repos = true; + else + repos = false; + repos_t++; + } if (_x > x_block) { + if (_x - x_block == 1) + repos = true; + else + repos = false; + repos_t++; + } if (y_block > _y) { + if (y_block - _y == 1) + repos = true; + else + repos = false; + repos_t++; + } if (_y > y_block) { + if (_y - y_block == 1) + repos = true; + else + repos = false; + repos_t++; + } + + // repos_t stops diagonal movemet. + if (repos_t > 1) + repos = false; + else if (repos && chc > 0) { + unsigned char new_color; + + // White. + if (chc == 1) { + switch (ccolor) { + case RED: + new_color = BLUE; + break; + case YELLOW: + new_color = GREEN; + break; + case GREEN: + new_color = YELLOW; + break; + case BLUE: + new_color = RED; + break; + default: + break; + } + // Black. + } else if (chc == 2) { + switch(ccolor) { + case RED: + new_color = GREEN; + break; + case YELLOW: + new_color = RED; + break; + case GREEN: + new_color = BLUE; + break; + case BLUE: + new_color = YELLOW; + break; + default: + break; + } + } + + all_colors[new_color]++; + all_colors[color_map[y_block][x_block]]--; + + color_map[y_block][x_block] = new_color; + int _font_size = bsize / 2; + + boxs[y_block][x_block]->labelsize(_font_size); + boxs[y_block][x_block]->color(color_to_flcolor(new_color)); + boxs[y_block][x_block]->label(color_to_label(new_color)); + boxs[y_block][x_block]->labelcolor(FL_BLACK); + + } else if (repos) { + all_colors[color_map[_y][_x]]++; + all_colors[color_map[y_block][x_block]]--; + + color_map[y_block][x_block] = color_map[_y][_x]; + _font_size = bsize / 2; + + boxs[y_block][x_block]->labelsize(_font_size); + boxs[y_block][x_block]->color(color()); + boxs[y_block][x_block]->labelcolor(labelcolor()); + boxs[y_block][x_block]->label(label()); + } + + int da_size = (bsize * 2 + 10); + + _window->damage(FL_DAMAGE_ALL, boxs[y_block][x_block]->x() - da_size, + boxs[y_block][x_block]->y() - da_size, boxs[y_block][x_block]->w() + da_size * 2, + boxs[y_block][x_block]->h() + da_size * 2); +} diff --git a/src/color_game.cpp b/src/color_game.cpp new file mode 100644 index 0000000..298f404 --- /dev/null +++ b/src/color_game.cpp @@ -0,0 +1,189 @@ +// FLTK headers. +#include "FL/Fl.H" +#include "FL/Fl_Double_Window.H" +#include "FL/Fl_Box.H" +#include "FL/Fl_Button.H" +#include "FL/Fl_Output.H" +#include "FL/Fl_Multiline_Output.H" +#include "FL/Fl_File_Browser.H" +#include "FL/Fl_PNG_Image.H" + +#ifndef FL_BROWN + #define FL_BROWN 0x65432100 +#endif + +#ifdef _WIN32 + #define dir_to_map_prf "%smaps\\" + #include <windows.h> + #include "FL/x.H" +#else + #define dir_to_map_prf "%smaps/" +#endif + +// Main Folder. +// MAINDIR must end with / or \ (windows) and be a full path. +#ifdef _WIN32 + #define MAINDIR ".\\" +#else + #define MAINDIR "/usr/local/share/color_game/" +#endif + +#define check_game_speed 5.0 +#define max_map 50 +#define button_gap 10 +// buttet_height is the fraction of bside. +#define button_height 7 + +// Max blocks. +int MBLOCKS; + +// Window. +Fl_Double_Window * _window; + +// Color boxes. +class ColorBox; +ColorBox * boxs[50][50]; +ColorBox * overlap_wid; + +// Buttons. +Fl_Button * startb; +Fl_Button * exit_button; +Fl_Button * fullsc_button; +Fl_Button * browse_maps; + +// Output. +Fl_Multiline_Output * _output; + +// Browser. +class MapBrowser; +MapBrowser * map_browser; + +// Error box. +Fl_Button * ok_button; +Fl_Output * error_msg; + +// Game over +Fl_Button * game_over; + +// Screen size and flags. +int bside, bsize; +bool g_active, ext_used; + +// Std lib. +#include <cstdlib> +#include <cstdio> +#include <cstring> + +// My headers. +#include "handle_json.h" +#include "map.h" +#include "color_box.h" +#include "input.h" +#include "window.h" + +int main(int argv, char ** args) { + Fl::background(0xC0, 0xC0, 0xC0); + g_active = false; + ext_used = false; + + _window = new MyWindow(Fl::w() / 2, Fl::h() / 2, "color game"); + _window->xclass("color game"); + + bside = (_window->w() - _window->h()) / 2; + bsize = _window->h() / MBLOCKS; + + int bw, by; + bw = bside - (bside / 3); + by = bside / button_height; + + add_boxs(); + + // Start button. + startb = new Fl_Button((_window->w() / 2) - (bside / 2), + (_window->h() / 2) - (bside / 4), bside, bside / 2, "Start"); + startb->labelsize(bw / 4); + startb->color(FL_BLUE); + startb->labelcolor(FL_WHITE); + startb->callback(startb_cb); + startb->box(FL_ROUNDED_BOX); + act_boxs(false); + + // Exit button. + exit_button = new Fl_Button(0, 0, bw, by, "Exit"); + exit_button->labelsize(bw / 4); + exit_button->callback(exit_cb); + exit_button->shortcut(FL_Escape); + + // Fullscreen button. + fullsc_button = new Fl_Button(0, 0, bw, by, "Fullscreen"); + fullsc_button->labelsize(bw / 6); + fullsc_button->callback(fullsc_cb); + fullsc_button->shortcut(FL_F + 11); + + // Output. + _output = new Fl_Multiline_Output((_window->w() - bside) + 10, 10, \ + bside - 20, _window->h() - 20); + _output->textsize(_output->w() / 8); + + // Browser button. + browse_maps = new Fl_Button(0, 0, bw, by, "maps"); + browse_maps->labelsize(browse_maps->w() / 5); + browse_maps->when(FL_WHEN_CHANGED); + browse_maps->callback(browse_cb); + + // Overlap. + overlap_wid = new ColorBox(0, 0, 0, 0); + + // Browser. + map_browser = new MapBrowser((_window->w() / 2) - (_window->w() / 4), + (_window->h() / 2) - (_window->h() / 4), _window->w() / 2, + _window->h() / 2, "Map Browser"); + + // Error box. + int e_w, e_h, e_x, e_y; + e_w = _window->w() / 5; + e_h = _window->h() / 8; + e_x = (_window->w() / 2) - (e_w / 2); + e_y = (_window->h() / 2) - (e_h / 2); + + error_msg = new Fl_Output(e_x, e_y, e_w, e_h); + error_msg->hide(); + + ok_button = new Fl_Button(e_x, e_y + e_h, e_w, e_h, "Ok"); + ok_button->callback(error_cb); + ok_button->hide(); + + // Game over. + int gx, gy, gw, gh; + gw = _window->w() / 3; + gh = _window->h() / 5; + gx = (_window->w() / 2) - (gw / 2); + gy = (_window->h() / 2) - (gh / 2); + + game_over = new Fl_Button(gx, gy, gw, gh, "You Win! (:"); + game_over->box(FL_UP_BOX); + game_over->labeltype(FL_SHADOW_LABEL); + game_over->labelsize(gw / 7); + game_over->hide(); + game_over->callback(startb_cb); + + _window->end(); + _window->resizable(_window); + ((MyWindow*)_window)->reset_sizes(); + + // Setting window icon. + #ifdef _WIN32 + _window->icon((char*)LoadIcon(fl_display, MAKEINTRESOURCE(101))); + #else + char icon_image_path[255]; + sprintf(icon_image_path, "%sicon.png", MAINDIR); + Fl_PNG_Image * icon_image = + new Fl_PNG_Image((const char*)icon_image_path); + + if (!icon_image->fail()) + _window->icon(icon_image); + #endif + + _window->show(argv, args); + return Fl::run(); +} diff --git a/src/handle_json.h b/src/handle_json.h new file mode 100644 index 0000000..ddf5934 --- /dev/null +++ b/src/handle_json.h @@ -0,0 +1,58 @@ +#include "json.h" + +bool get_jsonf_size(json_value * value, int * w, int * h) { + json_object_entry _size = value->u.object.values[0]; + json_object_entry * _size_objects = _size.value->u.object.values; + + if (strcmp(_size.name, "size")) + return true; + + // Width. + if (!strcmp(_size_objects[0].name, "w")) + *w = _size_objects[0].value->u.integer; + else if (!strcmp(_size_objects[0].name, "h")) + *h = _size_objects[0].value->u.integer; + else + return true; + + // Height + if (!strcmp(_size_objects[1].name, "w")) + *w = _size_objects[1].value->u.integer; + else if (!strcmp(_size_objects[1].name, "h")) + *h = _size_objects[1].value->u.integer; + else + return true; + + if (*w > 255 || *w < 2 || *h > 255 || *h < 2) + return true; + + return false; +} + +bool read_data_jsonf(json_value * value, int w, int h, unsigned char ** buf) { + json_object_entry _size = value->u.object.values[0]; + json_object_entry _map = value->u.object.values[1]; + json_value ** astart = _map.value->u.array.values; + + if (strcmp(_size.name, "size") || + strcmp(_map.name, "map")) + return true; + + unsigned char y, x; + long int int_value; + + for (y = 0; y < h; y++) + for (x = 0; x < w; x++) { + + if (astart[y]->u.array.values[x]->type != json_integer) + return true; + + int_value = astart[y]->u.array.values[x]->u.integer; + + if (int_value > 8 || int_value < 0) + return true; + buf[y][x] = (unsigned char)int_value; + } + + return false; +} diff --git a/src/icon.rc b/src/icon.rc new file mode 100644 index 0000000..c5bd20b --- /dev/null +++ b/src/icon.rc @@ -0,0 +1 @@ +101 ICON DISCARDABLE icons.windows/icon.ico diff --git a/src/icon.res b/src/icon.res Binary files differnew file mode 100644 index 0000000..8cab40e --- /dev/null +++ b/src/icon.res diff --git a/src/input.h b/src/input.h new file mode 100644 index 0000000..c80c78f --- /dev/null +++ b/src/input.h @@ -0,0 +1,253 @@ +/* +Warning ugly code on line 248 turn back now if u +want to keep your joy and happens. +*/ + +void show_error(const char * label) { + ok_button->show(); + ok_button->labelsize(ok_button->w() / 5); + error_msg->show(); + error_msg->value(label); + + if (!g_active) + startb->do_callback(); + + act_boxs(false); +} + +void error_cb(Fl_Widget * w, void * d) { + ok_button->hide(); + error_msg->hide(); + act_boxs(true); +} + +class MapBrowser : public Fl_File_Browser { + public: + MapBrowser(int _x, int _y, int _w, int _h, const char * l=0) : + Fl_File_Browser(_x, _y, _w, _h, l) { + sprintf(mapdir, dir_to_map_prf, MAINDIR); + + load(mapdir); + type(FL_HOLD_BROWSER); + hide(); + callback(map_browser_cb, (void*)this); + + int bw, bh; + bw = w() / 5; + bh = h() / 5; + + close_button = new Fl_Button(x(), y() - bh, bw, bh, + "close"); + close_button->callback(close_cb, (void*)this); + close_button->labelsize(bw / 3); + close_button->hide(); + + if (text(1)) + if (!strcmp(text(1), "../")) + remove(1); + } + + static void map_browser_cb(Fl_Widget * w, void * d) { + MapBrowser * br = (MapBrowser*)d; + br->real_cb(); + } + + void show_all() { + close_button->show(); + show(); + act_boxs(false); + } + + void hide_all() { + close_button->hide(); + hide(); + + if (g_active) + act_boxs(true); + } + + bool is_visible() { + if (close_button->visible()) + return true; + else + return false; + } + + static void close_cb(Fl_Widget * w, void * d) { + MapBrowser * br = (MapBrowser*)d; + br->hide_all(); + } + + void handle_resize() { + close_button->labelsize(close_button->w() / 3); + } + + void real_cb(); + private: + Fl_Button * close_button; + int last_clicked; + char mapdir[255]; +}; + +void MapBrowser::real_cb() { + + if (!text(value())) + return; + else if (last_clicked != value()) { + last_clicked = value(); + return; + } + + last_clicked = -1; + map_browser->hide_all(); + + // Loading json. + char filename[255]; + sprintf(filename, "%s%s", mapdir, text(value())); + + FILE * fp = fopen(filename, "rt"); + + if (!fp) { + show_error("File not found"); + fclose(fp); + return; + } + + long int file_size = findsize(fp); + char file_buf[file_size]; + file_buf[0] = '\0'; + file_buf[file_size] = '\0'; + int a_w, a_h, c, r; + + fread(file_buf, file_size, 1, fp); + fclose(fp); + + json_value * _value = json_parse(file_buf, file_size); + + if (!_value) { + show_error("Can't read map"); + return; + } + + if (get_jsonf_size(_value, &a_w, &a_h)) { + show_error("Bad formatt"); + return; + } + + // Making 2d array. + unsigned char ** the_map = new unsigned char*[a_h]; + unsigned char i; + + if (the_map == NULL) { + show_error("Can't malloc data"); + delete [] the_map; + return; + } + + for (i = 0; i < a_h; i++) + the_map[i] = new unsigned char[a_w]; + + // Reading data. + if (read_data_jsonf(_value, a_w, a_h, the_map)) { + show_error("Bad formatt"); + + // Deleting memory. + for (i = 0; i < a_h; i++) { + delete [] the_map[i]; + } + + delete [] the_map; + + return; + } + + // Settings Max blocks. + if (a_w > a_h) + MBLOCKS = a_w; + else + MBLOCKS = a_h; + + if (a_w > max_map || a_h > max_map) { + // Deleting memory. + for (i = 0; i < a_h; i++) { + delete [] the_map[i]; + } + + delete [] the_map; + + loaded_map = false; + map_init(); + add_boxs(); + + show_error("Map is to big"); + return; + } + + map_init(the_map, a_w, a_h); + + // Deleting memory. + for (i = 0; i < a_h; i++) { + delete [] the_map[i]; + } + + delete [] the_map; + loaded_map = true; + + add_boxs(); + + // Activate game. + if (!g_active) + startb->do_callback(); + g_active = true; +} + +void startb_cb(Fl_Widget * w, void * d) { + int bw, by; + bw = bside - (bside / 3); + by = bside / 5; + ext_used = false; + + if (!g_active) { + g_active = true; + startb->label("Restart"); + startb->labelsize(bw / 5); + startb->resize(10, 10, exit_button->w(), + exit_button->h()); + startb->color(FL_GRAY); + startb->labelcolor(FL_BLACK); + startb->box(FL_UP_BOX); + act_boxs(true); + } + + overlap_wid->resize(0, 0, 0, 0); + map_init(); + add_boxs(); + + game_over->hide(); +} + +void exit_cb(Fl_Widget * w, void * d) { + _window->hide(); +} + +void fullsc_cb(Fl_Widget * w, void * d) { + if (_window->fullscreen_active()) + _window->fullscreen_off(); + else + _window->fullscreen(); +} + +void browse_cb(Fl_Widget * w, void * d) { + /* + My compiler was being stupid. The extistence of + this code makes me angery. + It should look like this: + game_over->hide(); + Why do I have to do this! + */ + if (game_over->visible()) + startb->do_callback(); + // The saddness is over for now. + + map_browser->show_all(); +} diff --git a/src/map.h b/src/map.h new file mode 100644 index 0000000..7f1c301 --- /dev/null +++ b/src/map.h @@ -0,0 +1,141 @@ +#define RED 1 +#define YELLOW 2 +#define GREEN 3 +#define BLUE 4 + +#define WHITE 5 +#define BLACK 6 +#define BROWN 7 +#define BLANK 8 + +// 0 == not part of the map. + +unsigned char info_output[9]; +unsigned char all_colors[9]; +unsigned char color_map[max_map][max_map]; +unsigned char old_color_map[max_map][max_map]; +bool loaded_map; +int map_x_offset, map_y_offset; + +unsigned char default_map[9][8] = { + {0, 0, 0, 0, 0, 0, 8, 8}, // 1 + {0, 0, 4, 3, 2, 0, 8, 4}, // 2 + {6, 8, 8, 8, 8, 8, 8, 0}, // 3 + {0, 8, 0, 8, 0, 8, 8, 0}, // 4 + {0, 1, 8, 8, 8, 8, 0, 0}, // 5 + {0, 0, 8, 0, 8, 8, 8, 8}, // 6 + {0, 8, 8, 0, 8, 8, 8, 5}, // 7 + {0, 0, 8, 0, 8, 0, 0, 0}, // 8 + {0, 0, 2, 7, 8, 0, 0, 0} // 9 +}; + +const char * color_to_label(unsigned char _color) { + switch (_color) { + case RED: + return "R"; + case YELLOW: + return "Y"; + case GREEN: + return "G"; + case BLUE: + return "B"; + case WHITE: + return "W"; + case BLACK: + return "X"; + case BROWN: + return "N"; + default: + return "\0"; + } +} + +Fl_Color color_to_flcolor(unsigned char _color) { + switch (_color) { + case RED: + return FL_RED; + case YELLOW: + return FL_YELLOW; + case GREEN: + return FL_GREEN; + case BLUE: + return FL_BLUE; + case WHITE: + return FL_WHITE; + case BLACK: + return FL_BLACK; + case BROWN: + return FL_BROWN; + default: + return FL_GRAY; + } +} + +long int findsize(FILE * fp) { + fseek(fp, 0L, SEEK_END); + long int _size = ftell(fp); + fseek(fp, 0L, SEEK_SET); + return _size; +} + +void map_init(unsigned char ** new_map=NULL, int a_w=0, int a_h=0) { + memset(color_map, 0, sizeof(color_map)); + memset(all_colors, 0, sizeof(all_colors)); + ext_used = false; + + int x, y; + + /* + Sorry this function is a bit hacky. + It was made for testing but then made + it to this version. + */ + + // Loading new maps. + if (new_map || loaded_map) { + + // For rectangle shaped maps. + if (new_map) { + map_x_offset = 0; + map_y_offset = 0; + + if (a_w < MBLOCKS) + map_x_offset = MBLOCKS - a_w; + if (a_h < MBLOCKS) + map_y_offset = MBLOCKS - a_h; + } + + for (y = 0; y < MBLOCKS; y++) + for (x = 0; x < MBLOCKS; x++) { + + if (y + map_y_offset >= MBLOCKS || + x + map_x_offset >= MBLOCKS) + continue; + + if (loaded_map && !new_map) + color_map[y][x] = old_color_map[y][x]; + else { + color_map[y][x] = new_map[y][x]; + old_color_map[y][x] = color_map[y][x]; + } + + all_colors[color_map[y][x]]++; + info_output[color_map[y][x]]++; + } + + loaded_map = true; + return; + } + + // Default map. + MBLOCKS = 9; + for (y = 0; y < MBLOCKS; y++) + for (x = 0; x < MBLOCKS; x++) { + + if (y < 9 && x < 8) + color_map[y][x] = default_map[y][x]; + + all_colors[color_map[y][x]]++; + info_output[color_map[y][x]]++; + } +} diff --git a/src/window.h b/src/window.h new file mode 100644 index 0000000..3eeb848 --- /dev/null +++ b/src/window.h @@ -0,0 +1,166 @@ +class MyWindow : public Fl_Double_Window { + public: + MyWindow(int _w, int _h, const char * l=0) : + Fl_Double_Window(_w, _h, l) { + color(FL_GRAY); + map_init(); + old_w = w(); + old_h = h(); + Fl::add_timeout(1.0/check_game_speed, time_cb, (void*)this); + } + + static void time_cb(void * data) { + MyWindow * win = (MyWindow*)data; + win->real_time_cb(); + Fl::repeat_timeout(1.0/check_game_speed, time_cb, data); + } + + void reset_sizes(); + void real_time_cb(); + private: + int old_w, old_h; +}; + +void update_output() { + char buf[10], end_buf[100], clabel[8]; + unsigned char i; + buf[0] = '\0'; + end_buf[0] = '\0'; + clabel[0] = '\0'; + + for (i = 1; i < 9; i++) { + info_output[i] = all_colors[i]; + clabel[0] = '\0'; + + // Label. + switch(i) { + case BLANK: + strcat(clabel, "Blank"); + break; + default: + strcat(clabel, color_to_label(i)); + break; + } + + sprintf(buf, "%s %d\n", clabel, all_colors[i]); + strcat(end_buf, buf); + } + + _output->value(end_buf); +} + +void check_game() { + unsigned char i, ext_color = 0; + bool updated = false; + + // Checking colors and for game over. + for (i = 0; i < 9; i++) { + // Updating output. + if (info_output[i] != all_colors[i] && !updated) { + update_output(); + updated = true; + // Game over. + } if (all_colors[i] + all_colors[0] == (MBLOCKS - + map_x_offset) * (MBLOCKS - map_y_offset)) { + act_boxs(false); + game_over->show(); + break; + // Extinct color. + } if (all_colors[i] == 0 && i > 0 && i <= 4 && !ext_used) { + ext_color = i; + break; + } + } + + if (!ext_color) + return; + + int num_of_browns = 0, x, y, max_browns = all_colors[BROWN]; + + for (y = 0; y < MBLOCKS; y++) + for (x = 0; x < MBLOCKS; x++) { + + if (color_map[y][x] == BROWN) { + color_map[y][x] = ext_color; + boxs[y][x]->color(color_to_flcolor(ext_color)); + boxs[y][x]->label(color_to_label(ext_color)); + all_colors[ext_color]++; + num_of_browns++; + } + + if (num_of_browns >= max_browns) + break; + } + + all_colors[BROWN] = 0; + ext_used = true; +} + +void MyWindow::reset_sizes() { + // Varibles. + old_w = w(); + old_h = h(); + bside = (_window->w() - _window->h()) / 2; + bsize = _window->h() / MBLOCKS; + + int bw, by; + bw = bside - (bside / 3); + by = bside / button_height; + + // Overlap. + overlap_wid->resize(0, 0, 0, 0); + + // Start button position. + if (g_active) + startb->resize(10, 10, exit_button->w(), exit_button->h()); + + startb->labelsize(startb->w() / 4); + + // Exit button. + exit_button->labelsize(exit_button->w() / 4); + exit_button->position(10, 10 + button_gap + exit_button->h()); + + // Fullscreen button. + fullsc_button->labelsize(fullsc_button->w() / 6); + fullsc_button->position(10, exit_button->y() + exit_button->h() + button_gap); + + // Browse button. + browse_maps->labelsize(browse_maps->w() / 5); + browse_maps->position(10, fullsc_button->y() + fullsc_button->h() + button_gap); + + // Map browser. + map_browser->handle_resize(); + + // Output. + _output->textsize(_output->w() / 8); + + // Error. + ok_button->labelsize(ok_button->w() / 5); + + // Game over. + game_over->labelsize(game_over->w() / 7); + + add_boxs(); + + if (map_browser->is_visible()) + act_boxs(false); +} + +void MyWindow::real_time_cb() { + bool dont_resize = false; + + // Testing screen size. + float screen_ra = (float)w() / (float)h(); + + if (screen_ra > 2.0 || screen_ra < 1.75) { + size(w(), int((float)w() / 1.756653)); + dont_resize = true; + } + + // Window resizing. + if ((old_w != w() || old_h != h()) && !dont_resize) { + reset_sizes(); + } + + check_game(); +} |