#include <iostream>
#include <algorithm>
#include <vector>
template <typename T>
class matrix {
public:
size_t cols;
size_t rows;
private:
std::vector<T> data;
public:
matrix() : cols(0), rows(0) {
}
matrix(const size_t cols, const size_t rows) : cols(cols), rows(rows) {
data = std::vector<T>(cols * rows);
}
matrix(const size_t cols, const size_t rows, const T val) : cols(cols), rows(rows) {
data = std::vector<T>(cols * rows, val);
}
T& operator()(const size_t col, const size_t row) {
return data[col * rows + row];
}
const T& operator()(const size_t col, const size_t row) const {
return data[col * rows + row];
}
matrix<T> rotate() const {
matrix<T> new_mat;
new_mat = matrix(rows, cols);
for (size_t col = 0; col < new_mat.cols; col++) {
for (size_t row = 0; row < new_mat.rows; row++) {
new_mat(col, row) = operator()(row, (rows - 1) - col);
}
}
return new_mat;
}
matrix<T> copy(const size_t c_col, const size_t c_row, size_t c_cols, size_t c_rows) const {
if (c_col + c_cols > cols - 1) {
c_cols = cols - c_col;
}
if (c_row + c_rows > rows - 1) {
c_rows = rows - c_row;
}
matrix<T> new_mat = matrix(c_cols, c_rows);
for (size_t col = 0; col < c_cols; col++) {
for (size_t row = 0; row < c_rows; row++) {
//std::cout << "(" << c_col + col << ", " << c_row + row << ") --> (" << col << ", " << row << ")" << std::endl;
new_mat(col, row) = operator()(c_col + col, c_row + row);
//std::cout << "(" << col << ", " << row << ") = " << i << std::endl;
}
}
return new_mat;
}
// You should change this to use a predicate to decide whether or not a value should be cropped.
matrix<T> crop(const T empty_val) const {
matrix<T> new_mat = *this;
// Use rotation to help crop!
int i = 4;
while (i --> 0) {
bool do_break = false;
for (size_t col = 0; col < new_mat.cols; col++) {
if (do_break) {
break;
}
for (size_t row = 0; row < new_mat.rows; row++) {
if (new_mat(col, row) != empty_val) {
new_mat = new_mat.copy(col, 0, new_mat.cols - col, new_mat.rows).rotate();
do_break = true;
break;
}
}
}
}
return new_mat;
}
// You have to go first by rows and then by columns since printing is sort of "row major".
void print() const {
for (size_t row = 0; row < rows; row++) {
for (size_t col = 0; col < cols; col++) {
std::cout << this->operator()(col, row) << ' ';
}
std::cout << std::endl;
}
std::cout << std::endl;
}
};
int main() {
std::vector<std::string> words = { "colorful", "dividend", "fourteen", "alsatian" };
size_t side_size = 28;
matrix<char> empty_mat(side_size, side_size, ' ');
matrix<char> best_mat(side_size, side_size, ' ');
// Try each possible sequence of words. For each word that you try, try every possible place that word can fit.
std::sort(words.begin(), words.end());
do {
matrix<char> mat(empty_mat);
for (std::string s : words) {
size_t this_col = 0;
size_t this_row = 0;
bool good = true;
bool do_break = false;
int r = 4;
while (r--> 0) {
if (do_break == true) break;
// Rotate the matrix ninety degrees each time and only deal with the forward horizontal case.
mat = mat.rotate();
// Find a place to try the word.
for (size_t i = 0; i < s.size(); i++) {
char& c = s[i];
if (do_break == true) break;
for (size_t col = 0; col < mat.cols; col++) {
if (do_break == true) break;
for (size_t row = 0; row < mat.rows; row++) {
good = false;
if (mat(col, row) == c) {
good = true;
// Make sure that the word isn't colliding with anything already there.
for (size_t k = col - i; k < col - i + s.size(); k++) {
for (size_t q = row - 1; q <= row + 1; q++) {
if (q == 0) {
if ((mat(k, row) != ' ') && (mat(k, row) != s[(k) - (col - i)])) {
good = false;
break;
}
}
else if (k != col) {
if (mat(k, q) != ' ') {
good = false;
break;
}
}
}
}
}
if (good) {
this_col = col - i;
this_row = row;
do_break = true;
break;
}
}
}
}
}
if (this_col == 0 && this_row == 0) {
this_col = side_size / 2;
this_row = side_size / 2;
}
for (char c : s) {
mat(this_col++, this_row) = c;
}
}
// for (std::string s : words) {
// std::cout << s << ' ';
// }
std::cout << std::endl;
mat.crop(' ').print();
} while (std::next_permutation(words.begin(), words.end()));
return 0;
}