propagator.hpp
4.53 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
#pragma once
#include <vector>
#include <tuple>
#include <array>
#include "utils/array2D.hpp"
#include "utils/array3D.hpp"
#include "wave.hpp"
#include "direction.hpp"
using namespace std;
/**
* Propagate information about patterns in the wave.
*/
class Propagator {
private:
/**
* The size of the patterns.
*/
const unsigned patterns_size;
/**
* propagator[pattern1][direction] contains all the patterns that can be placed in
* next to pattern1 in the direction direction.
*/
const vector<array<vector<unsigned>, 4>> propagator;
/**
* The wave width and height.
*/
const unsigned wave_width;
const unsigned wave_height;
/**
* True if the wave and the output is toric.
*/
const bool periodic_output;
/**
* All the tuples (y, x, pattern) that should be propagated.
* The tuple should be propagated when wave.get(y, x, pattern) is set to false.
*/
vector<tuple<unsigned, unsigned, unsigned>> propagating;
/**
* compatible.get(y, x, pattern)[direction] contains the number of patterns present in the wave
* that can be placed in the cell next to (y,x) in the opposite direction of direction without being
* in contradiction with pattern placed in (y,x).
* If wave.get(y, x, pattern) is set to false, then compatible.get(y, x, pattern) has every element negative or null
*/
Array3D<array<int, 4>> compatible;
/**
* Initialize compatible.
*/
void init_compatible() noexcept {
array<int, 4> value;
// We compute the number of pattern compatible in all directions.
for(unsigned y = 0; y < wave_height; y++) {
for(unsigned x = 0; x < wave_width; x++) {
for(unsigned pattern = 0; pattern < patterns_size; pattern++) {
for(int direction = 0; direction < 4; direction++) {
value[direction] = propagator[pattern][get_opposite_direction(direction)].size();
}
compatible.get(y, x, pattern) = value;
}
}
}
}
public:
/**
* Constructor building the propagator and initializing compatible.
*/
Propagator(unsigned wave_height, unsigned wave_width, bool periodic_output,
vector<array<vector<unsigned>, 4>> propagator) noexcept :
patterns_size(propagator.size()), propagator(propagator), wave_width(wave_width),
wave_height(wave_height), periodic_output(periodic_output),
compatible(wave_height, wave_width, patterns_size)
{
init_compatible();
}
/**
* Add an element to the propagator.
* This function is called when wave.get(y, x, pattern) is set to false.
*/
void add_to_propagator(unsigned y, unsigned x, unsigned pattern) noexcept {
// All the direction are set to 0, since the pattern cannot be set in (y,x).
array<int, 4> temp = {0,0,0,0};
compatible.get(y,x,pattern) = temp;
propagating.emplace_back(y, x, pattern);
}
/**
* Propagate the information given with add_to_propagator.
*/
void propagate(Wave& wave) noexcept {
// We propagate every element while there is element to propagate.
while(propagating.size() != 0) {
// The cell and pattern that has been set to false.
unsigned y1, x1, pattern;
tie(y1, x1, pattern) = propagating.back();
propagating.pop_back();
// We propagate the information in all 4 directions.
for(unsigned direction = 0; direction < 4; direction++) {
// We get the next cell in the direction direction.
int dx = directions_x[direction];
int dy = directions_y[direction];
int x2, y2;
if(periodic_output) {
x2 = ((int)x1 + dx + (int)wave.width) % wave.width;
y2 = ((int)y1 + dy + (int)wave.height) % wave.height;
} else {
x2 = x1 + dx;
y2 = y1 + dy;
if(x2 < 0 || x2 >= (int)wave.width) {
continue;
}
if(y2 < 0 || y2 >= (int)wave.height) {
continue;
}
}
// The index of the second cell, and the patterns compatible
unsigned i2 = x2 + y2 * wave.width;
const vector<unsigned>& patterns = propagator[pattern][direction];
// For every pattern that could be placed in that cell without being in contradiction with pattern1
for(auto it = patterns.begin(), it_end = patterns.end(); it < it_end; ++it) {
// We decrease the number of compatible patterns in the opposite direction
// If the pattern was discarded from the wave, the element is still negative, which is not a problem
array<int, 4>& value = compatible.get(y2, x2, *it);
value[direction]--;
// If the element was set to 0 with this operation, we need to remove the pattern
// from the wave, and propagate the information
if(value[direction] == 0) {
add_to_propagator(y2, x2, *it);
wave.set(i2, *it, false);
}
}
}
}
}
};