random generator bugfix
This commit is contained in:
@@ -47,27 +47,39 @@ int main() {
|
|||||||
|
|
||||||
auto [x, y] = world.getCoord(index);
|
auto [x, y] = world.getCoord(index);
|
||||||
|
|
||||||
|
// enable walls in 3x3 area around floor (without center)
|
||||||
|
// must come before Exclude to avoid collapsing then un-collapsing cells
|
||||||
|
for (int dy = -1; dy <= 1; ++dy) {
|
||||||
|
for (int dx = -1; dx <= 1; ++dx) {
|
||||||
|
if (dx == 0 && dy == 0) continue;
|
||||||
|
constrainer.template Include<Tile::Wall>(world.getCoordOffset(x, y, dx, dy));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// floor cannot be adjacent to empty space
|
// floor cannot be adjacent to empty space
|
||||||
constrainer.template Exclude<Tile::Empty>(world.getCoordOffset(x, y, -1, 0)); // Left
|
constrainer.template Exclude<Tile::Empty>(world.getCoordOffset(x, y, -1, 0)); // Left
|
||||||
constrainer.template Exclude<Tile::Empty>(world.getCoordOffset(x, y, 1, 0)); // Right
|
constrainer.template Exclude<Tile::Empty>(world.getCoordOffset(x, y, 1, 0)); // Right
|
||||||
constrainer.template Exclude<Tile::Empty>(world.getCoordOffset(x, y, 0, -1)); // Up
|
constrainer.template Exclude<Tile::Empty>(world.getCoordOffset(x, y, 0, -1)); // Up
|
||||||
constrainer.template Exclude<Tile::Empty>(world.getCoordOffset(x, y, 0, 1)); // Down
|
constrainer.template Exclude<Tile::Empty>(world.getCoordOffset(x, y, 0, 1)); // Down
|
||||||
})>
|
})>
|
||||||
::SetInitialState<decltype([](World& world, auto& constrainer, auto& rng) constexpr {
|
::SetInitialState<decltype([](World& world, auto& constrainer, auto&) constexpr {
|
||||||
|
// disable walls everywhere by default
|
||||||
|
for (size_t i = 0; i < world.size(); ++i) {
|
||||||
|
constrainer.template Exclude<Tile::Wall>(i);
|
||||||
|
}
|
||||||
// make it impossible for the edge to be floor
|
// make it impossible for the edge to be floor
|
||||||
for (size_t x = 0; x < world.width(); ++x) {
|
for (size_t x = 0; x < world.width(); ++x) {
|
||||||
constrainer.template Exclude<Tile::Floor>(world.getId({static_cast<int>(x), 0}));
|
constrainer.template Exclude<Tile::Floor>(world.getId({static_cast<int>(x), 0}));
|
||||||
constrainer.template Exclude<Tile::Floor>(world.getId({static_cast<int>(x), static_cast<int>(world.height() - 1)}));
|
constrainer.template Exclude<Tile::Floor>(world.getId({static_cast<int>(x), static_cast<int>(world.height() - 1)}));
|
||||||
}
|
}
|
||||||
for (size_t y = 0; y < world.height(); ++y) {
|
// seed floor tiles to kick-start dungeon generation
|
||||||
constrainer.template Exclude<Tile::Wall>(world.getId({0, static_cast<int>(y)}));
|
constrainer.template Only<Tile::Floor>(world.getId({2, 2}));
|
||||||
constrainer.template Exclude<Tile::Wall>(world.getId({static_cast<int>(world.width() - 1), static_cast<int>(y)}));
|
|
||||||
}
|
|
||||||
})>
|
})>
|
||||||
|
::SetRandomSelector<WFC::AdvancedRandomSelector<Tile>>
|
||||||
::Build;
|
::Build;
|
||||||
|
|
||||||
World world{};
|
World world{};
|
||||||
bool success = WFC::Run<DungeonBuilder>(world, 0xDEADBEEF);
|
bool success = WFC::Run<DungeonBuilder>(world, std::random_device{}());
|
||||||
if (!success) {
|
if (!success) {
|
||||||
std::cout << "WFC solver failed!\n";
|
std::cout << "WFC solver failed!\n";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -117,6 +117,23 @@ public:
|
|||||||
ApplyMask(cellId, 1 << value.InternalIndex);
|
ApplyMask(cellId, 1 << value.InternalIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Re-enable specific values for a cell (OR bits back in)
|
||||||
|
* @param cellId The ID of the cell to modify
|
||||||
|
*/
|
||||||
|
template <typename IDMapT::Type ... IncludedValues>
|
||||||
|
void Include(size_t cellId) {
|
||||||
|
static_assert(sizeof...(IncludedValues) > 0, "At least one included value must be provided");
|
||||||
|
if (m_wave.IsCollapsed(cellId)) return; // don't un-collapse decided cells
|
||||||
|
auto indices = IDMapT::template ValuesToIndices<IncludedValues...>();
|
||||||
|
m_wave.Enable(cellId, BitContainerT::GetMask(indices));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Include(WorldValue<typename IDMapT::Type> value, size_t cellId) {
|
||||||
|
if (m_wave.IsCollapsed(cellId)) return;
|
||||||
|
m_wave.Enable(cellId, 1 << value.InternalIndex);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void ApplyMask(size_t cellId, MaskType mask) {
|
void ApplyMask(size_t cellId, MaskType mask) {
|
||||||
bool wasCollapsed = m_wave.IsCollapsed(cellId);
|
bool wasCollapsed = m_wave.IsCollapsed(cellId);
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <random>
|
||||||
|
|
||||||
namespace WFC {
|
namespace WFC {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -27,14 +29,14 @@ public:
|
|||||||
template <typename VarT>
|
template <typename VarT>
|
||||||
class AdvancedRandomSelector {
|
class AdvancedRandomSelector {
|
||||||
private:
|
private:
|
||||||
std::mt19937& m_rng;
|
mutable std::mt19937 m_rng;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit AdvancedRandomSelector(std::mt19937& rng) : m_rng(rng) {}
|
explicit AdvancedRandomSelector(uint32_t seed = 0x12345678) : m_rng(seed) {}
|
||||||
|
|
||||||
uint32_t rng(uint32_t max) const {
|
uint32_t rng(uint32_t max) const {
|
||||||
std::uniform_int_distribution<uint32_t> dist(0, max);
|
std::uniform_int_distribution<uint32_t> dist(0, max - 1);
|
||||||
return dist(m_rng);
|
return dist(m_rng);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ public:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
void Collapse(size_t index, ElementT mask) { m_data[index] &= mask; }
|
void Collapse(size_t index, ElementT mask) { m_data[index] &= mask; }
|
||||||
|
void Enable(size_t index, ElementT mask) { m_data[index] |= mask; }
|
||||||
size_t size() const { return m_data.size(); }
|
size_t size() const { return m_data.size(); }
|
||||||
size_t Entropy(size_t index) const { return std::popcount(m_data[index]); }
|
size_t Entropy(size_t index) const { return std::popcount(m_data[index]); }
|
||||||
bool IsCollapsed(size_t index) const { return Entropy(index) == 1; }
|
bool IsCollapsed(size_t index) const { return Entropy(index) == 1; }
|
||||||
|
|||||||
Reference in New Issue
Block a user