summaryrefslogtreecommitdiff
path: root/rushs/libzork
diff options
context:
space:
mode:
authorMartial Simon <msimon_fr@hotmail.com>2025-09-15 01:08:27 +0200
committerMartial Simon <msimon_fr@hotmail.com>2025-09-15 01:08:27 +0200
commitc9b6b9a5ca082fe7c1b6f58d7713f785a9eb6a5c (patch)
tree3e4f42f93c7ae89a364e4d51fff6e5cec4e55fa9 /rushs/libzork
add: graphs et rushs
Diffstat (limited to 'rushs/libzork')
-rw-r--r--rushs/libzork/libzork/CMakeLists.txt22
-rw-r--r--rushs/libzork/libzork/client/flake.nix23
-rw-r--r--rushs/libzork/libzork/src/CMakeLists.txt24
-rw-r--r--rushs/libzork/libzork/src/exceptions.cc6
-rw-r--r--rushs/libzork/libzork/src/exceptions.hh17
-rw-r--r--rushs/libzork/libzork/src/runner/CMakeLists.txt6
-rw-r--r--rushs/libzork/libzork/src/runner/caca.caca13
-rw-r--r--rushs/libzork/libzork/src/runner/choice.cc17
-rw-r--r--rushs/libzork/libzork/src/runner/choice_impl.cc40
-rw-r--r--rushs/libzork/libzork/src/runner/choice_impl.hh18
-rw-r--r--rushs/libzork/libzork/src/runner/html.cc18
-rw-r--r--rushs/libzork/libzork/src/runner/html_impl.cc13
-rw-r--r--rushs/libzork/libzork/src/runner/html_impl.hh16
-rw-r--r--rushs/libzork/libzork/src/runner/interactive.cc40
-rw-r--r--rushs/libzork/libzork/src/runner/runner.cc12
-rw-r--r--rushs/libzork/libzork/src/runner/smart.cc21
-rw-r--r--rushs/libzork/libzork/src/runner/smart_impl.cc29
-rw-r--r--rushs/libzork/libzork/src/runner/smart_impl.hh20
-rw-r--r--rushs/libzork/libzork/src/store/CMakeLists.txt6
-rw-r--r--rushs/libzork/libzork/src/store/store.cc14
-rw-r--r--rushs/libzork/libzork/src/store/store_impl.cc42
-rw-r--r--rushs/libzork/libzork/src/store/store_impl.hh26
-rw-r--r--rushs/libzork/libzork/src/story/CMakeLists.txt6
-rw-r--r--rushs/libzork/libzork/src/story/choice.cc16
-rw-r--r--rushs/libzork/libzork/src/story/choice.hh25
-rw-r--r--rushs/libzork/libzork/src/story/node.cc21
-rw-r--r--rushs/libzork/libzork/src/story/node_impl.cc73
-rw-r--r--rushs/libzork/libzork/src/story/node_impl.hh38
-rw-r--r--rushs/libzork/libzork/src/story/story.cc15
-rw-r--r--rushs/libzork/libzork/src/story/story_impl.cc118
-rw-r--r--rushs/libzork/libzork/src/story/story_impl.hh31
-rw-r--r--rushs/libzork/libzork/src/vars/CMakeLists.txt6
-rw-r--r--rushs/libzork/libzork/src/vars/action.cc20
-rw-r--r--rushs/libzork/libzork/src/vars/action_impl.cc13
-rw-r--r--rushs/libzork/libzork/src/vars/action_impl.hh16
-rw-r--r--rushs/libzork/libzork/src/vars/condition.cc21
-rw-r--r--rushs/libzork/libzork/src/vars/condition_impl.cc16
-rw-r--r--rushs/libzork/libzork/src/vars/condition_impl.hh16
-rw-r--r--rushs/libzork/libzork/tests/scripts/little_quest/castle.txt3
-rw-r--r--rushs/libzork/libzork/tests/scripts/little_quest/castle_weapon.txt3
-rw-r--r--rushs/libzork/libzork/tests/scripts/little_quest/forest.txt4
-rw-r--r--rushs/libzork/libzork/tests/scripts/little_quest/house.txt2
-rw-r--r--rushs/libzork/libzork/tests/scripts/little_quest/tower.txt2
-rw-r--r--rushs/libzork/libzork/tests/scripts/short_static/cave.txt1
-rw-r--r--rushs/libzork/libzork/tests/scripts/short_static/forest.txt1
-rw-r--r--rushs/libzork/libzork/tests/scripts/short_static/welcome.txt1
-rw-r--r--rushs/libzork/libzork/tests/stories/dynamic/story.yml51
-rw-r--r--rushs/libzork/libzork/tests/stories/long_static/story.yml25
-rw-r--r--rushs/libzork/libzork/tests/stories/short_static/story.yml16
-rw-r--r--rushs/libzork/libzork/zorkxplorer/CMakeLists.txt3
-rw-r--r--rushs/libzork/libzork/zorkxplorer/src/CMakeLists.txt3
-rw-r--r--rushs/libzork/libzork/zorkxplorer/src/hello.txt1
-rw-r--r--rushs/libzork/libzork/zorkxplorer/src/main.cc63
-rw-r--r--rushs/libzork/libzork/zorkxplorer/src/options.cc57
-rw-r--r--rushs/libzork/libzork/zorkxplorer/src/options.hh22
-rw-r--r--rushs/libzork/libzork/zorkxplorer/src/world.txt1
56 files changed, 1153 insertions, 0 deletions
diff --git a/rushs/libzork/libzork/CMakeLists.txt b/rushs/libzork/libzork/CMakeLists.txt
new file mode 100644
index 0000000..f9fccbc
--- /dev/null
+++ b/rushs/libzork/libzork/CMakeLists.txt
@@ -0,0 +1,22 @@
+cmake_minimum_required(VERSION 3.21.2)
+project(Zork)
+
+add_executable(zork_test)
+target_compile_options(zork_test PRIVATE -Wall -Wextra -Werror -pedantic -std=c++20 -Wold-style-cast)
+set_target_properties(zork_test PROPERTIES
+ CXX_STANDARD 20
+ CXX_EXTENSIONS OFF)
+add_subdirectory(src)
+add_subdirectory(zorkxplorer)
+
+target_link_libraries(zork_test PUBLIC libzork)
+target_include_directories(zork_test PUBLIC
+ "${PROJECT_BINARY_DIR}"
+ "${PROJECT_SOURCE_DIR}/include"
+ "${PROJECT_SOURCE_DIR}/src"
+)
+target_include_directories(libzork PUBLIC
+ "${PROJECT_BINARY_DIR}"
+ "${PROJECT_SOURCE_DIR}/include"
+ "${PROJECT_SOURCE_DIR}/src"
+) \ No newline at end of file
diff --git a/rushs/libzork/libzork/client/flake.nix b/rushs/libzork/libzork/client/flake.nix
new file mode 100644
index 0000000..b6eb844
--- /dev/null
+++ b/rushs/libzork/libzork/client/flake.nix
@@ -0,0 +1,23 @@
+{
+ description = "Flake for libzork";
+
+ inputs = {
+ nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
+ };
+
+ outputs = { self, nixpkgs }: {
+ devShells.x86_64-linux.default = with nixpkgs.legacyPackages.x86_64-linux; mkShell {
+ buildInputs = [
+ gcc
+ cmake
+ yaml-cpp
+ curl
+ nlohmann_json
+ openssl
+ cmake
+ pkg-config
+ ];
+
+ };
+ };
+}
diff --git a/rushs/libzork/libzork/src/CMakeLists.txt b/rushs/libzork/libzork/src/CMakeLists.txt
new file mode 100644
index 0000000..4f4224d
--- /dev/null
+++ b/rushs/libzork/libzork/src/CMakeLists.txt
@@ -0,0 +1,24 @@
+cmake_minimum_required(VERSION 3.21.2)
+project(Zork)
+add_library(libzork SHARED)
+
+target_compile_options(libzork PUBLIC -Wall -Wextra -Werror -pedantic -std=c++20 -Wold-style-cast)
+set_target_properties(libzork PROPERTIES
+ CXX_STANDARD 20
+ CXX_EXTENSIONS OFF
+ LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}"
+ OUTPUT_NAME "zork" )
+target_include_directories(libzork PRIVATE
+ "${PROJECT_SOURCE_DIR}/include"
+ "${PROJECT_SOURCE_DIR}/src"
+)
+
+target_sources(libzork PRIVATE exceptions.cc)
+
+find_library(YAML-CPP NAMES yaml-cpp libyaml-cpp REQUIRED)
+target_link_libraries(libzork PUBLIC yaml-cpp)
+
+add_subdirectory(runner)
+add_subdirectory(store)
+add_subdirectory(story)
+add_subdirectory(vars) \ No newline at end of file
diff --git a/rushs/libzork/libzork/src/exceptions.cc b/rushs/libzork/libzork/src/exceptions.cc
new file mode 100644
index 0000000..f24eb9b
--- /dev/null
+++ b/rushs/libzork/libzork/src/exceptions.cc
@@ -0,0 +1,6 @@
+#include "exceptions.hh"
+
+#include <string>
+
+namespace libzork
+{} // namespace libzork
diff --git a/rushs/libzork/libzork/src/exceptions.hh b/rushs/libzork/libzork/src/exceptions.hh
new file mode 100644
index 0000000..93c0a0b
--- /dev/null
+++ b/rushs/libzork/libzork/src/exceptions.hh
@@ -0,0 +1,17 @@
+#pragma once
+
+#include <stdexcept>
+
+namespace libzork
+{
+ class NotImplemented : public std::runtime_error
+ {
+ public:
+ NotImplemented(const char* file = __builtin_FILE(),
+ int line = __builtin_LINE())
+ : std::runtime_error(std::string{ "Unimplemented function: " }
+ + file + ":" + std::to_string(line))
+ {}
+ };
+
+} // namespace libzork
diff --git a/rushs/libzork/libzork/src/runner/CMakeLists.txt b/rushs/libzork/libzork/src/runner/CMakeLists.txt
new file mode 100644
index 0000000..5e472d4
--- /dev/null
+++ b/rushs/libzork/libzork/src/runner/CMakeLists.txt
@@ -0,0 +1,6 @@
+cmake_minimum_required(VERSION 3.21.2)
+project(Zork)
+target_sources(libzork PRIVATE choice.cc choice_impl.cc html.cc html_impl.cc interactive.cc runner.cc smart.cc smart_impl.cc)
+set_target_properties(libzork PROPERTIES
+ CXX_STANDARD 20
+ CXX_EXTENSIONS OFF) \ No newline at end of file
diff --git a/rushs/libzork/libzork/src/runner/caca.caca b/rushs/libzork/libzork/src/runner/caca.caca
new file mode 100644
index 0000000..2df4dd2
--- /dev/null
+++ b/rushs/libzork/libzork/src/runner/caca.caca
@@ -0,0 +1,13 @@
+#include <caca.h>
+
+void caca::caca(caca::Caca& caca, string caca) {
+ std::caca caca = caca.get_caca();
+ for(auto caca : caca) {
+ if(!caca->caca.is_caca()) {
+ return caca;
+ }
+ caca = caca.caca;
+ }
+ caca.set_caca(caca.get_caca());
+ return caca;
+} \ No newline at end of file
diff --git a/rushs/libzork/libzork/src/runner/choice.cc b/rushs/libzork/libzork/src/runner/choice.cc
new file mode 100644
index 0000000..1e677bb
--- /dev/null
+++ b/rushs/libzork/libzork/src/runner/choice.cc
@@ -0,0 +1,17 @@
+#include <algorithm>
+#include <libzork/runner/choice.hh>
+
+#include "exceptions.hh"
+#include "runner/choice_impl.hh"
+
+namespace libzork::runner
+{
+
+ std::unique_ptr<ChoiceRunner>
+ make_choice_runner(std::unique_ptr<story::Story> story, std::istream& is,
+ std::ostream& os)
+ {
+ return std::make_unique<ChoiceRunnerImpl>(std::move(story), is, os);
+ }
+
+} // namespace libzork::runner
diff --git a/rushs/libzork/libzork/src/runner/choice_impl.cc b/rushs/libzork/libzork/src/runner/choice_impl.cc
new file mode 100644
index 0000000..2572ef3
--- /dev/null
+++ b/rushs/libzork/libzork/src/runner/choice_impl.cc
@@ -0,0 +1,40 @@
+#include "runner/choice_impl.hh"
+
+#include <libzork/exceptions.hh>
+#include <sstream>
+
+#include "exceptions.hh"
+
+namespace libzork::runner
+{
+
+ void ChoiceRunnerImpl::print_script() const
+ {
+ InteractiveRunner::print_script();
+ os_ << "\n";
+ size_t i = 1;
+ for (auto choice : story_->get_current()->list_choices())
+ {
+ os_ << i << ". " << choice << "\n";
+ i++;
+ }
+ os_ << "\n";
+ }
+
+ void ChoiceRunnerImpl::process_input()
+ {
+ int input;
+ std::string s;
+ std::getline(is_, s);
+ if (!is_)
+ throw RunnerInterrupt{ "Bad input." };
+ std::istringstream ss{ s };
+ ss >> input;
+ const story::Node* choice;
+ if (ss.fail() || !ss.eof()
+ || !((choice = story_->get_current()->get_choice(input - 1))))
+ throw RunnerInterrupt{ "Bad input." };
+ story_->set_current(choice);
+ }
+
+} // namespace libzork::runner
diff --git a/rushs/libzork/libzork/src/runner/choice_impl.hh b/rushs/libzork/libzork/src/runner/choice_impl.hh
new file mode 100644
index 0000000..6818bab
--- /dev/null
+++ b/rushs/libzork/libzork/src/runner/choice_impl.hh
@@ -0,0 +1,18 @@
+#pragma once
+
+#include <libzork/runner/choice.hh>
+
+namespace libzork::runner
+{
+
+ class ChoiceRunnerImpl : public ChoiceRunner
+ {
+ public:
+ using ChoiceRunner::ChoiceRunner;
+ ~ChoiceRunnerImpl() override = default;
+
+ void print_script() const override;
+ void process_input() override;
+ };
+
+} // namespace libzork::runner
diff --git a/rushs/libzork/libzork/src/runner/html.cc b/rushs/libzork/libzork/src/runner/html.cc
new file mode 100644
index 0000000..ec67f43
--- /dev/null
+++ b/rushs/libzork/libzork/src/runner/html.cc
@@ -0,0 +1,18 @@
+#include <libzork/runner/html.hh>
+
+#include "exceptions.hh"
+#include "runner/html_impl.hh"
+
+namespace libzork::runner
+{
+
+ std::unique_ptr<HTMLRunner>
+ make_html_runner(std::unique_ptr<story::Story> story,
+ const fs::path& output_dir)
+ {
+ (void)story;
+ (void)output_dir;
+ throw NotImplemented();
+ }
+
+} // namespace libzork::runner
diff --git a/rushs/libzork/libzork/src/runner/html_impl.cc b/rushs/libzork/libzork/src/runner/html_impl.cc
new file mode 100644
index 0000000..e7b982b
--- /dev/null
+++ b/rushs/libzork/libzork/src/runner/html_impl.cc
@@ -0,0 +1,13 @@
+#include "runner/html_impl.hh"
+
+#include "exceptions.hh"
+
+namespace libzork::runner
+{
+
+ void HTMLRunnerImpl::run()
+ {
+ throw NotImplemented();
+ }
+
+} // namespace libzork::runner
diff --git a/rushs/libzork/libzork/src/runner/html_impl.hh b/rushs/libzork/libzork/src/runner/html_impl.hh
new file mode 100644
index 0000000..3d47a3e
--- /dev/null
+++ b/rushs/libzork/libzork/src/runner/html_impl.hh
@@ -0,0 +1,16 @@
+#pragma once
+
+#include <libzork/runner/html.hh>
+
+namespace libzork::runner
+{
+
+ class HTMLRunnerImpl : public HTMLRunner
+ {
+ public:
+ ~HTMLRunnerImpl() override = default;
+
+ void run() override;
+ };
+
+} // namespace libzork::runner
diff --git a/rushs/libzork/libzork/src/runner/interactive.cc b/rushs/libzork/libzork/src/runner/interactive.cc
new file mode 100644
index 0000000..85a76a8
--- /dev/null
+++ b/rushs/libzork/libzork/src/runner/interactive.cc
@@ -0,0 +1,40 @@
+#include <libzork/exceptions.hh>
+#include <libzork/runner/interactive.hh>
+
+#include "exceptions.hh"
+
+namespace libzork::runner
+{
+
+ InteractiveRunner::InteractiveRunner(std::unique_ptr<story::Story> story,
+ std::istream& is, std::ostream& os)
+ : Runner(std::move(story))
+ , is_(is)
+ , os_(os)
+ {}
+
+ void InteractiveRunner::print_script() const
+ {
+ os_ << story_->get_current()->get_text();
+ }
+
+ void InteractiveRunner::run()
+ {
+ print_script();
+ while (story_->get_current()->list_choices().size() != 0)
+ {
+ try
+ {
+ os_ << "> ";
+ process_input();
+ }
+ catch (RunnerInterrupt& i)
+ {
+ os_ << i.what() << "\n";
+ continue;
+ }
+ print_script();
+ }
+ }
+
+} // namespace libzork::runner
diff --git a/rushs/libzork/libzork/src/runner/runner.cc b/rushs/libzork/libzork/src/runner/runner.cc
new file mode 100644
index 0000000..3968723
--- /dev/null
+++ b/rushs/libzork/libzork/src/runner/runner.cc
@@ -0,0 +1,12 @@
+#include <libzork/runner/runner.hh>
+
+#include "exceptions.hh"
+
+namespace libzork::runner
+{
+
+ Runner::Runner(std::unique_ptr<story::Story> story)
+ : story_{ std::move(story) }
+ {}
+
+} // namespace libzork::runner
diff --git a/rushs/libzork/libzork/src/runner/smart.cc b/rushs/libzork/libzork/src/runner/smart.cc
new file mode 100644
index 0000000..e99dd90
--- /dev/null
+++ b/rushs/libzork/libzork/src/runner/smart.cc
@@ -0,0 +1,21 @@
+#include <libzork/runner/smart.hh>
+
+#include "exceptions.hh"
+#include "runner/smart_impl.hh"
+
+namespace libzork::runner
+{
+
+ std::unique_ptr<SmartRunner>
+ make_smart_runner(std::unique_ptr<story::Story> story,
+ const fs::path& synonyms_path, std::istream& is,
+ std::ostream& os)
+ {
+ (void)story;
+ (void)synonyms_path;
+ (void)is;
+ (void)os;
+ throw NotImplemented();
+ }
+
+} // namespace libzork::runner
diff --git a/rushs/libzork/libzork/src/runner/smart_impl.cc b/rushs/libzork/libzork/src/runner/smart_impl.cc
new file mode 100644
index 0000000..022f07a
--- /dev/null
+++ b/rushs/libzork/libzork/src/runner/smart_impl.cc
@@ -0,0 +1,29 @@
+#include "runner/smart_impl.hh"
+
+#include "exceptions.hh"
+
+namespace libzork::runner
+{
+
+ void SmartRunnerImpl::process_input()
+ {
+ throw NotImplemented();
+ }
+
+ std::unordered_set<std::string>
+ SmartRunnerImpl::tokenize(const std::string& str) const
+ {
+ (void)str;
+ throw NotImplemented();
+ }
+
+ bool SmartRunnerImpl::has_unmatched_token(
+ const std::unordered_set<std::string>& user_tokens,
+ const std::unordered_set<std::string>& choice_tokens) const
+ {
+ (void)user_tokens;
+ (void)choice_tokens;
+ throw NotImplemented();
+ }
+
+} // namespace libzork::runner
diff --git a/rushs/libzork/libzork/src/runner/smart_impl.hh b/rushs/libzork/libzork/src/runner/smart_impl.hh
new file mode 100644
index 0000000..201237f
--- /dev/null
+++ b/rushs/libzork/libzork/src/runner/smart_impl.hh
@@ -0,0 +1,20 @@
+#pragma once
+
+#include <libzork/runner/smart.hh>
+
+namespace libzork::runner
+{
+
+ class SmartRunnerImpl : public SmartRunner
+ {
+ public:
+ void process_input() override;
+ virtual std::unordered_set<std::string>
+ tokenize(const std::string& str) const override;
+ virtual bool
+ has_unmatched_token(const std::unordered_set<std::string>& user_tokens,
+ const std::unordered_set<std::string>&
+ choice_tokens) const override;
+ };
+
+} // namespace libzork::runner
diff --git a/rushs/libzork/libzork/src/store/CMakeLists.txt b/rushs/libzork/libzork/src/store/CMakeLists.txt
new file mode 100644
index 0000000..420356d
--- /dev/null
+++ b/rushs/libzork/libzork/src/store/CMakeLists.txt
@@ -0,0 +1,6 @@
+cmake_minimum_required(VERSION 3.21.2)
+project(Zork)
+target_sources(libzork PRIVATE store.cc store_impl.cc)
+set_target_properties(libzork PROPERTIES
+ CXX_STANDARD 20
+ CXX_EXTENSIONS OFF) \ No newline at end of file
diff --git a/rushs/libzork/libzork/src/store/store.cc b/rushs/libzork/libzork/src/store/store.cc
new file mode 100644
index 0000000..be91193
--- /dev/null
+++ b/rushs/libzork/libzork/src/store/store.cc
@@ -0,0 +1,14 @@
+#include <libzork/store/store.hh>
+
+#include "exceptions.hh"
+#include "store/store_impl.hh"
+
+namespace libzork::store
+{
+
+ std::unique_ptr<Store> make_store()
+ {
+ return std::make_unique<StoreImpl>();
+ }
+
+} // namespace libzork::store
diff --git a/rushs/libzork/libzork/src/store/store_impl.cc b/rushs/libzork/libzork/src/store/store_impl.cc
new file mode 100644
index 0000000..3abcb55
--- /dev/null
+++ b/rushs/libzork/libzork/src/store/store_impl.cc
@@ -0,0 +1,42 @@
+#include "store/store_impl.hh"
+
+#include "exceptions.hh"
+
+namespace libzork::store
+{
+
+ const story::Node* StoreImpl::get_active_node() const
+ {
+ return active_node_;
+ }
+
+ void StoreImpl::set_active_node(const story::Node* node)
+ {
+ active_node_ = node;
+ }
+
+ bool StoreImpl::has_variable(const std::string& name) const
+ {
+ (void)name;
+ throw NotImplemented();
+ }
+
+ int StoreImpl::get_variable(const std::string& name) const
+ {
+ (void)name;
+ throw NotImplemented();
+ }
+
+ void StoreImpl::set_variable(const std::string& name, int value)
+ {
+ (void)name;
+ (void)value;
+ throw NotImplemented();
+ }
+
+ std::map<std::string, int> StoreImpl::get_inventory() const
+ {
+ throw NotImplemented();
+ }
+
+} // namespace libzork::store
diff --git a/rushs/libzork/libzork/src/store/store_impl.hh b/rushs/libzork/libzork/src/store/store_impl.hh
new file mode 100644
index 0000000..a978128
--- /dev/null
+++ b/rushs/libzork/libzork/src/store/store_impl.hh
@@ -0,0 +1,26 @@
+#pragma once
+
+#include <libzork/store/store.hh>
+
+namespace libzork::store
+{
+
+ class StoreImpl : public Store
+ {
+ public:
+ StoreImpl() = default;
+ ~StoreImpl() override = default;
+
+ const story::Node* get_active_node() const override;
+ void set_active_node(const story::Node* node) override;
+
+ bool has_variable(const std::string& name) const override;
+ int get_variable(const std::string& name) const override;
+ void set_variable(const std::string& name, int value) override;
+ std::map<std::string, int> get_inventory() const override;
+
+ private:
+ const story::Node* active_node_ = nullptr;
+ };
+
+} // namespace libzork::store
diff --git a/rushs/libzork/libzork/src/story/CMakeLists.txt b/rushs/libzork/libzork/src/story/CMakeLists.txt
new file mode 100644
index 0000000..6549964
--- /dev/null
+++ b/rushs/libzork/libzork/src/story/CMakeLists.txt
@@ -0,0 +1,6 @@
+cmake_minimum_required(VERSION 3.21.2)
+project(Zork)
+target_sources(libzork PRIVATE node.cc node_impl.cc story.cc story_impl.cc choice.cc)
+set_target_properties(libzork PROPERTIES
+ CXX_STANDARD 20
+ CXX_EXTENSIONS OFF) \ No newline at end of file
diff --git a/rushs/libzork/libzork/src/story/choice.cc b/rushs/libzork/libzork/src/story/choice.cc
new file mode 100644
index 0000000..4b01983
--- /dev/null
+++ b/rushs/libzork/libzork/src/story/choice.cc
@@ -0,0 +1,16 @@
+//
+// Created by martial.simon on 2/28/25.
+//
+
+#include <story/choice.hh>
+namespace libzork::story
+{
+ std::string Choice::get_text() const
+ {
+ return text_;
+ }
+ const Node* Choice::get_choice() const
+ {
+ return choice_;
+ }
+} // namespace libzork::story \ No newline at end of file
diff --git a/rushs/libzork/libzork/src/story/choice.hh b/rushs/libzork/libzork/src/story/choice.hh
new file mode 100644
index 0000000..08bbd29
--- /dev/null
+++ b/rushs/libzork/libzork/src/story/choice.hh
@@ -0,0 +1,25 @@
+//
+// Created by martial.simon on 2/28/25.
+//
+
+#pragma once
+#include <libzork/story/node.hh>
+#include <string>
+
+namespace libzork::story
+{
+ class Choice
+ {
+ public:
+ Choice(const std::string& text, const Node* choice)
+ : text_(text)
+ , choice_(choice)
+ {}
+ std::string get_text() const;
+ const Node* get_choice() const;
+
+ private:
+ std::string text_;
+ const Node* choice_;
+ };
+} // namespace libzork::story
diff --git a/rushs/libzork/libzork/src/story/node.cc b/rushs/libzork/libzork/src/story/node.cc
new file mode 100644
index 0000000..416b902
--- /dev/null
+++ b/rushs/libzork/libzork/src/story/node.cc
@@ -0,0 +1,21 @@
+#include <fstream>
+#include <libzork/story/node.hh>
+
+#include "exceptions.hh"
+#include "story/node_impl.hh"
+
+namespace libzork::story
+{
+
+ std::unique_ptr<Node> make_node(const std::string& name,
+ const fs::path& script_path)
+ {
+ auto stream = std::ifstream(script_path.c_str());
+ if (!stream.is_open())
+ throw std::invalid_argument{ "Invalid file, unable to open." };
+ std::ostringstream o;
+ o << stream.rdbuf();
+ return std::make_unique<NodeImpl>(name, o.str());
+ }
+
+} // namespace libzork::story
diff --git a/rushs/libzork/libzork/src/story/node_impl.cc b/rushs/libzork/libzork/src/story/node_impl.cc
new file mode 100644
index 0000000..c9877e8
--- /dev/null
+++ b/rushs/libzork/libzork/src/story/node_impl.cc
@@ -0,0 +1,73 @@
+#include "story/node_impl.hh"
+
+#include <fstream>
+
+#include "exceptions.hh"
+
+namespace libzork::story
+{
+ NodeImpl::NodeImpl(const std::string& name, const std::string& text)
+ : name_(name)
+ , text_(text)
+ {}
+
+ const std::string& NodeImpl::get_name() const
+ {
+ return name_;
+ }
+
+ const std::string& NodeImpl::get_text() const
+ {
+ return text_;
+ }
+
+ const Node* NodeImpl::get_choice(size_t index, bool check_conditions) const
+ {
+ (void)check_conditions;
+ if (choices_.size() <= index)
+ return nullptr;
+ return choices_.at(index).get_choice();
+ }
+
+ std::vector<std::string> NodeImpl::list_choices(bool check_conditions) const
+ {
+ (void)check_conditions;
+ std::vector<std::string> texts;
+ for (auto choice : choices_)
+ {
+ texts.push_back(choice.get_text());
+ }
+ return texts;
+ }
+
+ void NodeImpl::add_choice(
+ const Node* other, const std::string& text,
+ std::vector<std::unique_ptr<vars::Condition>> conditions,
+ std::vector<std::unique_ptr<vars::Action>> actions)
+ {
+ (void)conditions;
+ (void)actions;
+ Choice c{ text, other };
+ choices_.push_back(std::move(c));
+ }
+
+ const NodeImpl& to_impl(const Node& node)
+ {
+ const NodeImpl* cast = dynamic_cast<const NodeImpl*>(&node);
+ if (!cast)
+ throw std::runtime_error{
+ "Invalid conversion from const Node* to const NodeImpl*"
+ };
+ return *cast;
+ }
+
+ NodeImpl& to_impl(Node& node)
+ {
+ NodeImpl* cast = dynamic_cast<NodeImpl*>(&node);
+ if (!cast)
+ throw std::runtime_error{
+ "Invalid conversion from const Node* to const NodeImpl*"
+ };
+ return *cast;
+ }
+} // namespace libzork::story
diff --git a/rushs/libzork/libzork/src/story/node_impl.hh b/rushs/libzork/libzork/src/story/node_impl.hh
new file mode 100644
index 0000000..f55de7c
--- /dev/null
+++ b/rushs/libzork/libzork/src/story/node_impl.hh
@@ -0,0 +1,38 @@
+#pragma once
+
+#include <libzork/story/node.hh>
+#include <story/choice.hh>
+
+namespace libzork::story
+{
+ class NodeImpl : public Node
+ {
+ public:
+ NodeImpl(const std::string& name, const std::string& text);
+ ~NodeImpl() override = default;
+
+ const std::string& get_name() const override;
+
+ const std::string& get_text() const override;
+
+ const Node* get_choice(std::size_t index,
+ bool check_conditions = true) const override;
+
+ std::vector<std::string>
+ list_choices(bool check_conditions = true) const override;
+
+ void add_choice(
+ const Node* other, const std::string& text,
+ std::vector<std::unique_ptr<vars::Condition>> conditions = {},
+ std::vector<std::unique_ptr<vars::Action>> actions = {}) override;
+
+ private:
+ const std::string name_;
+ const std::string text_;
+ std::vector<Choice> choices_;
+ };
+
+ const NodeImpl& to_impl(const Node& node);
+
+ NodeImpl& to_impl(Node& node);
+} // namespace libzork::story
diff --git a/rushs/libzork/libzork/src/story/story.cc b/rushs/libzork/libzork/src/story/story.cc
new file mode 100644
index 0000000..4b26eff
--- /dev/null
+++ b/rushs/libzork/libzork/src/story/story.cc
@@ -0,0 +1,15 @@
+#include <libzork/story/story.hh>
+#include <store/store_impl.hh>
+
+#include "exceptions.hh"
+#include "story/story_impl.hh"
+
+namespace libzork::story
+{
+
+ std::unique_ptr<Story> make_story(const fs::path& path)
+ {
+ return std::make_unique<StoryImpl>(path);
+ }
+
+} // namespace libzork::story
diff --git a/rushs/libzork/libzork/src/story/story_impl.cc b/rushs/libzork/libzork/src/story/story_impl.cc
new file mode 100644
index 0000000..ad39d09
--- /dev/null
+++ b/rushs/libzork/libzork/src/story/story_impl.cc
@@ -0,0 +1,118 @@
+#include "story/story_impl.hh"
+
+#include "exceptions.hh"
+#include "node_impl.hh"
+
+namespace libzork::story
+{
+
+ StoryImpl::StoryImpl(const fs::path& path)
+ {
+ YAML::Node config = YAML::LoadFile(path);
+ title_ = config["title"].as<std::string>();
+ auto dir = config["scripts-path"].as<std::string>();
+ auto story = config["story"];
+ for (auto script : story)
+ {
+ auto name = script["name"].as<std::string>();
+ auto script_path = script["script"].as<std::string>();
+ nodes_.push_back(
+ make_node(name, path.parent_path() / dir / script_path));
+ }
+ size_t i = 0;
+ for (auto script : story)
+ {
+ for (auto choice : script["choices"])
+ {
+ auto text = choice["text"].as<std::string>();
+ auto matches = std::ranges::find_if(
+ nodes_.begin(), nodes_.end(),
+ [choice](const std::unique_ptr<Node>& c) -> bool {
+ return c->get_name()
+ == choice["target"].as<std::string>();
+ });
+ nodes_.at(i)->add_choice(matches->get(), text);
+ }
+ i++;
+ }
+ if (nodes_.empty())
+ store_ = nullptr;
+ else
+ {
+ store_ = store::make_store();
+ store_->set_active_node(nodes_.at(0).get());
+ }
+ }
+ const std::string& StoryImpl::get_title() const
+ {
+ return title_;
+ }
+
+ const Node* StoryImpl::get_current() const
+ {
+ if (!store_)
+ return nullptr;
+ return store_->get_active_node();
+ }
+
+ void StoryImpl::set_current(const Node* node)
+ {
+ store_->set_active_node(node);
+ }
+
+ const store::Store* StoryImpl::get_store() const
+ {
+ return store_.get();
+ }
+
+ std::ostream& StoryImpl::display(std::ostream& os) const
+ {
+ os << "digraph story {\n";
+ for (auto node = nodes_.begin(); node != nodes_.end(); node++)
+ {
+ auto choices = node->get()->list_choices();
+ if (choices.size() == 0)
+ continue;
+ os << "\t\"" << node->get()->get_name() << "\" -> ";
+ if (choices.size() > 1)
+ {
+ os << "{";
+ os << "\"" << to_impl(*node->get()->get_choice(0)).get_name()
+ << "\"";
+ for (size_t i = 1; i < choices.size(); i++)
+ {
+ os << " " << "\""
+ << to_impl(*node->get()->get_choice(i)).get_name()
+ << "\"";
+ }
+ os << "}";
+ }
+ else
+ {
+ os << "\"" << to_impl(*node->get()->get_choice(0)).get_name()
+ << "\"";
+ }
+ os << ";\n";
+ }
+ os << "}\n";
+ return os;
+ }
+ const StoryImpl& to_impl(const Story& story)
+ {
+ const StoryImpl* cast = dynamic_cast<const StoryImpl*>(&story);
+ if (!cast)
+ throw std::runtime_error{
+ "Invalid conversion from const Node* to const NodeImpl*"
+ };
+ return *cast;
+ }
+ StoryImpl& to_impl(Story& story)
+ {
+ StoryImpl* cast = dynamic_cast<StoryImpl*>(&story);
+ if (!cast)
+ throw std::runtime_error{
+ "Invalid conversion from const Node* to const NodeImpl*"
+ };
+ return *cast;
+ }
+} // namespace libzork::story
diff --git a/rushs/libzork/libzork/src/story/story_impl.hh b/rushs/libzork/libzork/src/story/story_impl.hh
new file mode 100644
index 0000000..6062d2f
--- /dev/null
+++ b/rushs/libzork/libzork/src/story/story_impl.hh
@@ -0,0 +1,31 @@
+#pragma once
+
+#include <libzork/story/story.hh>
+#include <store/store_impl.hh>
+#include <yaml-cpp/yaml.h>
+
+namespace libzork::story
+{
+
+ class StoryImpl : public Story
+ {
+ public:
+ StoryImpl(const fs::path& path);
+ ~StoryImpl() override = default;
+
+ const std::string& get_title() const override;
+ const Node* get_current() const override;
+ void set_current(const Node* node) override;
+ const store::Store* get_store() const override;
+ std::ostream& display(std::ostream& os) const override;
+
+ private:
+ std::string title_;
+ std::vector<std::unique_ptr<Node>> nodes_;
+ std::unique_ptr<store::Store> store_;
+ };
+
+ const StoryImpl& to_impl(const Story& story);
+ StoryImpl& to_impl(Story& story);
+
+} // namespace libzork::story
diff --git a/rushs/libzork/libzork/src/vars/CMakeLists.txt b/rushs/libzork/libzork/src/vars/CMakeLists.txt
new file mode 100644
index 0000000..8e3e5d5
--- /dev/null
+++ b/rushs/libzork/libzork/src/vars/CMakeLists.txt
@@ -0,0 +1,6 @@
+cmake_minimum_required(VERSION 3.21.2)
+
+target_sources(libzork PRIVATE action.cc action_impl.cc condition.cc condition_impl.cc)
+set_target_properties(libzork PROPERTIES
+ CXX_STANDARD 20
+ CXX_EXTENSIONS OFF) \ No newline at end of file
diff --git a/rushs/libzork/libzork/src/vars/action.cc b/rushs/libzork/libzork/src/vars/action.cc
new file mode 100644
index 0000000..83d8c8e
--- /dev/null
+++ b/rushs/libzork/libzork/src/vars/action.cc
@@ -0,0 +1,20 @@
+#include <libzork/vars/action.hh>
+
+#include "exceptions.hh"
+#include "vars/action_impl.hh"
+
+namespace libzork::vars
+{
+
+ std::unique_ptr<Action> make_action(store::Store& store,
+ const std::string& variable,
+ const std::string& action, int value)
+ {
+ (void)store;
+ (void)variable;
+ (void)action;
+ (void)value;
+ throw NotImplemented();
+ }
+
+} // namespace libzork::vars
diff --git a/rushs/libzork/libzork/src/vars/action_impl.cc b/rushs/libzork/libzork/src/vars/action_impl.cc
new file mode 100644
index 0000000..d0abcf7
--- /dev/null
+++ b/rushs/libzork/libzork/src/vars/action_impl.cc
@@ -0,0 +1,13 @@
+#include "vars/action_impl.hh"
+
+#include "exceptions.hh"
+
+namespace libzork::vars
+{
+
+ void ActionImpl::apply() const
+ {
+ throw NotImplemented();
+ }
+
+} // namespace libzork::vars
diff --git a/rushs/libzork/libzork/src/vars/action_impl.hh b/rushs/libzork/libzork/src/vars/action_impl.hh
new file mode 100644
index 0000000..bc7f933
--- /dev/null
+++ b/rushs/libzork/libzork/src/vars/action_impl.hh
@@ -0,0 +1,16 @@
+#pragma once
+
+#include <libzork/vars/action.hh>
+
+namespace libzork::vars
+{
+
+ class ActionImpl : public Action
+ {
+ public:
+ ~ActionImpl() override = default;
+
+ void apply() const override;
+ };
+
+} // namespace libzork::vars
diff --git a/rushs/libzork/libzork/src/vars/condition.cc b/rushs/libzork/libzork/src/vars/condition.cc
new file mode 100644
index 0000000..d0fb648
--- /dev/null
+++ b/rushs/libzork/libzork/src/vars/condition.cc
@@ -0,0 +1,21 @@
+#include <libzork/store/store.hh>
+#include <libzork/vars/condition.hh>
+
+#include "exceptions.hh"
+
+namespace libzork::vars
+{
+
+ std::unique_ptr<Condition> make_condition(const store::Store& store,
+ const std::string& variable,
+ const std::string& comparison,
+ int value)
+ {
+ (void)store;
+ (void)variable;
+ (void)comparison;
+ (void)value;
+ throw NotImplemented();
+ }
+
+} // namespace libzork::vars
diff --git a/rushs/libzork/libzork/src/vars/condition_impl.cc b/rushs/libzork/libzork/src/vars/condition_impl.cc
new file mode 100644
index 0000000..7d11fdc
--- /dev/null
+++ b/rushs/libzork/libzork/src/vars/condition_impl.cc
@@ -0,0 +1,16 @@
+#include "vars/condition_impl.hh"
+
+#include <algorithm>
+#include <map>
+
+#include "exceptions.hh"
+
+namespace libzork::vars
+{
+
+ bool ConditionImpl::apply() const
+ {
+ throw NotImplemented();
+ }
+
+} // namespace libzork::vars
diff --git a/rushs/libzork/libzork/src/vars/condition_impl.hh b/rushs/libzork/libzork/src/vars/condition_impl.hh
new file mode 100644
index 0000000..c8b300c
--- /dev/null
+++ b/rushs/libzork/libzork/src/vars/condition_impl.hh
@@ -0,0 +1,16 @@
+#pragma once
+
+#include <libzork/vars/condition.hh>
+
+namespace libzork::vars
+{
+
+ class ConditionImpl : public Condition
+ {
+ public:
+ ~ConditionImpl() override = default;
+
+ bool apply() const override;
+ };
+
+} // namespace libzork::vars
diff --git a/rushs/libzork/libzork/tests/scripts/little_quest/castle.txt b/rushs/libzork/libzork/tests/scripts/little_quest/castle.txt
new file mode 100644
index 0000000..23bef37
--- /dev/null
+++ b/rushs/libzork/libzork/tests/scripts/little_quest/castle.txt
@@ -0,0 +1,3 @@
+You enter the castle.
+A large dragon blocks your path, preventing you from proceeding further.
+A sword is on your left.
diff --git a/rushs/libzork/libzork/tests/scripts/little_quest/castle_weapon.txt b/rushs/libzork/libzork/tests/scripts/little_quest/castle_weapon.txt
new file mode 100644
index 0000000..7e1d77f
--- /dev/null
+++ b/rushs/libzork/libzork/tests/scripts/little_quest/castle_weapon.txt
@@ -0,0 +1,3 @@
+You enter the castle.
+A large dragon blocks your path, preventing you from proceeding further.
+To your right, there is a forge. Perhaps there are weapons there ?
diff --git a/rushs/libzork/libzork/tests/scripts/little_quest/forest.txt b/rushs/libzork/libzork/tests/scripts/little_quest/forest.txt
new file mode 100644
index 0000000..e37ad98
--- /dev/null
+++ b/rushs/libzork/libzork/tests/scripts/little_quest/forest.txt
@@ -0,0 +1,4 @@
+You find yourself in a vast, lush forest.
+In the distance, you spot a prince perched atop a tower of a castle.
+He appears to be in desperate need of assistance.
+To your right lies a house.
diff --git a/rushs/libzork/libzork/tests/scripts/little_quest/house.txt b/rushs/libzork/libzork/tests/scripts/little_quest/house.txt
new file mode 100644
index 0000000..c285e6a
--- /dev/null
+++ b/rushs/libzork/libzork/tests/scripts/little_quest/house.txt
@@ -0,0 +1,2 @@
+There is a bed, worn out from fatigue, you collapse onto it and take a nap.
+The end.
diff --git a/rushs/libzork/libzork/tests/scripts/little_quest/tower.txt b/rushs/libzork/libzork/tests/scripts/little_quest/tower.txt
new file mode 100644
index 0000000..2e61000
--- /dev/null
+++ b/rushs/libzork/libzork/tests/scripts/little_quest/tower.txt
@@ -0,0 +1,2 @@
+You slay the dragon, climb the tower, and find the prince safe and sound.
+The end.
diff --git a/rushs/libzork/libzork/tests/scripts/short_static/cave.txt b/rushs/libzork/libzork/tests/scripts/short_static/cave.txt
new file mode 100644
index 0000000..f77f4bf
--- /dev/null
+++ b/rushs/libzork/libzork/tests/scripts/short_static/cave.txt
@@ -0,0 +1 @@
+This is a dark cave
diff --git a/rushs/libzork/libzork/tests/scripts/short_static/forest.txt b/rushs/libzork/libzork/tests/scripts/short_static/forest.txt
new file mode 100644
index 0000000..ac917ab
--- /dev/null
+++ b/rushs/libzork/libzork/tests/scripts/short_static/forest.txt
@@ -0,0 +1 @@
+This is a large forest
diff --git a/rushs/libzork/libzork/tests/scripts/short_static/welcome.txt b/rushs/libzork/libzork/tests/scripts/short_static/welcome.txt
new file mode 100644
index 0000000..af5626b
--- /dev/null
+++ b/rushs/libzork/libzork/tests/scripts/short_static/welcome.txt
@@ -0,0 +1 @@
+Hello, world!
diff --git a/rushs/libzork/libzork/tests/stories/dynamic/story.yml b/rushs/libzork/libzork/tests/stories/dynamic/story.yml
new file mode 100644
index 0000000..7d75431
--- /dev/null
+++ b/rushs/libzork/libzork/tests/stories/dynamic/story.yml
@@ -0,0 +1,51 @@
+title: A dynamic story
+scripts-path: ../../scripts/little_quest
+variables:
+ - name: health
+ value: 10
+ - name: sword_taken
+ value: 0
+story:
+ - name: forest
+ script: forest.txt
+ choices:
+ - text: Enter the house
+ target: house
+ - text: Enter the castle
+ target: castle
+ - text: Eat a fruit
+ target: forest
+ actions:
+ - name: health
+ operation: add
+ value: 10
+ - name: house
+ script: house.txt
+ choices: []
+ - name: castle
+ script: castle_weapon.txt
+ choices:
+ - text: Flee
+ target: forest
+ - text: Take the sword
+ target: castle
+ conditions:
+ - name: sword_taken
+ comparison: equal
+ value: 0
+ actions:
+ - name: sword_taken
+ operation: add
+ value: 1
+ - text: Kill the dragon
+ target: tower
+ conditions:
+ - name: sword_taken
+ comparison: equal
+ value: 1
+ - name: health
+ comparison: greater
+ value: 10
+ - name: tower
+ script: tower.txt
+ choices: []
diff --git a/rushs/libzork/libzork/tests/stories/long_static/story.yml b/rushs/libzork/libzork/tests/stories/long_static/story.yml
new file mode 100644
index 0000000..152fad8
--- /dev/null
+++ b/rushs/libzork/libzork/tests/stories/long_static/story.yml
@@ -0,0 +1,25 @@
+title: A long static story
+scripts-path: ../../scripts/little_quest
+story:
+ - name: forest
+ script: forest.txt
+ choices:
+ - text: Enter the house
+ target: house
+ - text: Enter the castle
+ target: castle
+ - text: Eat a fruit
+ target: forest
+ - name: house
+ script: house.txt
+ choices: []
+ - name: castle
+ script: castle.txt
+ choices:
+ - text: Flee
+ target: forest
+ - text: Kill the dragon
+ target: tower
+ - name: tower
+ script: tower.txt
+ choices: []
diff --git a/rushs/libzork/libzork/tests/stories/short_static/story.yml b/rushs/libzork/libzork/tests/stories/short_static/story.yml
new file mode 100644
index 0000000..701a954
--- /dev/null
+++ b/rushs/libzork/libzork/tests/stories/short_static/story.yml
@@ -0,0 +1,16 @@
+title: A short static story
+scripts-path: ../../scripts/short_static
+story:
+ - name: welcome
+ script: welcome.txt
+ choices:
+ - text: Explore the cave
+ target: cave
+ - text: Go in the forest
+ target: forest
+ - name: cave
+ script: cave.txt
+ choices: []
+ - name: forest
+ script: forest.txt
+ choices: []
diff --git a/rushs/libzork/libzork/zorkxplorer/CMakeLists.txt b/rushs/libzork/libzork/zorkxplorer/CMakeLists.txt
new file mode 100644
index 0000000..9633f06
--- /dev/null
+++ b/rushs/libzork/libzork/zorkxplorer/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.21.2)
+project(Zork)
+add_subdirectory(src) \ No newline at end of file
diff --git a/rushs/libzork/libzork/zorkxplorer/src/CMakeLists.txt b/rushs/libzork/libzork/zorkxplorer/src/CMakeLists.txt
new file mode 100644
index 0000000..88a75d1
--- /dev/null
+++ b/rushs/libzork/libzork/zorkxplorer/src/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.21.2)
+project(Zork)
+target_sources(zork_test PUBLIC main.cc options.cc) \ No newline at end of file
diff --git a/rushs/libzork/libzork/zorkxplorer/src/hello.txt b/rushs/libzork/libzork/zorkxplorer/src/hello.txt
new file mode 100644
index 0000000..05a682b
--- /dev/null
+++ b/rushs/libzork/libzork/zorkxplorer/src/hello.txt
@@ -0,0 +1 @@
+Hello! \ No newline at end of file
diff --git a/rushs/libzork/libzork/zorkxplorer/src/main.cc b/rushs/libzork/libzork/zorkxplorer/src/main.cc
new file mode 100644
index 0000000..2494d62
--- /dev/null
+++ b/rushs/libzork/libzork/zorkxplorer/src/main.cc
@@ -0,0 +1,63 @@
+#include <fstream>
+#include <iostream>
+#include <libzork/exceptions.hh>
+#include <libzork/runner/choice.hh>
+#include <libzork/runner/html.hh>
+#include <libzork/runner/smart.hh>
+
+#include "options.hh"
+
+std::unique_ptr<libzork::story::Story> get_story(const Config& config)
+{
+ return libzork::story::make_story(config.story_path);
+}
+
+std::unique_ptr<libzork::runner::Runner>
+get_runner(const Config& config, std::unique_ptr<libzork::story::Story> story)
+{
+ switch (config.story_type)
+ {
+ case StoryType::Choice:
+ return libzork::runner::make_choice_runner(std::move(story));
+ case StoryType::Smart:
+ return libzork::runner::make_smart_runner(std::move(story),
+ config.story_arg);
+ case StoryType::HTML:
+ return libzork::runner::make_html_runner(std::move(story),
+ config.story_arg);
+ default:
+ return nullptr;
+ }
+}
+
+int main(int argc, char** argv)
+{
+ Config config;
+ try
+ {
+ config = parse_options(argc, argv);
+ }
+ catch (const std::invalid_argument& exc)
+ {
+ std::cerr << "invalid options: " << exc.what() << "\n";
+ return 1;
+ }
+
+ auto story = get_story(config);
+ auto output = std::ofstream(
+ "/home/martial.simon/afs/ing/zork/libzork/tests/output/dot.out");
+ story->display(output);
+
+ std::unique_ptr<libzork::runner::Runner> runner =
+ libzork::runner::make_choice_runner(std::move(story), std::cin,
+ std::cout);
+
+ try
+ {
+ runner->run();
+ }
+ catch (const libzork::RunnerQuit&)
+ {}
+
+ return 0;
+}
diff --git a/rushs/libzork/libzork/zorkxplorer/src/options.cc b/rushs/libzork/libzork/zorkxplorer/src/options.cc
new file mode 100644
index 0000000..e97a7ea
--- /dev/null
+++ b/rushs/libzork/libzork/zorkxplorer/src/options.cc
@@ -0,0 +1,57 @@
+#include "options.hh"
+
+#include <getopt.h>
+#include <iostream>
+
+namespace
+{
+ constexpr option options[] = {
+ { "story", required_argument, nullptr, 's' },
+ { "smart", required_argument, nullptr, 'm' },
+ { "html", required_argument, nullptr, 'h' },
+ };
+
+ std::string usage(const std::string& name)
+ {
+ return "usage: " + name
+ + " (--story <story.yml>)"
+ " [--smart <synonyms.yml> | --html <directory/>]";
+ };
+} // namespace
+
+Config parse_options(int argc, char** argv)
+{
+ Config config;
+ int opt;
+ while ((opt = getopt_long(argc, argv, "s:m:h:t:u:o:n:r:", options, nullptr))
+ != -1)
+ {
+ switch (opt)
+ {
+ case 's': // --story
+ config.story_path = optarg;
+ break;
+ case 'm': // --smart
+ if (config.story_type == StoryType::HTML)
+ throw std::invalid_argument(
+ "incompatble options: `--smart` and `--html`");
+ config.story_type = StoryType::Smart;
+ config.story_arg = optarg;
+ break;
+ case 'h': // --html
+ if (config.story_type == StoryType::Smart)
+ throw std::invalid_argument(
+ "incompatible options: `--smart` and `--html`");
+ config.story_type = StoryType::HTML;
+ config.story_arg = optarg;
+ break;
+ default:
+ throw std::invalid_argument(usage(argv[0]));
+ }
+ };
+
+ if (config.story_path.empty())
+ throw std::invalid_argument("option '--story' is mandatory");
+
+ return config;
+}
diff --git a/rushs/libzork/libzork/zorkxplorer/src/options.hh b/rushs/libzork/libzork/zorkxplorer/src/options.hh
new file mode 100644
index 0000000..d3f919d
--- /dev/null
+++ b/rushs/libzork/libzork/zorkxplorer/src/options.hh
@@ -0,0 +1,22 @@
+#pragma once
+
+#include <filesystem>
+#include <optional>
+
+namespace fs = std::filesystem;
+
+enum class StoryType
+{
+ Choice,
+ Smart,
+ HTML,
+};
+
+struct Config
+{
+ std::filesystem::path story_path;
+ StoryType story_type = StoryType::Choice;
+ fs::path story_arg; /** Undefined if story_type is StoryType::BASIC */
+};
+
+Config parse_options(int argc, char** argv);
diff --git a/rushs/libzork/libzork/zorkxplorer/src/world.txt b/rushs/libzork/libzork/zorkxplorer/src/world.txt
new file mode 100644
index 0000000..5dd01c1
--- /dev/null
+++ b/rushs/libzork/libzork/zorkxplorer/src/world.txt
@@ -0,0 +1 @@
+Hello, world! \ No newline at end of file