192 lines
6.4 KiB
C++
192 lines
6.4 KiB
C++
/**
|
|
* @brief Example demonstrating custom random selectors in WFC
|
|
*
|
|
* This example shows how to use different random selection strategies
|
|
* in the Wave Function Collapse algorithm, including:
|
|
* - Default constexpr random selector
|
|
* - Advanced random selector with std::mt19937
|
|
* - Custom lambda-based selectors
|
|
*/
|
|
|
|
#include <iostream>
|
|
#include <vector>
|
|
#include <array>
|
|
#include <random>
|
|
|
|
#include "../include/nd-wfc/wfc.hpp"
|
|
|
|
// Simple test world for demonstration
|
|
struct SimpleWorld {
|
|
using ValueType = int;
|
|
std::vector<int> data;
|
|
size_t grid_size;
|
|
|
|
SimpleWorld(size_t size) : data(size * size, 0), grid_size(size) {}
|
|
size_t size() const { return data.size(); }
|
|
void setValue(size_t id, int value) { data[id] = value; }
|
|
int getValue(size_t id) const { return data[id]; }
|
|
|
|
void print() const {
|
|
for (size_t i = 0; i < grid_size; ++i) {
|
|
for (size_t j = 0; j < grid_size; ++j) {
|
|
std::cout << data[i * grid_size + j] << " ";
|
|
}
|
|
std::cout << std::endl;
|
|
}
|
|
}
|
|
};
|
|
|
|
int main() {
|
|
std::cout << "=== WFC Random Selector Examples ===\n\n";
|
|
|
|
// Example 1: Using the default constexpr random selector
|
|
std::cout << "1. Default Random Selector (constexpr-friendly):\n";
|
|
{
|
|
WFC::DefaultRandomSelector<int> selector(0x12345678);
|
|
|
|
// Test with some sample values
|
|
std::array<int, 4> values = {1, 2, 3, 4};
|
|
std::span<const int> span(values.data(), values.size());
|
|
|
|
std::cout << "Possible values: ";
|
|
for (int v : values) std::cout << v << " ";
|
|
std::cout << "\nSelected indices: ";
|
|
|
|
for (int i = 0; i < 8; ++i) {
|
|
size_t index = selector(span);
|
|
std::cout << index << "(" << values[index] << ") ";
|
|
}
|
|
std::cout << "\n\n";
|
|
}
|
|
|
|
// Example 2: Using the advanced random selector
|
|
std::cout << "2. Advanced Random Selector (std::mt19937):\n";
|
|
{
|
|
std::mt19937 rng(54321);
|
|
WFC::AdvancedRandomSelector<int> selector(rng);
|
|
|
|
std::array<int, 5> values = {10, 20, 30, 40, 50};
|
|
std::span<const int> span(values.data(), values.size());
|
|
|
|
std::cout << "Possible values: ";
|
|
for (int v : values) std::cout << v << " ";
|
|
std::cout << "\nSelected values: ";
|
|
|
|
for (int i = 0; i < 10; ++i) {
|
|
size_t index = selector(span);
|
|
std::cout << values[index] << " ";
|
|
}
|
|
std::cout << "\n\n";
|
|
}
|
|
|
|
// Example 3: Custom lambda selector that always picks the first element
|
|
std::cout << "3. Custom Lambda Selector (always first):\n";
|
|
{
|
|
auto firstSelector = [](std::span<const int> values) -> size_t {
|
|
return 0; // Always pick first
|
|
};
|
|
|
|
std::array<int, 3> values = {100, 200, 300};
|
|
std::span<const int> span(values.data(), values.size());
|
|
|
|
std::cout << "Possible values: ";
|
|
for (int v : values) std::cout << v << " ";
|
|
std::cout << "\nSelected values: ";
|
|
|
|
for (int i = 0; i < 5; ++i) {
|
|
size_t index = firstSelector(span);
|
|
std::cout << values[index] << " ";
|
|
}
|
|
std::cout << "\n\n";
|
|
}
|
|
|
|
// Example 4: Stateful lambda selector with captured variables
|
|
std::cout << "4. Stateful Lambda Selector (round-robin):\n";
|
|
{
|
|
int callCount = 0;
|
|
auto roundRobinSelector = [&callCount](std::span<const int> values) mutable -> size_t {
|
|
return callCount++ % values.size();
|
|
};
|
|
|
|
std::array<int, 3> values = {1, 2, 3};
|
|
std::span<const int> span(values.data(), values.size());
|
|
|
|
std::cout << "Possible values: ";
|
|
for (int v : values) std::cout << v << " ";
|
|
std::cout << "\nRound-robin selection: ";
|
|
|
|
for (int i = 0; i < 9; ++i) {
|
|
size_t index = roundRobinSelector(span);
|
|
std::cout << values[index] << " ";
|
|
}
|
|
std::cout << "\n\n";
|
|
}
|
|
|
|
// Example 5: Custom selector with probability weighting
|
|
std::cout << "5. Weighted Random Selector:\n";
|
|
{
|
|
std::mt19937 rng(99999);
|
|
auto weightedSelector = [&rng](std::span<const int> values) -> size_t {
|
|
// Simple weighted selection - favor earlier indices
|
|
std::vector<double> weights;
|
|
for (size_t i = 0; i < values.size(); ++i) {
|
|
weights.push_back(1.0 / (i + 1.0)); // Higher weight for lower indices
|
|
}
|
|
|
|
std::discrete_distribution<size_t> dist(weights.begin(), weights.end());
|
|
return dist(rng);
|
|
};
|
|
|
|
std::array<int, 4> values = {1, 2, 3, 4};
|
|
std::span<const int> span(values.data(), values.size());
|
|
|
|
std::cout << "Possible values: ";
|
|
for (int v : values) std::cout << v << " ";
|
|
std::cout << "\nWeighted selection ( favors lower values): ";
|
|
|
|
for (int i = 0; i < 12; ++i) {
|
|
size_t index = weightedSelector(span);
|
|
std::cout << values[index] << " ";
|
|
}
|
|
std::cout << "\n\n";
|
|
}
|
|
|
|
// Example 6: Integration with WFC Builder
|
|
std::cout << "6. WFC Builder Integration:\n";
|
|
{
|
|
// Define a simple WFC setup with custom random selector
|
|
using VariableMap = WFC::VariableIDMap<int, 0, 1, 2, 3>;
|
|
|
|
// Using default random selector
|
|
using DefaultWFC = WFC::Builder<SimpleWorld, int, VariableMap>
|
|
::SetRandomSelector<WFC::DefaultRandomSelector<int>>
|
|
::Build;
|
|
|
|
// Using advanced random selector
|
|
using AdvancedWFC = WFC::Builder<SimpleWorld, int, VariableMap>
|
|
::SetRandomSelector<WFC::AdvancedRandomSelector<int>>
|
|
::Build;
|
|
|
|
// Note: Lambda types cannot be used directly as template parameters
|
|
// Instead, you would create a custom selector class:
|
|
// class CustomSelector {
|
|
// public:
|
|
// size_t operator()(std::span<const int> values) const {
|
|
// return values.size() > 1 ? 1 : 0;
|
|
// }
|
|
// };
|
|
// using CustomWFC = WFC::Builder<SimpleWorld, int, VariableMap>
|
|
// ::SetRandomSelector<CustomSelector>
|
|
// ::Build;
|
|
|
|
std::cout << "Successfully created WFC types with different random selectors:\n";
|
|
std::cout << "- DefaultWFC with DefaultRandomSelector\n";
|
|
std::cout << "- AdvancedWFC with AdvancedRandomSelector\n";
|
|
std::cout << "- Custom selector classes can be created for lambda-like behavior\n";
|
|
}
|
|
|
|
std::cout << "\n=== Examples completed successfully! ===\n";
|
|
|
|
return 0;
|
|
}
|