Initial C++ version of Partridge solver
This is almost a complete copy of the OCaml version About twice as fast.
This commit is contained in:
167
main.cc
Normal file
167
main.cc
Normal file
@@ -0,0 +1,167 @@
|
||||
//
|
||||
// Created by Matthew Gretton-Dann on 31/08/2025.
|
||||
//
|
||||
|
||||
#include <cassert>
|
||||
#include <utility>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
|
||||
using Pos = std::pair<int, int>;
|
||||
|
||||
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<int>;
|
||||
|
||||
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;
|
||||
}
|
||||
Reference in New Issue
Block a user