diff --git a/.gitmodules b/.gitmodules
index 70a5151..fb678ab 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,3 +1,6 @@
[submodule "lib/blt-with-graphics"]
path = lib/blt-with-graphics
url = https://git.tpgc.me/tri11paragon/BLT-With-Graphics-Template
+[submodule "tools/skyscraper_parser"]
+ path = tools/skyscraper_parser
+ url = https://github.com/Tri11Paragon/skyscraper_parser
diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..13566b8
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,8 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Editor-based HTTP Client requests
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..0b76fe5
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..ecadcfb
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/skyscrapers-ga.iml b/.idea/skyscrapers-ga.iml
new file mode 100644
index 0000000..f08604b
--- /dev/null
+++ b/.idea/skyscrapers-ga.iml
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..3739d1a
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 563278b..1828e9a 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -49,7 +49,7 @@ macro(blt_add_project name source type)
project(skyscrapers-ga)
endmacro()
-project(skyscrapers-ga VERSION 0.0.2)
+project(skyscrapers-ga VERSION 0.0.3)
option(ENABLE_ADDRSAN "Enable the address sanitizer" OFF)
option(ENABLE_UBSAN "Enable the ub sanitizer" OFF)
diff --git a/default.nix b/default.nix
new file mode 100644
index 0000000..5895532
--- /dev/null
+++ b/default.nix
@@ -0,0 +1,66 @@
+{ pkgs ? (import {
+ config.allowUnfree = true;
+ config.segger-jlink.acceptLicense = true;
+}), customPkgs ? (import /home/brett/my-nixpkgs {
+ config.allowUnfree = true;
+ config.segger-jlink.acceptLicense = true;
+}), ... }:
+pkgs.mkShell
+{
+ nativeBuildInputs = with pkgs; [
+ playwright-driver.browsers
+ ];
+ buildInputs = with pkgs; [
+ cmake
+ gcc
+ clang
+ emscripten
+ ninja
+ customPkgs.jetbrains.clion
+ #clion = import ~/my-nixpkgs/pkgs/applications/editors/jetbrains {};
+ renderdoc
+ valgrind
+ (python3.withPackages (python-pkgs: [
+ python-pkgs.beautifulsoup4
+ python-pkgs.playwright
+ python-pkgs.requests
+ ]))
+ ];
+ propagatedBuildInputs = with pkgs; [
+ xorg.libX11
+ xorg.libX11.dev
+ xorg.libXcursor
+ xorg.libXcursor.dev
+ xorg.libXext
+ xorg.libXext.dev
+ xorg.libXinerama
+ xorg.libXinerama.dev
+ xorg.libXrandr
+ xorg.libXrandr.dev
+ xorg.libXrender
+ xorg.libXrender.dev
+ xorg.libxcb
+ xorg.libxcb.dev
+ xorg.libXi
+ xorg.libXi.dev
+ harfbuzz
+ harfbuzz.dev
+ zlib
+ zlib.dev
+ bzip2
+ bzip2.dev
+ pngpp
+ brotli
+ brotli.dev
+ pulseaudio.dev
+ git
+ libGL
+ libGL.dev
+ glfw
+ ];
+ LD_LIBRARY_PATH="/run/opengl-driver/lib:/run/opengl-driver-32/lib";
+ shellHook = ''
+ export PLAYWRIGHT_BROWSERS_PATH=${pkgs.playwright-driver.browsers}
+ export PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS=true
+ '';
+}
diff --git a/include/skyscrapers.h b/include/skyscrapers.h
new file mode 100644
index 0000000..a81fd03
--- /dev/null
+++ b/include/skyscrapers.h
@@ -0,0 +1,66 @@
+#pragma once
+/*
+ * Copyright (C) 2024 Brett Terpstra
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#ifndef SKYSCRAPERS_H
+#define SKYSCRAPERS_H
+
+#include
+#include
+#include
+#include
+#include
+
+namespace sky
+{
+ struct problem_t
+ {
+ enum class error_t
+ {
+ MISSING_BOARD_SIZE,
+ MISSING_BOARD_DATA,
+ INCORRECT_BOARD_DATA_FOR_SIZE
+ };
+
+ blt::i32 board_size;
+ std::vector top, bottom, left, right;
+
+ explicit problem_t(const blt::i32 board_size): board_size(board_size)
+ {
+ top.reserve(board_size);
+ bottom.reserve(board_size);
+ left.reserve(board_size);
+ right.reserve(board_size);
+ }
+
+ void print();
+
+ [[nodiscard]] blt::i32 min() const // NOLINT
+ {
+ return 1;
+ }
+
+ [[nodiscard]] blt::i32 max() const
+ {
+ return board_size + 1;
+ }
+ };
+
+ blt::expected problem_from_file(std::string_view path);
+}
+
+#endif //SKYSCRAPERS_H
diff --git a/rules.txt b/rules.txt
new file mode 100644
index 0000000..e4f0fa6
--- /dev/null
+++ b/rules.txt
@@ -0,0 +1,5 @@
+Each of the boxes contains a skyscraper.
+Put numbers 1 to 4 into the boxes which give the height of the building. The higher the number, the taller the skyscraper.
+Each row and each column contains each number exactly once.
+The number in an arrow shows you how many skyscrapers can be seen when looking in the direction of the arrow.
+You cannot see a shorter skyscraper behind a taller one.
\ No newline at end of file
diff --git a/skyscraper_problem.txt b/skyscraper_problem.txt
new file mode 100644
index 0000000..64f3abf
--- /dev/null
+++ b/skyscraper_problem.txt
@@ -0,0 +1,10 @@
+BOARD_SIZE: 6
+
+1 4 2 3 3 3
+1 3
+2 3
+4 2
+3 3
+2 4
+2 1
+2 2 3 3 4 1
diff --git a/src/main.cpp b/src/main.cpp
index 6f2b004..aabf5d1 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1,6 +1,71 @@
-#include
+#include
+#include "blt/gfx/renderer/resource_manager.h"
+#include "blt/gfx/renderer/batch_2d_renderer.h"
+#include "blt/gfx/renderer/camera.h"
+#include
+#include
+#include
-int main()
+blt::gfx::matrix_state_manager global_matrices;
+blt::gfx::resource_manager resources;
+blt::gfx::batch_renderer_2d renderer_2d(resources, global_matrices);
+blt::gfx::first_person_camera camera;
+
+void init(const blt::gfx::window_data&)
{
- std::cout << "Hello World!" << std::endl;
+ using namespace blt::gfx;
+
+
+ global_matrices.create_internals();
+ resources.load_resources();
+ renderer_2d.create();
}
+
+void update(const blt::gfx::window_data& data)
+{
+ global_matrices.update_perspectives(data.width, data.height, 90, 0.1, 2000);
+
+ camera.update();
+ camera.update_view(global_matrices);
+ global_matrices.update();
+
+ renderer_2d.render(data.width, data.height);
+}
+
+void destroy(const blt::gfx::window_data&)
+{
+ global_matrices.cleanup();
+ resources.cleanup();
+ renderer_2d.cleanup();
+ blt::gfx::cleanup();
+}
+
+int main(int argc, const char** argv)
+{
+ blt::arg_parse parser;
+
+ parser.addArgument(blt::arg_builder("file").build());
+
+ auto args = parser.parse_args(argc, argv);
+
+ if (!args.contains("file"))
+ {
+ BLT_WARN("Please provide a skyscraper formatted file!");
+ return EXIT_FAILURE;
+ }
+
+ const auto file = args.get("file");
+
+ auto problem = sky::problem_from_file(file);
+
+ if (!problem)
+ {
+ BLT_WARN("Unable to parse skyscraper file!");
+ return EXIT_FAILURE;
+ }
+
+ auto& problem_d = problem.value();
+ problem_d.print();
+
+ blt::gfx::init(blt::gfx::window_data{"My Sexy Window", init, update, destroy}.setSyncInterval(1));
+}
\ No newline at end of file
diff --git a/src/skyscrapers.h.cpp b/src/skyscrapers.h.cpp
new file mode 100644
index 0000000..2262eb0
--- /dev/null
+++ b/src/skyscrapers.h.cpp
@@ -0,0 +1,110 @@
+/*
+ *
+ * Copyright (C) 2025 Brett Terpstra
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+#include
+
+#include
+#include
+
+namespace sky
+{
+ void problem_t::print()
+ {
+ BLT_TRACE("Board Size: %d", board_size);
+ BLT_TRACE_STREAM << "\t";
+ for (int i = 0; i < board_size; i++)
+ BLT_TRACE_STREAM << top[i] << '\t';
+ BLT_TRACE_STREAM << "\n";
+ for (int i = 0; i < board_size; i++)
+ {
+ BLT_TRACE_STREAM << left[i];
+ for (int j = 0; j < board_size + 1; j++)
+ BLT_TRACE_STREAM << '\t';
+ BLT_TRACE_STREAM << right[i] << "\n";
+ }
+ BLT_TRACE_STREAM << "\t";
+ for (int i = 0; i < board_size; i++)
+ BLT_TRACE_STREAM << bottom[i] << '\t';
+ BLT_TRACE_STREAM << "\n";
+ }
+
+ blt::expected problem_from_file(const std::string_view path)
+ {
+ const auto lines = blt::fs::getLinesFromFile(path);
+
+ const auto size_line = blt::string::split(lines.front(), '\t');
+
+ if (size_line.size() != 2)
+ {
+ BLT_WARN("File is incorrectly formatted. First line is expected to describe board size like 'BOARD_SIZE: #`");
+ return blt::unexpected(problem_t::error_t::MISSING_BOARD_SIZE);
+ }
+
+ problem_t problem{std::stoi(size_line[1])};
+
+ if (lines.size() != static_cast(problem.board_size) + 3)
+ {
+ BLT_TRACE(lines.size());
+ BLT_TRACE(problem.board_size + 1);
+ BLT_WARN("File is incorrectly formatted. Expected problem to be defined as a series of lines, describing the structure of the board");
+ return blt::unexpected(problem_t::error_t::MISSING_BOARD_DATA);
+ }
+
+ auto top_problems = blt::string::split(lines[1], '\t');
+
+ if (top_problems.size() != static_cast(problem.board_size))
+ {
+ BLT_WARN("File is incorrectly formatted. Expected BOARD_SIZE '%d' number of elements got %lu", problem.board_size, top_problems.size());
+ return blt::unexpected(problem_t::error_t::INCORRECT_BOARD_DATA_FOR_SIZE);
+ }
+
+ for (const auto& arrow : top_problems)
+ problem.top.push_back(std::stoi(arrow));
+
+ for (blt::size_t i = 0; i < static_cast(problem.board_size); i++)
+ {
+ const auto index = i + 2;
+ if (index >= lines.size())
+ {
+ BLT_WARN("File is incorrectly formatted. Expected BOARD_SIZE '%d' number of rows describing the sizes of the board but got %lu",
+ problem.board_size, lines.size());
+ return blt::unexpected(problem_t::error_t::INCORRECT_BOARD_DATA_FOR_SIZE);
+ }
+ auto data = blt::string::split(lines[index], '\t');
+ if (data.size() != 2)
+ {
+ BLT_WARN("File is incorrectly formatted. Expected 2 points for the side data descriptors, got %lu", data.size());
+ return blt::unexpected(problem_t::error_t::INCORRECT_BOARD_DATA_FOR_SIZE);
+ }
+ problem.left.push_back(std::stoi(data[0]));
+ problem.right.push_back(std::stoi(data[1]));
+ }
+
+ auto bottom_problems = blt::string::split(lines[8], '\t');
+
+ if (bottom_problems.size() != static_cast(problem.board_size))
+ {
+ BLT_WARN("File is incorrectly formatted. Expected BOARD_SIZE '%d' number of elements got %lu", problem.board_size, top_problems.size());
+ return blt::unexpected(problem_t::error_t::INCORRECT_BOARD_DATA_FOR_SIZE);
+ }
+
+ for (const auto& arrow : bottom_problems)
+ problem.bottom.push_back(std::stoi(arrow));
+
+ return problem;
+ }
+}
diff --git a/tools/skyscraper_parser b/tools/skyscraper_parser
new file mode 160000
index 0000000..529553b
--- /dev/null
+++ b/tools/skyscraper_parser
@@ -0,0 +1 @@
+Subproject commit 529553b9a4f432c7f9e742c80308c6edd369c07e