2022-04-21 20:00:42 +02:00
|
|
|
#ifndef WAVE_FORM_COLLAPSE_H
|
|
|
|
#define WAVE_FORM_COLLAPSE_H
|
|
|
|
|
2022-04-21 23:31:25 +02:00
|
|
|
#include "core/int_types.h"
|
|
|
|
#include "core/math/random_pcg.h"
|
2022-04-20 03:05:34 +02:00
|
|
|
|
|
|
|
#include "array_2d.h"
|
2022-04-21 23:31:25 +02:00
|
|
|
#include "array_3d.h"
|
|
|
|
#include "core/vector.h"
|
|
|
|
|
|
|
|
#include "core/reference.h"
|
|
|
|
|
2022-04-21 20:00:42 +02:00
|
|
|
class WaveFormCollapse : public Reference {
|
|
|
|
GDCLASS(WaveFormCollapse, Reference);
|
|
|
|
|
|
|
|
public:
|
|
|
|
enum ObserveStatus {
|
|
|
|
OBSERVE_STATUS_SUCCESS,
|
|
|
|
OBSERVE_STATUS_FAILURE,
|
|
|
|
OBSERVE_STATUS_TO_CONTINUE
|
|
|
|
};
|
|
|
|
|
2022-04-21 23:31:25 +02:00
|
|
|
struct PropagatorStateEntry {
|
|
|
|
Vector<uint32_t> directions[4];
|
|
|
|
};
|
|
|
|
|
2022-04-22 00:50:57 +02:00
|
|
|
struct PropagatingEntry {
|
|
|
|
uint32_t data[3];
|
|
|
|
|
|
|
|
PropagatingEntry() {
|
|
|
|
for (int i = 0; i < 3; ++i) {
|
|
|
|
data[i] = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
PropagatingEntry(uint32_t x, uint32_t y, uint32_t z) {
|
|
|
|
data[0] = x;
|
|
|
|
data[1] = y;
|
|
|
|
data[2] = z;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2022-04-21 23:31:25 +02:00
|
|
|
struct CompatibilityEntry {
|
|
|
|
int direction[4];
|
|
|
|
|
|
|
|
CompatibilityEntry() {
|
|
|
|
for (int i = 0; i < 4; ++i) {
|
|
|
|
direction[i] = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2022-04-21 23:35:45 +02:00
|
|
|
static constexpr int directions_x[4] = { 0, -1, 1, 0 };
|
|
|
|
static constexpr int directions_y[4] = { -1, 0, 0, 1 };
|
|
|
|
|
2022-04-21 23:31:25 +02:00
|
|
|
public:
|
|
|
|
bool get_eriodic_output() const;
|
|
|
|
void set_periodic_output(const bool val);
|
|
|
|
|
|
|
|
void set_seed(const int seed);
|
|
|
|
|
|
|
|
void set_size(uint32_t p_width, uint32_t p_height);
|
|
|
|
|
|
|
|
void set_propagator_state(const Vector<PropagatorStateEntry> &p_propagator_state);
|
|
|
|
void set_pattern_frequencies(const Vector<double> &p_patterns_frequencies, const bool p_normalize = true);
|
|
|
|
|
2022-04-21 20:00:42 +02:00
|
|
|
Array2D<uint32_t> run();
|
|
|
|
|
|
|
|
ObserveStatus observe();
|
|
|
|
|
2022-04-21 23:31:25 +02:00
|
|
|
//dvoid propagate() { propagator.propagate(wave); }
|
2022-04-21 20:00:42 +02:00
|
|
|
|
|
|
|
void remove_wave_pattern(uint32_t i, uint32_t j, uint32_t pattern) {
|
2022-04-21 23:31:25 +02:00
|
|
|
if (wave_get(i, j, pattern)) {
|
|
|
|
wave_set(i, j, pattern, false);
|
|
|
|
add_to_propagator(i, j, pattern);
|
2022-04-21 20:00:42 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-21 23:31:25 +02:00
|
|
|
// Return true if pattern can be placed in cell index.
|
|
|
|
bool wave_get(uint32_t index, uint32_t pattern) const {
|
|
|
|
return data.get(index, pattern);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Return true if pattern can be placed in cell (i,j)
|
|
|
|
bool wave_get(uint32_t i, uint32_t j, uint32_t pattern) const {
|
|
|
|
return wave_get(i * wave_width + j, pattern);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set the value of pattern in cell index.
|
|
|
|
void wave_set(uint32_t index, uint32_t pattern, bool value);
|
|
|
|
|
|
|
|
// Set the value of pattern in cell (i,j).
|
|
|
|
void wave_set(uint32_t i, uint32_t j, uint32_t pattern, bool value) {
|
|
|
|
wave_set(i * wave_width + j, pattern, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Return the index of the cell with lowest entropy different of 0.
|
|
|
|
// If there is a contradiction in the wave, return -2.
|
|
|
|
// If every cell is decided, return -1.
|
|
|
|
int wave_get_min_entropy() const;
|
|
|
|
|
|
|
|
void add_to_propagator(uint32_t y, uint32_t x, uint32_t pattern) {
|
|
|
|
// All the direction are set to 0, since the pattern cannot be set in (y,x).
|
|
|
|
CompatibilityEntry temp;
|
|
|
|
compatible.get(y, x, pattern) = temp;
|
|
|
|
|
2022-04-22 00:50:57 +02:00
|
|
|
propagating.push_back(PropagatingEntry(y, x, pattern));
|
2022-04-21 23:31:25 +02:00
|
|
|
}
|
|
|
|
|
2022-04-21 23:35:45 +02:00
|
|
|
constexpr uint32_t get_opposite_direction(uint32_t direction) {
|
|
|
|
return 3 - direction;
|
|
|
|
}
|
|
|
|
|
2022-04-21 23:33:21 +02:00
|
|
|
void normalize(Vector<double> &v);
|
|
|
|
Vector<double> get_plogp(const Vector<double> &distribution);
|
|
|
|
double get_min_abs_half(const Vector<double> &v);
|
|
|
|
|
2022-04-21 23:31:25 +02:00
|
|
|
void propagate();
|
|
|
|
|
|
|
|
void initialize();
|
|
|
|
|
2022-04-21 20:00:42 +02:00
|
|
|
WaveFormCollapse();
|
2022-04-21 23:31:25 +02:00
|
|
|
~WaveFormCollapse();
|
2022-04-21 20:00:42 +02:00
|
|
|
|
|
|
|
protected:
|
|
|
|
static void bind_methods();
|
|
|
|
|
2022-04-20 03:05:34 +02:00
|
|
|
private:
|
2022-04-21 23:31:25 +02:00
|
|
|
RandomPCG gen;
|
2022-04-20 03:05:34 +02:00
|
|
|
|
2022-04-20 03:24:50 +02:00
|
|
|
// The number of distinct patterns.
|
2022-04-21 23:31:25 +02:00
|
|
|
size_t nb_patterns;
|
2022-04-20 03:05:34 +02:00
|
|
|
|
2022-04-20 03:24:50 +02:00
|
|
|
// Transform the wave to a valid output (a 2d array of patterns that aren't in
|
|
|
|
// contradiction). This function should be used only when all cell of the wave
|
|
|
|
// are defined.
|
2022-04-21 16:43:04 +02:00
|
|
|
Array2D<uint32_t> wave_to_output() const;
|
2022-04-21 23:31:25 +02:00
|
|
|
|
|
|
|
//Wave
|
|
|
|
uint32_t wave_width;
|
|
|
|
uint32_t wave_height;
|
|
|
|
uint32_t wave_size;
|
|
|
|
|
|
|
|
// The patterns frequencies p given to wfc.
|
|
|
|
Vector<double> patterns_frequencies;
|
|
|
|
|
|
|
|
// The precomputation of p * log(p).
|
|
|
|
Vector<double> plogp_patterns_frequencies;
|
|
|
|
|
|
|
|
// The precomputation of min (p * log(p)) / 2.
|
|
|
|
// This is used to define the maximum value of the noise.
|
|
|
|
double min_abs_half_plogp;
|
|
|
|
|
|
|
|
Vector<double> memoisation_plogp_sum; // The sum of p'(pattern)// log(p'(pattern)).
|
|
|
|
Vector<double> memoisation_sum; // The sum of p'(pattern).
|
|
|
|
Vector<double> memoisation_log_sum; // The log of sum.
|
|
|
|
Vector<uint32_t> memoisation_nb_patterns; // The number of patterns present
|
|
|
|
Vector<double> memoisation_entropy; // The entropy of the cell.
|
|
|
|
|
|
|
|
// This value is set to true if there is a contradiction in the wave (all elements set to false in a cell).
|
|
|
|
bool is_impossible;
|
|
|
|
|
|
|
|
// The actual wave. data.get(index, pattern) is equal to 0 if the pattern can
|
|
|
|
// be placed in the cell index.
|
|
|
|
Array2D<uint8_t> data;
|
|
|
|
|
|
|
|
//Propagator
|
|
|
|
Vector<PropagatorStateEntry> propagator_state;
|
|
|
|
|
|
|
|
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.
|
2022-04-22 00:50:57 +02:00
|
|
|
Vector<PropagatingEntry> propagating;
|
2022-04-21 23:31:25 +02:00
|
|
|
|
|
|
|
// 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<CompatibilityEntry> compatible;
|
|
|
|
|
|
|
|
void init_compatible();
|
2022-04-20 03:05:34 +02:00
|
|
|
};
|
|
|
|
|
2022-04-21 20:00:42 +02:00
|
|
|
#endif
|