]> git.seodisparate.com - RockPaperScissorsDuel/commitdiff
WIP work on game (logic.js about done)
authorStephen Seo <seo.disparate@gmail.com>
Sun, 1 Jan 2023 11:23:52 +0000 (20:23 +0900)
committerStephen Seo <seo.disparate@gmail.com>
Sun, 1 Jan 2023 11:23:52 +0000 (20:23 +0900)
.gitignore [new file with mode: 0644]
CMakeLists.txt [new file with mode: 0644]
src/.lvimrc [new file with mode: 0644]
src/constants.h [new file with mode: 0644]
src/main.cc [new file with mode: 0644]
wasm_build/.gitignore [new file with mode: 0644]
wasm_build/Makefile [new file with mode: 0644]
wasm_build/client.js [new file with mode: 0644]
wasm_build/custom_shell.html [new file with mode: 0644]
wasm_build/logic.js [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..52afeba
--- /dev/null
@@ -0,0 +1,3 @@
+/build*/
+/compile_commands.json
+/.cache/
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644 (file)
index 0000000..e6465aa
--- /dev/null
@@ -0,0 +1,25 @@
+project(RockPaperScissorsDuelNative)
+cmake_minimum_required(VERSION 3.18.4)
+
+set(CMAKE_C_FLAGS "-Wall -Wextra -Wpedantic")
+set(CMAKE_C_FLAGS_DEBUG "-O0 -g")
+set(CMAKE_C_FLAGS_RELEASE "-O3 -D NDEBUG")
+set(CMAKE_CXX_FLAGS "-Wall -Wextra -Wpedantic")
+set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g")
+set(CMAKE_CXX_FLAGS_RELEASE "-O3 -D NDEBUG")
+
+if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
+    message(STATUS "Setting build type to 'Debug', none was specified.")
+    set(CMAKE_BUILD_TYPE Debug CACHE STRING "Choose the type of build." FORCE)
+    set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release")
+endif()
+
+set(RPSDuelNative_SOURCES
+    src/main.cc
+)
+
+add_executable(RPSDuelNative ${RPSDuelNative_SOURCES})
+
+target_link_libraries(RPSDuelNative PUBLIC
+    raylib
+)
diff --git a/src/.lvimrc b/src/.lvimrc
new file mode 100644 (file)
index 0000000..81ba35f
--- /dev/null
@@ -0,0 +1,3 @@
+set tabstop=2
+set softtabstop=2
+set shiftwidth=2
diff --git a/src/constants.h b/src/constants.h
new file mode 100644 (file)
index 0000000..56151e0
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef ROCK_PAPER_SCISSORS_DUEL_CONSTANTS_H_
+#define ROCK_PAPER_SCISSORS_DUEL_CONSTANTS_H_
+
+constexpr int DEFAULT_SCREEN_WIDTH = 500;
+constexpr int DEFAULT_SCREEN_HEIGHT = 800;
+
+#endif
diff --git a/src/main.cc b/src/main.cc
new file mode 100644 (file)
index 0000000..f18db16
--- /dev/null
@@ -0,0 +1,62 @@
+// emscripten includes
+#ifdef __EMSCRIPTEN__
+#include <emscripten.h>
+#include <emscripten/html5.h>
+#else
+#include <random>
+#endif
+
+// third party includes
+#include <raylib.h>
+
+// local includes
+#include "constants.h"
+
+#ifdef __EMSCRIPTEN__
+// em exposed fns
+extern "C" {
+
+void EMSCRIPTEN_KEEPALIVE game_visual_update(
+    const char *playerOne, const char *playerTwo, const char *currentPlayer,
+    char first_first, char first_second, char first_third, char second_first,
+    char second_second, char second_third, bool first_ready, bool second_ready,
+    int pos) {
+  // TODO
+}
+
+} // end em exposed functions
+
+EM_JS(void, js_set_ready, (), { Rune.actions.set_ready(); });
+
+EM_JS(void, js_set_choices,
+      (const char *first, const char *second, const char *third), {
+        Rune.actions.set_choices(UTF8ToString(first), UTF8ToString(second),
+                                 UTF8ToString(third));
+      });
+#endif
+
+int main() {
+#ifdef __EMSCRIPTEN__
+  InitWindow(DEFAULT_SCREEN_WIDTH, DEFAULT_SCREEN_HEIGHT,
+             "RockPaperScissorsDuel");
+#else
+  InitWindow(DEFAULT_SCREEN_WIDTH, DEFAULT_SCREEN_HEIGHT, "RPSDuel_Native");
+#endif
+
+#ifdef __EMSCRIPTEN__
+#else
+  SetTargetFPS(60);
+
+  while (!WindowShouldClose()) {
+    BeginDrawing();
+    ClearBackground(BLACK);
+    DrawText("Testing...", 100, 100, 30, RAYWHITE);
+    EndDrawing();
+  }
+
+  CloseAudioDevice();
+  CloseWindow();
+#endif
+
+  return 0;
+}
diff --git a/wasm_build/.gitignore b/wasm_build/.gitignore
new file mode 100644 (file)
index 0000000..f60af13
--- /dev/null
@@ -0,0 +1,4 @@
+/rock_paper_scissors_duel.html
+/rock_paper_scissors_duel.js
+/rock_paper_scissors_duel.wasm
+/rock_paper_scissors_duel.data
diff --git a/wasm_build/Makefile b/wasm_build/Makefile
new file mode 100644 (file)
index 0000000..5a932af
--- /dev/null
@@ -0,0 +1,35 @@
+ifdef RELEASE
+       OTHER_FLAGS = -DNDEBUG -O3
+else
+       OTHER_FLAGS = -O0
+endif
+
+SOURCES = \
+               ../src/main.cc
+
+HEADERS = \
+               ../src/constants.h
+
+CXX = source ${HOME}/git/emsdk/emsdk_env.sh && em++
+
+all: | format rock_paper_scissors_duel.html
+
+rock_paper_scissors_duel.html: ${SOURCES} ${HEADERS}
+       ${CXX} -o rock_paper_scissors_duel.html \
+               -s USE_GLFW=3 -I../wasm_includes -L../wasm_libs -lraylib \
+               --shell-file custom_shell.html \
+               -sEXPORTED_FUNCTIONS=_main,_game_visual_update \
+               -sEXPORTED_RUNTIME_METHODS=ccall \
+               ${OTHER_FLAGS} \
+               ${SOURCES}
+
+.PHONY: clean format
+
+clean:
+       rm -f rock_paper_scissors_duel.html
+       rm -f rock_paper_scissors_duel.js
+       rm -f rock_paper_scissors_duel.wasm
+       rm -f rock_paper_scissors_duel.data
+
+format:
+       clang-format -i --style=file ${SOURCES} ${HEADERS}
diff --git a/wasm_build/client.js b/wasm_build/client.js
new file mode 100644 (file)
index 0000000..662ea3e
--- /dev/null
@@ -0,0 +1,18 @@
+Rune.initClient({
+    visualUpdate: ({ newGame, yourPlayerId}) => {
+        const { player1, player2, first_choices, second_choices, first_ready, second_ready, pos } = newGame;
+
+        Module.ccall('_game_visual_update',
+            undefined,
+            ['string', 'string', 'string',
+                'number', 'number', 'number',
+                'number', 'number', 'number',
+                'boolean', 'boolean',
+                'number'],
+            [player1, player2, yourPlayerId === undefined ? 'undefined' : yourPlayerId,
+                first_choices[0], first_choices[1], first_choices[2],
+                second_choices[0], second_choices[1], second_choices[2],
+                first_ready, second_ready,
+                pos]);
+    },
+});
diff --git a/wasm_build/custom_shell.html b/wasm_build/custom_shell.html
new file mode 100644 (file)
index 0000000..c2386ff
--- /dev/null
@@ -0,0 +1,65 @@
+<!doctype html>
+<html lang="en-us">
+  <head>
+    <meta charset="utf-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no"/>
+    <title>Hexagonal Crawler</title>
+    <style>
+        body { margin: 0; background-color: black }
+        .emscripten {
+            position: absolute;
+            top: 0px;
+            left: 0px;
+            margin: 0px;
+            border: 0;
+            width: 100%;
+            height: 100%;
+            overflow: hidden;
+            display: block;
+            image-rendering: optimizeSpeed;
+            image-rendering: -moz-crisp-edges;
+            image-rendering: -o-crisp-edges;
+            image-rendering: -webkit-optimize-contrast;
+            image-rendering: optimize-contrast;
+            image-rendering: crisp-edges;
+            image-rendering: pixelated;
+            -ms-interpolation-mode: nearest-neighbor;
+        }
+    </style>
+  </head>
+  <body>
+<!--    <script src="https://cdn.jsdelivr.net/npm/rune-games-sdk@2.5.2/dist/browser.min.js"></script> -->
+    <canvas class="emscripten" id="canvas" oncontextmenu="event.preventDefault()"></canvas>
+    <script type='text/javascript'>
+      var Module = {
+        preRun: [],
+        postRun: [],
+        print: (function() {
+            return function(text) {
+                text = Array.prototype.slice.call(arguments).join(' ');
+                console.log(text);
+            };
+        })(),
+        printErr: function(text) {
+            text = Array.prototype.slice.call(arguments).join(' ');
+            console.error(text);
+        },
+        canvas: (function() {
+            var canvas = document.getElementById('canvas');
+            //canvas.addEventListener("webglcontextlost", function(e) { alert('FIXME: WebGL context lost, please reload the page'); e.preventDefault(); }, false);
+            return canvas;
+        })(),
+        setStatus: function(text) {
+            console.log("status: " + text);
+        },
+        monitorRunDependencies: function(left) {
+            // no run dependencies to log
+        }
+      };
+      window.onerror = function() {
+        console.log("onerror: " + event);
+      };
+    </script>
+    {{{ SCRIPT }}}
+  </body>
+</html>
diff --git a/wasm_build/logic.js b/wasm_build/logic.js
new file mode 100644 (file)
index 0000000..3fb3746
--- /dev/null
@@ -0,0 +1,124 @@
+Rune.initlogic({
+    minPlayers: 2,
+    maxPlayers: 2,
+    setup: (players) => ({
+        player1: players[0],
+        player2: players[1],
+        first_choices: new Array(3).fill(null),
+        second_choices: new Array(3).fill(null),
+        first_ready: false,
+        second_ready: false,
+        pos: 0,
+    }),
+    actions: {
+        set_choices: (first, second, third, { game, playerId }) => {
+            if (!game.first_ready || !game.second_ready) {
+                throw Rune.invalidAction();
+            }
+
+            let is_first = game.player1 === playerId;
+
+            function is_choices_filled(choices) {
+                for (let i = 0; i < 3; ++i) {
+                    if (choices[i] === null) {
+                        return false;
+                    }
+                }
+                return true;
+            }
+
+            if (is_choices_filled(is_first ? game.first_choices : game.second_choices)) {
+                throw Rune.invalidAction();
+            }
+
+            function is_valid_choice(choice) {
+                if (choice !== 'r' && choice !== 'p' && choice !== 's') {
+                    return false;
+                }
+                return true;
+            }
+
+            if (!is_valid_choice(first) || !is_valid_choice(second)
+                    || !is_valid_choice(third)) {
+                throw Rune.invalidAction();
+            }
+
+            if (is_first) {
+                game.first_choices[0] = first;
+                game.first_choices[1] = second;
+                game.first_choices[2] = third;
+            } else {
+                game.second_choices[0] = first;
+                game.second_choices[1] = second;
+                game.second_choices[2] = third;
+            }
+
+
+            if (!is_choices_filled(game.first_choices)
+                    || !is_choices_filled(game.second_choices)) {
+                return;
+            }
+
+            // Both sides are ready, iterate through matchups
+
+            let has_remaining = false;
+
+            for (let i = 0; i < 3; ++i) {
+                // Get next matchup
+                if (game.first_choices[i] === 'r'
+                        || game.first_choices[i] === 'p'
+                        || game.first_choices[i] === 's') {
+                    // check if first won the matchup
+                    if ((game.first_choices[i] === 'r' && game.second_choices[i] === 's')
+                            || (game.first_choices[i] === 'p' && game.second_choices[i] === 'r')
+                            || (game.first_choices[i] === 's' && game.second_choices[i] === 'p')) {
+                        game.first_choices[i] = 'w';
+                        game.second_choices[i] = 'l';
+                        game.pos = game.pos + 1;
+                    }
+                    // check if second won the matchup
+                    else if ((game.first_choices[i] === 'r' && game.second_choices[i] === 'p')
+                            || (game.first_choices[i] === 'p' && game.second_choices[i] === 's')
+                            || (game.first_choices[i] === 's' && game.second_choices[i] === 'r')) {
+                        game.first_choices[i] = 'l';
+                        game.second_choices[i] = 'w';
+                        game.pos = game.pos - 1;
+                    }
+                    // matchup was a draw
+                    else {
+                        game.first_choices[i] = 'd';
+                        game.second_choices[i] = 'd';
+                    }
+                    has_remaining = i === 2 ? false : true;
+                }
+            }
+
+            game.first_ready = false;
+            game.second_ready = false;
+            if (!has_remaining) {
+                if (pos <= -3) {
+                    // second won
+                    Rune.gameOver();
+                } else if (pos >= 3) {
+                    // first won
+                    Rune.gameOver();
+                } else {
+                    // game is still going
+                    for (let i = 0; i < 3; ++i) {
+                        game.first_choices[i] = null;
+                        game.second_choices[i] = null;
+                    }
+                }
+            }
+        },
+        set_ready: ({ game, playerId }) => {
+            let is_first = game.player1 === playerId;
+
+            if (is_first) {
+                game.first_ready = true;
+            } else {
+                game.second_ready = true;
+            }
+        },
+    },
+})