From b5be3ac5ad22afbc0d69eb70bef506d9107f1e4f Mon Sep 17 00:00:00 2001 From: Stephen Seo Date: Sun, 1 Jan 2023 20:23:52 +0900 Subject: [PATCH] WIP work on game (logic.js about done) --- .gitignore | 3 + CMakeLists.txt | 25 +++++++ src/.lvimrc | 3 + src/constants.h | 7 ++ src/main.cc | 62 ++++++++++++++++++ wasm_build/.gitignore | 4 ++ wasm_build/Makefile | 35 ++++++++++ wasm_build/client.js | 18 +++++ wasm_build/custom_shell.html | 65 ++++++++++++++++++ wasm_build/logic.js | 124 +++++++++++++++++++++++++++++++++++ 10 files changed, 346 insertions(+) create mode 100644 .gitignore create mode 100644 CMakeLists.txt create mode 100644 src/.lvimrc create mode 100644 src/constants.h create mode 100644 src/main.cc create mode 100644 wasm_build/.gitignore create mode 100644 wasm_build/Makefile create mode 100644 wasm_build/client.js create mode 100644 wasm_build/custom_shell.html create mode 100644 wasm_build/logic.js diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..52afeba --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/build*/ +/compile_commands.json +/.cache/ diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..e6465aa --- /dev/null +++ b/CMakeLists.txt @@ -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 index 0000000..81ba35f --- /dev/null +++ b/src/.lvimrc @@ -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 index 0000000..56151e0 --- /dev/null +++ b/src/constants.h @@ -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 index 0000000..f18db16 --- /dev/null +++ b/src/main.cc @@ -0,0 +1,62 @@ +// emscripten includes +#ifdef __EMSCRIPTEN__ +#include +#include +#else +#include +#endif + +// third party includes +#include + +// 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 index 0000000..f60af13 --- /dev/null +++ b/wasm_build/.gitignore @@ -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 index 0000000..5a932af --- /dev/null +++ b/wasm_build/Makefile @@ -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 index 0000000..662ea3e --- /dev/null +++ b/wasm_build/client.js @@ -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 index 0000000..c2386ff --- /dev/null +++ b/wasm_build/custom_shell.html @@ -0,0 +1,65 @@ + + + + + + Hexagonal Crawler + + + + + + + {{{ SCRIPT }}} + + diff --git a/wasm_build/logic.js b/wasm_build/logic.js new file mode 100644 index 0000000..3fb3746 --- /dev/null +++ b/wasm_build/logic.js @@ -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; + } + }, + }, +}) -- 2.49.0