This question is a general algorithmic question, but I am writing it in C as it is the language in which I have faced this problem. Let's say I have the following function:
using Matrix = std::array<std::array<uint8_t, 3>, 3>;
void findOccurrences(std::vector<Matrix>& output, const std::vector<std::vector<uint8_t>>& pattern);
Assuming that pattern
is a certain pattern of numbers from 0 to 255, that can fit in a Matrix
as I defined above, and given that 0
means an "empty" slot, I want to be able to generate all the possible occurrences of pattern
as a Matrix
.
For example, given the following pattern:
{
{ 1, 2 },
{ 3, 4 }
}
I want to recive the following vector of matrixes:
1 | 2 | 0
3 | 4 | 0
0 | 0 | 0
0 | 1 | 2
0 | 3 | 4
0 | 0 | 0
0 | 0 | 0
1 | 2 | 0
3 | 4 | 0
0 | 0 | 0
0 | 1 | 2
0 | 3 | 4
The pattern does not have to be a square, but we assume that it is not larger than a Matrix
can contain.
I have thought of some approaches for this problem, and ended up with what I think is the most obvious way to do it, but I am having a hard time trying to figure out the logic for the entire thing.
So far what I have is:
void findOccurrences(std::vector<Matrix>& output, const std::vector<std::vector<uint8_t>>& pattern)
{
Pattern curPattern = {0}; //temporary pattern, to store each time the current we work on
const size_t lineOpts = 3 - pattern.size() 1; //amount of possible line combinations
for (size_t i = 0; i < lineOpts; i ) //for each possible combination
{
for (size_t j = 0; j < pattern.size(); j ) //for each line in pattern
{
const size_t lineInd = j i; //index of line in curPattern
const auto& line = pattern[j]; //current line in input pattern
const size_t colOpts = 3 - line.size() 1; //amount of possible column combinations for this line
for (size_t k = 0; k < colOpts; k ) //for each possible column combination
{
for (size_t l = 0; l < line.size(); l ) //for each column in line
{
const size_t colInd = l k; //index of column in curPattern
//got stuck here
}
}
}
}
}
The problem I'm having here is that I can't think of a way to continue this algorithm without losing possibilities. For example, getting only options 0
and 2
from the example result vector I gave earlier. Plus, this approach seems like it might be a inefficient.
Is this even the right way to go? And if so, what am I missing?
Edit: We also assume that pattern
does not contains 0
, as it marks an empty slot.
CodePudding user response:
You were already somehow on the right track.
Logically it is clear what has to be done.
We take the upper left edge of the sub pattern. Then we calculate the resulting upper left edges in the target matrix.
The column offset in the resulting matrix, where we will copy the pattern to, will start at 0 and will be incremented up to the size of the matrix - the size of the pattern 1.
Same with the row offset.
So, in the above case, with a matrix size of 3,3 and a pattern size, the target position in the resulting matrix will be 0,0, 0,1, 1,0 1,1. And then we copy the complete pattern at these positions.
We need to play a little bit with indices, but that is not that complicated.
I have created a well documented example code. If you will read this, then you will immediately understand. Please see below one of many possible solutions:
#include <iostream>
#include <vector>
#include <array>
#include <cstdint>
constexpr size_t MatrixSize = 3u;
using MyType = uint8_t;
using MatrixRow = std::array<MyType, MatrixSize>;
using Matrix = std::array<MatrixRow, MatrixSize>;
using Pattern = std::vector<std::vector<MyType>>;
using MatrixPattern = std::vector<Matrix>;
MatrixPattern findOccurence(const Pattern& pattern) {
// Here we will store the resulting matrixes
MatrixPattern result{};
// Sanity check 1. Do we have data in the pattern at all
if (pattern.empty() or pattern.front().empty()) {
std::cerr << "\n\n*** Error: At least one dimension of input pattern is empty\n\n";
}
// Sanity check 2. Does pattern fit at all into the matrix
else if ((pattern.size() > MatrixSize) or (pattern.front().size() > MatrixSize)) {
std::cerr << "\n\n*** Error: At least one dimension of input pattern is empty\n\n";
}
else {
// Now, we know that we will have a solution
// Check, how many horizontol fits we can theoretically have
// This will be size of sizeof Matrix - sizeof pattern 1.
const size_t horizontalFits{ MatrixSize - pattern.front().size() 1 };
// Same for vertical fits
const size_t verticalFits{ MatrixSize - pattern.size() 1 };
// We now know the horizontal and vertical fits and can resize the
// Resulting vector accordingly.
result.resize(horizontalFits * verticalFits);
size_t indexInResult{ 0 };
// For all possible positions of the patern in the resulting matrix
for (size_t startRowInResultingMatrix{ 0u }; startRowInResultingMatrix < verticalFits; startRowInResultingMatrix)
for (size_t startColumnInMatrix{ 0u }; startColumnInMatrix < horizontalFits; startColumnInMatrix) {
// Now we have the upper left edge position of the pattern in the matrix
// Copy pattern to that position
for (size_t rowOfPattern{ 0u }; rowOfPattern < pattern.size(); rowOfPattern)
for (size_t colOfPattern{ 0u }; colOfPattern < pattern.front().size(); colOfPattern)
// Copy. Calculate the correct indices and copy values from sub pattern to matrix
result[indexInResult][startRowInResultingMatrix rowOfPattern][startColumnInMatrix colOfPattern] = pattern[rowOfPattern][colOfPattern];
// Next sub matrix
indexInResult;
}
}
return result;
}
// Driver/Test code
int main() {
// Pattern to insert
Pattern pattern{
{1,2},
{3,4}
};
// Get the result
MatrixPattern matrixPattern = findOccurence(pattern);
// Show output
for (const Matrix& matrix : matrixPattern) {
for (const MatrixRow& matrixRow : matrix) {
for (const MyType& m : matrixRow)
std::cout << (int)m << ' ';
std::cout << '\n';
}
std::cout << "\n\n";
}
}