// // Created by Matthew Gretton-Dann on 31/08/2025. // #include #include #include #include #include #include using Pos = std::pair; auto x(Pos const& p) noexcept -> int { return p.first; } auto y(Pos const& p) noexcept -> int { return p.second; } struct Square { Square(Pos const& pos, int length) noexcept : pos_(pos), length_(length) {} Square(Square const& other) noexcept = default; Square(Square&& other) noexcept = default; Square& operator=(Square const& other) noexcept = default; Square& operator=(Square&& other) noexcept = default; ~Square() noexcept = default; auto x() const noexcept -> int { return ::x(pos_); } auto y() const noexcept -> int { return ::y(pos_); } auto length() const noexcept -> int { return length_; } Pos pos_; int length_; }; struct OverlappingSquares { Pos pos_; }; struct Grid { Grid(int length) : grid_(length * length, '.'), length_(length) {} Grid(Grid const& other) = default; Grid(Grid&& other) noexcept = default; Grid& operator=(Grid const& other) = default; Grid& operator=(Grid&& other) noexcept = default; ~Grid() noexcept = default; auto length() const noexcept -> int { return length_; } auto set(int x, int y, char c) noexcept -> void { assert (x < length_); assert (y < length_); assert (grid_[x + y * length_] != c); grid_[x + y * length_] = c; } auto get(int x, int y) const noexcept -> char { assert (x < length_); assert (y < length_); return grid_[x + y * length_]; } auto add(Square const& sq) -> void { switch (sq.length()) { case 1: set(sq.x(), sq.y(), '*'); break; case 2: set(sq.x(), sq.y(), '+'); set(sq.x() + 1, sq.y(), '+');set(sq.x(), sq.y() + 1, '+');set(sq.x() + 1, sq.y() + 1, '+'); break; default: { auto n = sq.length(); set(sq.x(), sq.y(), '+'); set(sq.x() + n - 1, sq.y(), '+'); set(sq.x(), sq.y() + n -1, '+'); set(sq.x() + n - 1, sq.y() + n -1, '+'); for (int i = 1; i < n -1; ++i) { set(sq.x() + i, sq.y(), '-'); set(sq.x() + i, sq.y() + n - 1, '-'); set(sq.x(), sq.y() + i, '|'); for (int j = 1; j < n -1; ++j) { set (sq.x() + j, sq.y() + i, ' '); } set(sq.x() + n - 1, sq.y() + i, '|'); } int i = sq.x() + n - 1; while (n != 0) { set(--i, sq.y() + 1, '0' + (n % 10)); n /= 10; } } } } auto clear(Square const& sq) { for (auto i = sq.x(); i < sq.x() + sq.length(); ++i) { for (auto j = sq.y(); j < sq.y() + sq.length(); ++j) { set(i, j, '.'); } } } auto output() const { for (auto i = 0; i < length_; ++i) { std::cout << grid_.substr(i * length_, length_) << '\n'; } } auto fits(Square const& sq) const noexcept -> bool { assert (sq.x() < length_); assert (sq.y() < length_); if (sq.x() + sq.length() > length_) { return false; } else if (sq.y() + sq.length() > length_) { return false; } else { auto pos = grid_.begin() + sq.x() + sq.y() * length_; std::string_view v(pos, pos + sq.length()); return v.find_first_not_of('.') == std::string_view::npos; } } auto next_pos(Pos const& pos) const noexcept -> Pos { if (const auto p = x(pos) + 1 + y(pos) * length_; p >= grid_.size()) { return std::make_pair(0, length_); } else { const auto next_p = grid_.find('.', p); if (next_p == std::string::npos) { return std::make_pair(0, length_); } return std::make_pair(next_p % length_, next_p / length_); } } std::string grid_; int length_; }; auto triangle_num(int n) { return (n * (n + 1)) / 2; } using Avail = std::vector; auto find_solution_impl(Grid& grid, int n, Pos const& pos, int idx, Avail& avail_sqs)-> bool { auto const sq = Square(pos, idx); if (x(pos) == 0 && y(pos) == grid.length()) { return true; } if (idx == 0) { return false; } if (avail_sqs[idx] == 0) { return find_solution_impl(grid, n, pos, idx - 1, avail_sqs); } if (grid.fits(sq)) { --avail_sqs[idx]; grid.add(sq); auto next_pos = grid.next_pos(pos); auto const result = find_solution_impl(grid, n, next_pos, n, avail_sqs); ++avail_sqs[idx]; if (result) { return true; } grid.clear(sq); return find_solution_impl(grid, n, pos, idx - 1, avail_sqs); } return find_solution_impl(grid, n, pos, idx - 1, avail_sqs); } auto find_solution(int n) -> Grid{ auto length = triangle_num(n); Grid grid(length); Avail avail_sqs; for (auto i = 0; i <= n; ++i) { avail_sqs.push_back(i); } find_solution_impl(grid, n, std::make_pair(0, 0), n, avail_sqs); return grid; } int main(int argc, char** argv) { auto n = (argc == 1) ? 9 : atoi(argv[1]); auto grid = find_solution(n); std::cout << "Partridge problem " << n << " side length " << grid.length() << '\n'; grid.output(); return 0; }