Comment code.
This commit is contained in:
112
main.cc
112
main.cc
@@ -1,6 +1,10 @@
|
|||||||
//
|
/** \file main.cc
|
||||||
// Created by Matthew Gretton-Dann on 31/08/2025.
|
* \author Matthew Gretton-Dann
|
||||||
//
|
* \brief Solves the partirige problem for user specified size.
|
||||||
|
*
|
||||||
|
* Copyright 2025, Matthew-Gretton-Dann
|
||||||
|
* SPDX: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
@@ -8,13 +12,23 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
|
/** (x, y) pair storing a position. */
|
||||||
using Pos = std::pair<int, int>;
|
using Pos = std::pair<int, int>;
|
||||||
|
|
||||||
|
/** Get x co-ordinate from position */
|
||||||
auto x(Pos const &p) noexcept -> int { return p.first; }
|
auto x(Pos const &p) noexcept -> int { return p.first; }
|
||||||
|
|
||||||
|
/** Get y co-ordinate from position */
|
||||||
auto y(Pos const &p) noexcept -> int { return p.second; }
|
auto y(Pos const &p) noexcept -> int { return p.second; }
|
||||||
|
|
||||||
|
/** A square - consisting of position of closest corner to origin, and side-length.
|
||||||
|
*/
|
||||||
struct Square {
|
struct Square {
|
||||||
Square(Pos const &pos, int length) noexcept : pos_(pos), length_(length) {
|
/** Construct a square.
|
||||||
|
* \param pos Position of closest corner to origin
|
||||||
|
* \param length Side length.
|
||||||
|
*/
|
||||||
|
Square(Pos const &pos, int const length) noexcept : pos_(pos), length_(length) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Square(Square const &other) noexcept = default;
|
Square(Square const &other) noexcept = default;
|
||||||
@@ -27,20 +41,24 @@ struct Square {
|
|||||||
|
|
||||||
~Square() noexcept = default;
|
~Square() noexcept = default;
|
||||||
|
|
||||||
|
/** Get x co-ordinate of closest corner to origin. */
|
||||||
auto x() const noexcept -> int { return ::x(pos_); }
|
auto x() const noexcept -> int { return ::x(pos_); }
|
||||||
|
|
||||||
|
/** Get y co-ordinate of closest corner to origin. */
|
||||||
auto y() const noexcept -> int { return ::y(pos_); }
|
auto y() const noexcept -> int { return ::y(pos_); }
|
||||||
|
|
||||||
|
/** Get side length. */
|
||||||
auto length() const noexcept -> int { return length_; }
|
auto length() const noexcept -> int { return length_; }
|
||||||
|
|
||||||
Pos pos_;
|
private:
|
||||||
int length_;
|
Pos pos_; ///< Position of corner closest to origin
|
||||||
};
|
int length_; ///< Side length
|
||||||
|
|
||||||
struct OverlappingSquares {
|
|
||||||
Pos pos_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** An N * N grid of characters. */
|
||||||
struct Grid {
|
struct Grid {
|
||||||
Grid(int length) : grid_(length * length, '.'), length_(length) {
|
/** Construct a grid of given side-length. */
|
||||||
|
Grid(int length) : grid_(length * length, empty), length_(length) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Grid(Grid const &other) = delete;
|
Grid(Grid const &other) = delete;
|
||||||
@@ -53,22 +71,11 @@ struct Grid {
|
|||||||
|
|
||||||
~Grid() noexcept = default;
|
~Grid() noexcept = default;
|
||||||
|
|
||||||
|
/** Get grid length */
|
||||||
auto length() const noexcept -> int { return length_; }
|
auto length() const noexcept -> int { return length_; }
|
||||||
|
|
||||||
auto set(int x, int y, char c) noexcept -> void {
|
/** Add a square to the grid. */
|
||||||
assert(x < length_);
|
auto add(Square const &sq) noexcept -> void {
|
||||||
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()) {
|
switch (sq.length()) {
|
||||||
case 1: set(sq.x(), sq.y(), '*');
|
case 1: set(sq.x(), sq.y(), '*');
|
||||||
break;
|
break;
|
||||||
@@ -102,18 +109,19 @@ struct Grid {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto clear(Square const &sq) {
|
/** Clear a square from the grid. */
|
||||||
|
auto clear(Square const &sq) noexcept -> void {
|
||||||
for (auto i = sq.x(); i < sq.x() + sq.length(); ++i) {
|
for (auto i = sq.x(); i < sq.x() + sq.length(); ++i) {
|
||||||
for (auto j = sq.y(); j < sq.y() + sq.length(); ++j) {
|
for (auto j = sq.y(); j < sq.y() + sq.length(); ++j) {
|
||||||
set(i, j, '.');
|
set(i, j, empty);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto output() const {
|
/** Output the grid. */
|
||||||
for (auto i = 0; i < length_; ++i) {
|
auto output() const -> void {
|
||||||
std::cout <<
|
for (auto idx = 0; idx < length_ * length_; idx += length_) {
|
||||||
std::string_view(grid_.data() + i * length_, length_) << '\n';
|
std::cout << std::string_view(grid_.data() + idx, length_) << '\n';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,23 +156,44 @@ struct Grid {
|
|||||||
*/
|
*/
|
||||||
auto next_pos(Pos const &pos, int n) const noexcept -> Pos {
|
auto next_pos(Pos const &pos, int n) const noexcept -> Pos {
|
||||||
auto const b = grid_.begin() + x(pos) + n + y(pos) * length_;
|
auto const b = grid_.begin() + x(pos) + n + y(pos) * length_;
|
||||||
auto const p = std::find(b, grid_.end(), '.');
|
auto const p = std::find(b, grid_.end(), empty);
|
||||||
if (p == grid_.end()) {
|
|
||||||
return std::make_pair(0, length_);
|
|
||||||
}
|
|
||||||
auto const v = p - grid_.begin();
|
auto const v = p - grid_.begin();
|
||||||
return std::make_pair(v % length_, v / length_);
|
return std::make_pair(v % length_, v / length_);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<char> grid_;
|
private:
|
||||||
int length_;
|
/** Set the grid position (x, y) to the character c.
|
||||||
|
*
|
||||||
|
* It is an error if (x, y) is already set to c - as that means we have overlapping
|
||||||
|
* squares.
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<char> grid_; ///< The grid
|
||||||
|
int length_; ///< Side length
|
||||||
|
|
||||||
|
static const int empty = '.'; ///< Character used for an empty cell.
|
||||||
};
|
};
|
||||||
|
|
||||||
auto triangle_num(int n) { return (n * (n + 1)) / 2; }
|
/** Get the n'th triangular number. */
|
||||||
|
auto triangle_num(int n) noexcept -> int { return (n * (n + 1)) / 2; }
|
||||||
|
|
||||||
|
/** Vector used to identify the available squares. */
|
||||||
using Avail = std::vector<int>;
|
using Avail = std::vector<int>;
|
||||||
|
|
||||||
auto find_solution_impl(Grid &grid, int n, Pos const &pos, Avail &avail_sqs) -> bool {
|
/** Recursive part of solution finder.
|
||||||
|
*
|
||||||
|
* Fills \a grid with squares from \a avail_sqs, starting at the current
|
||||||
|
* position \a pos. \a n is the side-length of the largest square.
|
||||||
|
*
|
||||||
|
* Returns \c true if a solution is found, \a c false if not.
|
||||||
|
*/
|
||||||
|
auto find_solution_impl(Grid &grid, int n, Pos const &pos, Avail &avail_sqs) noexcept -> bool {
|
||||||
if (x(pos) == 0 && y(pos) == grid.length()) { return true; }
|
if (x(pos) == 0 && y(pos) == grid.length()) { return true; }
|
||||||
|
|
||||||
/* Walk through the possible squares from the largest that will fit down to 0.
|
/* Walk through the possible squares from the largest that will fit down to 0.
|
||||||
@@ -176,7 +205,6 @@ auto find_solution_impl(Grid &grid, int n, Pos const &pos, Avail &avail_sqs) ->
|
|||||||
* If we know a square of side length N will fit then we know a square of side length
|
* If we know a square of side length N will fit then we know a square of side length
|
||||||
* N - 1 will fit.
|
* N - 1 will fit.
|
||||||
*/
|
*/
|
||||||
assert(x(pos) + grid.largest_square(pos, n) <= grid.length());
|
|
||||||
for (auto idx = grid.largest_square(pos, n); idx != 0; --idx) {
|
for (auto idx = grid.largest_square(pos, n); idx != 0; --idx) {
|
||||||
if (avail_sqs[idx] == 0) { continue; }
|
if (avail_sqs[idx] == 0) { continue; }
|
||||||
|
|
||||||
@@ -191,6 +219,10 @@ auto find_solution_impl(Grid &grid, int n, Pos const &pos, Avail &avail_sqs) ->
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Find a solution to the partridge problem of size n.
|
||||||
|
*
|
||||||
|
* Returns the solution grid.
|
||||||
|
*/
|
||||||
auto find_solution(int n) -> Grid {
|
auto find_solution(int n) -> Grid {
|
||||||
auto length = triangle_num(n);
|
auto length = triangle_num(n);
|
||||||
Grid grid(length);
|
Grid grid(length);
|
||||||
|
|||||||
Reference in New Issue
Block a user