#pragma once #include #include #include #include #include #include #include #include "special_numeric_types.hpp" #include "variant_visitor.hpp" namespace better { /* A specific square on the controller. (0, 0) is the top-left button, x goes right, y goes down. x → 0 1 2 3 y 0 □ □ □ □ ↓ 1 □ □ □ □ 2 □ □ □ □ 3 □ □ □ □ */ class Position { public: Position(std::uint64_t x, std::uint64_t y); static Position from_index(std::uint64_t index); std::uint64_t index() const; std::uint64_t get_x() const; std::uint64_t get_y() const; auto operator<=>(const Position&) const = default; friend std::ostream& operator<<(std::ostream& out, const Position& pos); Position mirror_horizontally() const; Position mirror_vertically() const; Position rotate_90_clockwise() const; Position rotate_90_counter_clockwise() const; Position rotate_180() const; private: std::uint64_t x; std::uint64_t y; }; class TapNote { public: TapNote(Fraction time, Position position); Fraction get_time() const; Position get_position() const; bool operator==(const TapNote&) const = default; friend std::ostream& operator<<(std::ostream& out, const TapNote& t); nlohmann::ordered_json dump_to_memon_1_0_0() const; TapNote mirror_horizontally() const; TapNote mirror_vertically() const; TapNote rotate_90_clockwise() const; TapNote rotate_90_counter_clockwise() const; TapNote rotate_180() const; TapNote quantize(unsigned int snap) const; private: Fraction time; Position position; }; class LongNote { public: LongNote(Fraction time, Position position, Fraction duration, Position tail_tip); Fraction get_time() const; Position get_position() const; Fraction get_end() const; Fraction get_duration() const; Position get_tail_tip() const; std::uint64_t get_tail_length() const; std::uint64_t get_tail_angle() const; bool operator==(const LongNote&) const = default; friend std::ostream& operator<<(std::ostream& out, const LongNote& l); nlohmann::ordered_json dump_to_memon_1_0_0() const; int tail_as_6_notation() const; LongNote mirror_horizontally() const; LongNote mirror_vertically() const; LongNote rotate_90_clockwise() const; LongNote rotate_90_counter_clockwise() const; LongNote rotate_180() const; LongNote quantize(unsigned int snap) const; private: Fraction time; Position position; Fraction duration; Position tail_tip; }; Position convert_legacy_memon_tail_index_to_position(const Position& pos, std::uint64_t tail_index); Position convert_6_notation_to_position(const Position& pos, std::uint64_t tail_index); class Note { public: template Note(Ts&&... Args) requires (std::constructible_from, Ts...>) : note(std::forward(Args)...) {}; Fraction get_time() const; std::pair get_time_bounds() const; Position get_position() const; Fraction get_end() const; template auto visit(T& visitor) const {return std::visit(visitor, this->note);}; bool operator==(const Note&) const = default; friend std::ostream& operator<<(std::ostream& out, const Note& n); nlohmann::ordered_json dump_to_memon_1_0_0() const; static Note load_from_memon_1_0_0( const nlohmann::json& json, std::uint64_t resolution = 240 ); static Note load_from_memon_legacy( const nlohmann::json& json, std::uint64_t resolution ); Note mirror_horizontally() const; Note mirror_vertically() const; Note rotate_90_clockwise() const; Note rotate_90_counter_clockwise() const; Note rotate_180() const; Note quantize(unsigned int snap) const; private: std::variant note; }; } template <> struct fmt::formatter: formatter { // parse is inherited from formatter. template auto format(const better::Position& pos, FormatContext& ctx) { return format_to( ctx.out(), "(x: {}, y: {})", pos.get_x(), pos.get_y() ); } }; template <> struct fmt::formatter: formatter { // parse is inherited from formatter. template auto format(const better::TapNote& t, FormatContext& ctx) { return format_to( ctx.out(), "TapNote(time: {}, position: {})", t.get_time(), t.get_position() ); } }; template <> struct fmt::formatter: formatter { // parse is inherited from formatter. template auto format(const better::LongNote& l, FormatContext& ctx) { return format_to( ctx.out(), "LongNote(time: {}, position: {}, duration: {}, tail tip: {})", l.get_time(), l.get_position(), l.get_duration(), l.get_tail_tip() ); } }; template <> struct fmt::formatter: formatter { // parse is inherited from formatter. template auto format(const better::Note& n, FormatContext& ctx) { const auto visitor = [&](const auto& n){return format_to(ctx.out(), "{}", n);}; return n.visit(visitor); } };