diff --git a/Makefile b/Makefile index e60560d..78e859c 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ # Compiler and flags CXX = g++ -CXXFLAGS = -std=c++17 -Wall -Wextra -Os -fno-exceptions -fno-asynchronous-unwind-tables -fno-unwind-tables -LDFLAGS = -lncurses -ltinfo -Wl,--gc-sections -s +CXXFLAGS = -std=c++17 -Wall -Wextra -O3 +LDFLAGS = -lncurses -ltinfo # Directories SRC_DIR = src diff --git a/src/Castle.h b/src/Castle.h index 6186ead..45042fa 100644 --- a/src/Castle.h +++ b/src/Castle.h @@ -14,7 +14,6 @@ public: const std::vector &getMask() const override { return mask; } char getDefaultColor() const noexcept override { return 'K'; } - bool shouldBeRemoved() const noexcept override { return false; } std::unique_ptr createReplacement() const override { return nullptr; } int getPreferredLayer() const noexcept override { return 0; } }; diff --git a/src/Entity.cpp b/src/Entity.cpp index 1237940..389588f 100644 --- a/src/Entity.cpp +++ b/src/Entity.cpp @@ -1,6 +1,5 @@ #include "Entity.h" #include "Aquarium.h" -#include void Entity::draw() const { auto &aquarium = Aquarium::getInstance(); @@ -57,25 +56,11 @@ void Entity::draw() const { } } -size_t Entity::getMaxRowWidth(const std::vector &image) noexcept { - if (image.empty()) { - return 0; - } - - size_t max_width = 0; - for (const auto &row : image) { - max_width = std::max(max_width, row.length()); - } - - return max_width; -} - bool Entity::shouldBeRemoved() const noexcept { const auto &aquarium = Aquarium::getInstance(); - const auto ¤t_image = getImage(); - const float entity_width = static_cast(getMaxRowWidth(current_image)); - - // Default implementation: remove if completely off-screen - return (x + entity_width < 0) || - (x > static_cast(aquarium.getWidth())); + if (moving_right) { + return x > static_cast(aquarium.getWidth()); + } else { + return (x + static_cast(getWidth())) < 0; + } } diff --git a/src/Entity.h b/src/Entity.h index 8e8fe1b..0e18c0a 100644 --- a/src/Entity.h +++ b/src/Entity.h @@ -10,33 +10,33 @@ struct AssetPair { class Entity { protected: + const bool moving_right; float x; float y; static inline size_t next_id = 0; const size_t entity_id; + virtual const std::vector &getImage() const = 0; + virtual const std::vector &getMask() const = 0; + virtual char getDefaultColor() const noexcept = 0; public: - Entity() : x(0.0f), y(0.0f), entity_id(++next_id) {} + Entity() : moving_right(false), x(0.0f), y(0.0f), entity_id(++next_id) {} + Entity(bool moving_right) + : moving_right(moving_right), x(0.0f), y(0.0f), entity_id(++next_id) {} Entity(float init_x, float init_y) - : x(init_x), y(init_y), entity_id(++next_id) {} + : moving_right(false), x(init_x), y(init_y), entity_id(++next_id) {} virtual ~Entity() = default; float getX() const noexcept { return x; } float getY() const noexcept { return y; } + virtual size_t getWidth() const noexcept { return getImage()[0].length(); } size_t getId() const noexcept { return entity_id; } virtual void update() noexcept = 0; - virtual const std::vector &getImage() const = 0; - virtual const std::vector &getMask() const = 0; - virtual char getDefaultColor() const noexcept = 0; virtual bool shouldBeRemoved() const noexcept; virtual std::unique_ptr createReplacement() const { return nullptr; } virtual int getPreferredLayer() const noexcept = 0; void draw() const; - -protected: - // Helper function to get the maximum width of any row in an image - static size_t getMaxRowWidth(const std::vector &image) noexcept; }; diff --git a/src/Fish.cpp b/src/Fish.cpp index 019eaac..53bc13a 100644 --- a/src/Fish.cpp +++ b/src/Fish.cpp @@ -9,10 +9,9 @@ std::unordered_map Fish::color_map; Fish::Fish() : Fish(getRandomAssetIndex()) {} Fish::Fish(int asset_index) - : Entity(), image(fishAssetPairs[asset_index].image), + : Entity(asset_index % 2 == 0), image(fishAssetPairs[asset_index].image), mask(fishAssetPairs[asset_index].mask), - speed(Random::floatInRange(0.25f, 2.25f)), - moving_right(asset_index % 2 == 0) { + speed(Random::floatInRange(0.25f, 2.25f)) { const auto &aquarium = Aquarium::getInstance(); y = Random::intInRange(static_cast(image.size()) + 6, @@ -50,15 +49,6 @@ int Fish::getRandomAssetIndex() { void Fish::update() noexcept { x += moving_right ? speed : -speed; } -bool Fish::shouldBeRemoved() const noexcept { - const auto &aquarium = Aquarium::getInstance(); - if (moving_right) { - return x > static_cast(aquarium.getWidth()); - } else { - return (x + static_cast(image[0].length())) < 0; - } -} - std::unique_ptr Fish::createReplacement() const { return std::make_unique(); } diff --git a/src/Fish.h b/src/Fish.h index e6bff4a..9addd0e 100644 --- a/src/Fish.h +++ b/src/Fish.h @@ -12,7 +12,6 @@ private: const std::vector ℑ std::vector mask; const float speed; - const bool moving_right; static std::unordered_map color_map; @@ -28,7 +27,6 @@ public: const std::vector &getMask() const override { return mask; } char getDefaultColor() const noexcept override { return 'k'; } - bool shouldBeRemoved() const noexcept override; std::unique_ptr createReplacement() const override; int getPreferredLayer() const noexcept override; diff --git a/src/SeaMonster.cpp b/src/SeaMonster.cpp index a016168..eb3f9ad 100644 --- a/src/SeaMonster.cpp +++ b/src/SeaMonster.cpp @@ -6,21 +6,21 @@ SeaMonster::SeaMonster() : SeaMonster(getRandomDirection()) {} SeaMonster::SeaMonster(int asset_index) - : Entity(), frame1(seaMonsterAssets[asset_index].frame1), - frame2(seaMonsterAssets[asset_index].frame2), - mask(seaMonsterAssets[asset_index].mask), speed(SEAMONSTER_SPEED), - moving_right(asset_index == 0) { + : Entity(asset_index == 0), frames(seaMonsterAssets[asset_index].frames), + mask(seaMonsterAssets[asset_index].mask), speed(SEAMONSTER_SPEED) { const auto &aquarium = Aquarium::getInstance(); y = WATER_SURFACE_OFFSET; + // Use first frame for positioning calculations + const auto &first_frame = frames[0]; if (moving_right) { - x = -static_cast(frame1[0].length()); + x = -static_cast(first_frame[0].length()); } else { x = static_cast(aquarium.getWidth()); } - current_image = frame1; + current_image = first_frame; } int SeaMonster::getRandomDirection() { return Random::intInRange(0, 1); } @@ -30,27 +30,14 @@ void SeaMonster::update() noexcept { ++animation_counter; if (animation_counter >= ANIMATION_DELAY) { - current_frame = !current_frame; + current_frame_index = (current_frame_index + 1) % frames.size(); animation_counter = 0; } } const std::vector &SeaMonster::getImage() const { - if (current_frame) { - current_image = frame2; - } else { - current_image = frame1; - } + current_image = frames[current_frame_index]; return current_image; } -bool SeaMonster::shouldBeRemoved() const noexcept { - const auto &aquarium = Aquarium::getInstance(); - if (moving_right) { - return x > static_cast(aquarium.getWidth()); - } else { - return (x + static_cast(frame1[0].length())) < 0; - } -} - int SeaMonster::getPreferredLayer() const noexcept { return 8; } diff --git a/src/SeaMonster.h b/src/SeaMonster.h index 22a22a0..d6b1bcc 100644 --- a/src/SeaMonster.h +++ b/src/SeaMonster.h @@ -7,13 +7,11 @@ private: static constexpr float SEAMONSTER_SPEED = 0.8f; static constexpr int WATER_SURFACE_OFFSET = 2; - const std::vector &frame1; - const std::vector &frame2; + const std::vector> frames; const std::vector &mask; const float speed; - const bool moving_right; - bool current_frame = false; + int current_frame_index = 0; int animation_counter = 0; mutable std::vector current_image; @@ -30,6 +28,5 @@ public: const std::vector &getMask() const override { return mask; } char getDefaultColor() const noexcept override { return 'G'; } - bool shouldBeRemoved() const noexcept override; int getPreferredLayer() const noexcept override; }; diff --git a/src/Ship.cpp b/src/Ship.cpp index f001566..d10d53f 100644 --- a/src/Ship.cpp +++ b/src/Ship.cpp @@ -6,12 +6,11 @@ Ship::Ship() : Ship(getRandomDirection()) {} Ship::Ship(int asset_index) - : Entity(), image(shipAssets[asset_index].image), - mask(shipAssets[asset_index].mask), speed(SHIP_SPEED), - moving_right(asset_index == 0) { + : Entity(asset_index == 0), image(shipAssets[asset_index].image), + mask(shipAssets[asset_index].mask), speed(SHIP_SPEED) { const auto &aquarium = Aquarium::getInstance(); - y = WATER_SURFACE_OFFSET; + y = 0; if (moving_right) { x = -static_cast(image[0].length()); } else { @@ -23,13 +22,4 @@ int Ship::getRandomDirection() { return Random::intInRange(0, 1); } void Ship::update() noexcept { x += moving_right ? speed : -speed; } -bool Ship::shouldBeRemoved() const noexcept { - const auto &aquarium = Aquarium::getInstance(); - if (moving_right) { - return x > static_cast(aquarium.getWidth()); - } else { - return (x + static_cast(image[0].length())) < 0; - } -} - int Ship::getPreferredLayer() const noexcept { return 9; } diff --git a/src/Ship.h b/src/Ship.h index a8bba84..4acfee4 100644 --- a/src/Ship.h +++ b/src/Ship.h @@ -5,12 +5,10 @@ class Ship : public Entity { private: static constexpr float SHIP_SPEED = 1.0f; - static constexpr int WATER_SURFACE_OFFSET = 0; const std::vector ℑ const std::vector &mask; const float speed; - const bool moving_right; explicit Ship(int asset_index); static int getRandomDirection(); @@ -23,6 +21,5 @@ public: const std::vector &getMask() const override { return mask; } char getDefaultColor() const noexcept override { return 'W'; } - bool shouldBeRemoved() const noexcept override; int getPreferredLayer() const noexcept override; }; diff --git a/src/assets/SpriteUtils.h b/src/SpriteUtils.h similarity index 50% rename from src/assets/SpriteUtils.h rename to src/SpriteUtils.h index 6b5c94d..7c43aa0 100644 --- a/src/assets/SpriteUtils.h +++ b/src/SpriteUtils.h @@ -1,3 +1,4 @@ +// SpriteUtils.h - Unified mirroring for all asset types #pragma once #include #include @@ -6,63 +7,75 @@ struct AssetPair; -namespace SpriteUtils { // Character mapping for directional elements const std::unordered_map charFlipMap = { - {'(', ')'}, {')', '('}, {'[', ']'}, {']', '['}, {'{', '}'}, {'}', '{'}, - {'<', '>'}, {'>', '<'}, {'/', '\\'}, {'\\', '/'}, {'`', '\''}, {'\'', '`'}, -}; + {'(', ')'}, {')', '('}, {'[', ']'}, {']', '['}, {'{', '}'}, + {'}', '{'}, {'<', '>'}, {'>', '<'}, {'/', '\\'}, {'\\', '/'}}; -// Mirror a single character (handle directional flipping) inline char mirrorChar(char c) { auto it = charFlipMap.find(c); return (it != charFlipMap.end()) ? it->second : c; } -// Mirror a single row with proper character flipping inline std::string mirrorRow(std::string row) { - // First reverse the string std::reverse(row.begin(), row.end()); - - // Then flip directional characters for (char &c : row) { c = mirrorChar(c); } - return row; } -// Mirror an entire sprite +// Mirror an entire sprite (vector of strings) inline std::vector mirrorSprite(const std::vector &sprite) { std::vector mirrored; mirrored.reserve(sprite.size()); - for (const auto &row : sprite) { mirrored.push_back(mirrorRow(row)); } - return mirrored; } -// Mirror an AssetPair inline AssetPair mirrorAssetPair(const AssetPair &asset) { return {mirrorSprite(asset.image), mirrorSprite(asset.mask)}; } -// Create bidirectional asset pairs from right-facing assets +// Create bidirectional assets from simple AssetPair vector inline std::vector createBidirectionalAssets(const std::vector &rightFacingAssets) { std::vector result; result.reserve(rightFacingAssets.size() * 2); for (const auto &asset : rightFacingAssets) { - // Add right-facing version - result.push_back(asset); - // Add left-facing (mirrored) version - result.push_back(mirrorAssetPair(asset)); + result.push_back(asset); // Right-facing + result.push_back(mirrorAssetPair(asset)); // Left-facing (mirrored) } return result; } -} // namespace SpriteUtils + +// Generic template for any asset type with frames and mask +template +AssetType mirrorFramedAsset(const AssetType &asset) { + AssetType mirrored; + + // Mirror all frames + for (const auto &frame : asset.frames) { + mirrored.frames.push_back(mirrorSprite(frame)); + } + + // Mirror mask + mirrored.mask = mirrorSprite(asset.mask); + + return mirrored; +} + +// Create bidirectional assets from single framed asset +template +std::vector +createBidirectionalFramedAssets(const AssetType &rightFacingAsset) { + return { + rightFacingAsset, // [0] = Right-facing + mirrorFramedAsset(rightFacingAsset) // [1] = Left-facing (mirrored) + }; +} diff --git a/src/Waterline.h b/src/Waterline.h index d0845c3..43d4968 100644 --- a/src/Waterline.h +++ b/src/Waterline.h @@ -24,7 +24,6 @@ public: const std::vector &getMask() const override; char getDefaultColor() const noexcept override { return WATERLINE_COLOR; } - bool shouldBeRemoved() const noexcept override { return false; } std::unique_ptr createReplacement() const override { return nullptr; } int getPreferredLayer() const noexcept override { return 0; } diff --git a/src/Whale.cpp b/src/Whale.cpp index c5f8c32..0ef56eb 100644 --- a/src/Whale.cpp +++ b/src/Whale.cpp @@ -6,9 +6,8 @@ Whale::Whale() : Whale(getRandomDirection()) {} Whale::Whale(int asset_index) - : Entity(), frames(whaleAssets[asset_index].frames), - mask(whaleAssets[asset_index].mask), speed(WHALE_SPEED), - moving_right(asset_index == 0) { + : Entity((asset_index = 0)), frames(whaleAssets[asset_index].frames), + mask(whaleAssets[asset_index].mask), speed(WHALE_SPEED) { const auto &aquarium = Aquarium::getInstance(); y = 0; @@ -46,15 +45,4 @@ const std::vector &Whale::getImage() const { return current_image; } -bool Whale::shouldBeRemoved() const noexcept { - const auto &aquarium = Aquarium::getInstance(); - const auto &first_frame = frames[0]; - - if (moving_right) { - return x > static_cast(aquarium.getWidth()); - } else { - return (x + static_cast(first_frame[6].length())) < 0; - } -} - int Whale::getPreferredLayer() const noexcept { return 8; } diff --git a/src/Whale.h b/src/Whale.h index f053545..0768b90 100644 --- a/src/Whale.h +++ b/src/Whale.h @@ -9,7 +9,6 @@ private: const std::vector> frames; const std::vector &mask; const float speed; - const bool moving_right; int current_frame_index = 0; int animation_counter = 0; @@ -28,7 +27,5 @@ public: const std::vector &getImage() const override; const std::vector &getMask() const override { return mask; } char getDefaultColor() const noexcept override { return 'B'; } - - bool shouldBeRemoved() const noexcept override; int getPreferredLayer() const noexcept override; }; diff --git a/src/assets/FishAssets.h b/src/assets/FishAssets.h index 86b592a..9c7efdf 100644 --- a/src/assets/FishAssets.h +++ b/src/assets/FishAssets.h @@ -1,53 +1,105 @@ #pragma once #include "../Entity.h" -#include "SpriteUtils.h" +#include "../SpriteUtils.h" #include -// Store only right-facing fish assets (half the data!) -const std::vector rightFacingFishAssets = { - {{R"(???\??)", R"(??/ \?)", R"(>=_('>)", R"(??\_/?)", R"(???/??)"}, - {R"( 1 )", R"( 1 1 )", R"(663745)", R"( 111 )", R"( 3 )"}}, - {{R"(?????,????)", R"(?????}\???)", R"(\??.' `\?)", R"(}}< ( 6>)", - R"(/??`, .'?)", R"(?????}/???)", R"(?????'????)"}, - {R"( 2 )", R"( 22 )", R"(6 11 11 )", R"(661 7 45)", - R"(6 11 11 )", R"( 33 )", R"( 3 )"}}, - {{R"(???????,--,_????)", R"(__????_\.---'-.?)", R"(\ '.-" // o\)", - R"(/_.'-._ \\ /)", R"(???????`"--(/"`?)"}, - {R"( 22222 )", R"(66 121111211 )", R"(6 6111 77 41)", - R"(6661111 77 1)", R"( 11113311 )"}}, - {{R"(??__?)", R"(><_'>)", R"(???'?)"}, - {R"( 11 )", R"(61145)", R"( 3 )"}}, - {{R"(????????_.-`\??????)", R"(?????-:`_..,_\?????)", - R"(('-..:-` , '-.,?)", R"(?} _ ;':( o :)", - R"((.-`/'-.,__'` _.-`?)", R"(???`'-.,/??//`?????)"}, - {R"( 22222 )", R"( 222111112 )", - R"(66661111 7 1111 )", R"( 6 1 7777 4 1)", - R"(6666211111177 1111 )", R"( 222222 333 )"}}, - {{ - R"(????????/\??????)", - R"(????????\.\_????)", - R"(\'-,.:-` '-,?)", - R"( ) _ (>( o <)", - R"(/.-`?':._ _.-`?)", - R"(??????;/?``?????)", +const std::vector fishAssets = { + { + { + R"(???\??)", + R"(??/ \?)", + R"(>=_('>)", + R"(??\_/?)", + R"(???/??)"}, + { + R"( 1 )", + R"( 1 1 )", + R"(663745)", + R"( 111 )", + R"( 3 )"}}, + { + { + R"(?????,????)", + R"(?????}\???)", + R"(\??.' `\?)", + R"(}}< ( 6>)", + R"(/??`, .'?)", + R"(?????}/???)", + R"(?????'????)"}, + { + R"( 2 )", + R"( 22 )", + R"(6 11 11 )", + R"(661 7 45)", + R"(6 11 11 )", + R"( 33 )", + R"( 3 )"}}, + { + { + R"(???????,--,_????)", + R"(__????_\.---'-.?)", + R"(\ '.-" // o\)", + R"(/_.'-._ \\ /)", + R"(???????`"--(/"`?)"}, + { + R"( 22222 )", + R"(66 121111211 )", + R"(6 6111 77 41)", + R"(6661111 77 1)", + R"( 11113311 )"}}, + { + { + R"(??__?)", + R"(><_'>)", + R"(???'?)"}, + { + R"( 11 )", + R"(61145)", + R"( 3 )"}}, + { + { + R"(????????_.-`\??????)", + R"(?????-:`_..,_\?????)", + R"(('-..:-` , '-.,?)", + R"(?} _ ;':( o :)", + R"((.-`/'-.,__'` _.-`?)", + R"(???`'-.,/??//`?????)"}, + { + R"( 22222 )", + R"( 222111112 )", + R"(66661111 7 1111 )", + R"( 6 1 7777 4 1)", + R"(6666211111177 1111 )", + R"( 222222 333 )"}}, + { + { + R"(????????/\??????)", + R"(????????\.\_????)", + R"(\'-,.:-` '-,?)", + R"( ) _ (>( o <)", + R"(/.-`?':._ _.-`?)", + R"(??????;/?``?????)", }, { - R"( 22 )", - R"( 2121 )", - R"(66661111 111 )", - R"( 6 1 777 4 1)", - R"(6666 1111 1111 )", - R"( 22 33 )", - }}, - {{R"(_?????????_.*"\??????)", R"(\'-._..-*` `'*-.??)", - R"(?) , (( o >)", R"(/.`"*--.__)_.`_.-*`??)"}, + R"( 22 )", + R"( 2121 )", + R"(66661111 111 )", + R"( 6 1 777 4 1)", + R"(6666 1111 1111 )", + R"( 22 33 )",}}, + { + { + R"(_?????????_.*"\??????)", + R"(\'-._..-*` `'*-.??)", + R"(?) , (( o >)", + R"(/.`"*--.__)_.`_.-*`??)"}, { - R"(6 11222 )", - R"(6661111111 11111 )", - R"( 6 3 77 4 1)", - R"(6661111111311311111 )", + R"(6 11222 )", + R"(6661111111 11111 )", + R"( 6 3 77 4 1)", + R"(6661111111311311111 )", }}}; inline const std::vector fishAssetPairs = - SpriteUtils::createBidirectionalAssets(rightFacingFishAssets); + createBidirectionalAssets(fishAssets); diff --git a/src/assets/SeaMonsterAssets.h b/src/assets/SeaMonsterAssets.h index 5fe98a6..c91a071 100644 --- a/src/assets/SeaMonsterAssets.h +++ b/src/assets/SeaMonsterAssets.h @@ -1,38 +1,30 @@ #pragma once #include "../Entity.h" +#include "../SpriteUtils.h" #include struct SeaMonsterAsset { - std::vector frame1; - std::vector frame2; + std::vector> frames; std::vector mask; }; -inline const std::vector seaMonsterAssets = { - {{ - R"( _???_?????????????????????_???_???????_a_a)", - R"( _{.`=`.}_??????_???_??????_{.`=`.}_????{/ ''\_)", - R"(?_????{.' _ '.}????{.`'`.}????{.' _ '.}??{| ._oo))", - R"({ \??{/ .'?'. \}??{/ .-. \}??{/ .'?'. \}?{/ |)", - }, - { - R"( _???_????????????????????_a_a)", - R"(??_??????_???_??????_{.`=`.}_??????_???_??????{/ ''\_)", - R"(?{ \????{.`'`.}????{.' _ '.}????{.`'`.}????{| ._oo))", - R"(??\ \??{/ .-. \}??{/ .'?'. \}??{/ .-. \}???{/ |)", - }, - { - R"( W W)", - R"()", - R"()", - R"()", - }}, - {{R"( a_a_???????_???_?????????????????????_???_)", - R"( _/'' \}????_{.`=`.}_??????_???_??????_{.`=`.}_)", - R"((oo_. |}??{.' _ '.}????{.`'`.}????{.' _ '.}????_)", - R"(????| \}?{/ .'?'. \}??{/ .-. \}??{/ .'?'. \}??/ })"}, - {R"( a_a_????????????????????_ _)", - R"( _/'' \}??????_???_??????_{.`=`.}_??????_???_??????_)", - R"((oo_. |}????{.`'`.}????{.' _ '.}????{.`'`.}????/ })", - R"(????| \}???{/ .-. \}??{/ .'?'. \}??{/ .-. \}??/ /)"}, - {R"( W W)", R"()", R"()", R"()"}}}; +const SeaMonsterAsset seaMonster = { + {// Frame 1 + { + R"(?????????_???_?????????????????????_???_???????_a_a???)", + R"(???????_{.`=`.}_??????_???_??????_{.`=`.}_????{/ ''\_?)", + R"(?_????{.' _ '.}????{.`'`.}????{.' _ '.}??{| ._oo))", + R"({ \??{/ .'?'. \}??{/ .-. \}??{/ .'?'. \}?{/ |????)"}, + { + R"(??????????????????????_???_????????????????????_a_a???)", + R"(??_??????_???_??????_{.`=`.}_??????_???_??????{/ ''\_?)", + R"(?{ \????{.`'`.}????{.' _ '.}????{.`'`.}????{| ._oo))", + R"(??\ \??{/ .-. \}??{/ .'?'. \}??{/ .-. \}???{/ |????)"}}, + { + R"( W W )", + R"()", + R"()", + R"()"}}; + +inline const std::vector seaMonsterAssets = + createBidirectionalFramedAssets(seaMonster); diff --git a/src/assets/ShipAssets.h b/src/assets/ShipAssets.h index 9dd3fae..b84d2e3 100644 --- a/src/assets/ShipAssets.h +++ b/src/assets/ShipAssets.h @@ -1,37 +1,15 @@ #pragma once #include "../Entity.h" +#include "../SpriteUtils.h" #include -inline std::vector shipAssets = { - {{ - R"( | | |)", - R"( )_) )_) )_))", - R"( )___))___))___)\)", - R"( )____)____)_____)\\)", - R"(_____|____|____|____\\\__)", - R"(\ /)", - }, - { - R"( y y y)", - R"()", - R"( w)", - R"( ww)", - R"(yyyyyyyyyyyyyyyyyyyywwwyy)", - R"(y y)", - }}, - {{ - R"( | | |)", - R"( (_( (_( (_()", - R"( /(___((___((___()", - R"( //(_____(____(____()", - R"(__///____|____|____|_____)", - R"(????\ /)", - }, - { - R"( y y y)", - R"()", - R"( w)", - R"( ww)", - R"(yywwwyyyyyyyyyyyyyyyyyyyy)", - R"( y y)", - }}}; +const AssetPair ship = { + {R"( | | | )", R"( )_) )_) )_) )", + R"( )___))___))___)\ )", R"( )____)____)_____)\\ )", + R"(_____|____|____|____\\\__)", R"(\ /????)"}, + {R"( y y y )", R"()", R"( w )", + R"( ww )", R"(yyyyyyyyyyyyyyyyyyyywwwyy)", + R"(y y )"}}; + +inline const std::vector shipAssets = + createBidirectionalAssets({ship});