bugfix std::integral
This commit is contained in:
@@ -28,7 +28,7 @@ namespace WFC {
|
|||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
concept WorldType = requires(T world, typename T::ValueType value) {
|
concept WorldType = requires(T world, typename T::ValueType value) {
|
||||||
{ world.size() } -> std::is_integral;
|
{ world.size() } -> std::integral;
|
||||||
{ world.setValue(static_cast<decltype(world.size())>(0), value) };
|
{ world.setValue(static_cast<decltype(world.size())>(0), value) };
|
||||||
{ world.getValue(static_cast<decltype(world.size())>(0)) } -> std::convertible_to<typename T::ValueType>;
|
{ world.getValue(static_cast<decltype(world.size())>(0)) } -> std::convertible_to<typename T::ValueType>;
|
||||||
typename T::ValueType;
|
typename T::ValueType;
|
||||||
@@ -48,7 +48,7 @@ template<typename WorldT, typename VarT,
|
|||||||
typename VariableIDMapT = VariableIDMap<VarT>,
|
typename VariableIDMapT = VariableIDMap<VarT>,
|
||||||
typename ConstrainerFunctionMapT = ConstrainerFunctionMap<void*>,
|
typename ConstrainerFunctionMapT = ConstrainerFunctionMap<void*>,
|
||||||
typename CallbacksT = Callbacks<WorldT>,
|
typename CallbacksT = Callbacks<WorldT>,
|
||||||
typename RandomSelectorT = DefaultRandomSelector<VarT>,
|
typename RandomSelectorT = DefaultRandomSelector<VarT>
|
||||||
>
|
>
|
||||||
class WFC {
|
class WFC {
|
||||||
public:
|
public:
|
||||||
@@ -189,61 +189,56 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static WorldSizeT FindMinimumEntropyCells(std::span<VariableIDT>& buffer, WaveType& wave)
|
static bool Branch(SolverState& state, WaveType& wave)
|
||||||
{
|
{
|
||||||
auto entropyGetter = [&wave](size_t index) -> size_t { return wave.Entropy(index); };
|
constexpr_assert(state.m_propagationQueue.empty());
|
||||||
auto entropyFilter = [&wave](size_t entropy) -> bool { return entropy > 1; };
|
|
||||||
auto minEntropyCell = *std::ranges::min_element(std::views::iota(0, wave.size()) | std::views::transform(entropyGetter) | std::views::filter(entropyFilter));
|
// Find cell with minimum entropy > 1
|
||||||
|
WorldSizeT minEntropyCell = static_cast<WorldSizeT>(-1);
|
||||||
|
size_t minEntropy = static_cast<size_t>(-1);
|
||||||
|
|
||||||
|
for (WorldSizeT i = 0; i < wave.size(); ++i) {
|
||||||
|
size_t entropy = wave.Entropy(i);
|
||||||
|
if (entropy > 1 && entropy < minEntropy) {
|
||||||
|
minEntropy = entropy;
|
||||||
|
minEntropyCell = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (minEntropyCell == static_cast<WorldSizeT>(-1)) return false;
|
||||||
|
|
||||||
constexpr_assert(!wave.IsCollapsed(minEntropyCell));
|
constexpr_assert(!wave.IsCollapsed(minEntropyCell));
|
||||||
|
|
||||||
// create a list of possible values
|
// create a list of possible values
|
||||||
VariableIDT availableValues = wave.Entropy(minEntropyCell);
|
VariableIDT availableValues = static_cast<VariableIDT>(wave.Entropy(minEntropyCell));
|
||||||
|
std::array<VariableIDT, VariableIDMapT::size()> possibleValues{};
|
||||||
MaskType mask = wave.GetMask(minEntropyCell);
|
MaskType mask = wave.GetMask(minEntropyCell);
|
||||||
for (size_t i = 0; i < availableValues; ++i)
|
for (size_t i = 0; i < availableValues; ++i)
|
||||||
{
|
{
|
||||||
VariableIDT index = static_cast<VariableIDT>(std::countr_zero(mask)); // get the index of the lowest set bit
|
VariableIDT index = static_cast<VariableIDT>(std::countr_zero(mask)); // get the index of the lowest set bit
|
||||||
constexpr_assert(index < VariableIDMapT::size(), "Possible value went outside bounds");
|
constexpr_assert(index < VariableIDMapT::size(), "Possible value went outside bounds");
|
||||||
|
|
||||||
buffer[i] = index;
|
possibleValues[i] = index;
|
||||||
constexpr_assert(((mask & (MaskType(1) << index)) != 0), "Possible value was not set");
|
constexpr_assert(((mask & (MaskType(1) << index)) != 0), "Possible value was not set");
|
||||||
|
|
||||||
mask = mask & (mask - 1); // turn off lowest set bit
|
mask = mask & (mask - 1); // turn off lowest set bit
|
||||||
}
|
}
|
||||||
|
|
||||||
return minEntropyCell;
|
|
||||||
}
|
|
||||||
|
|
||||||
using RandomGeneratorReturnType = decltype(RandomSelectorT{}.rng(static_cast<uint32_t>(1)));
|
|
||||||
|
|
||||||
static bool Branch(SolverState& state, WaveType& wave)
|
|
||||||
{
|
|
||||||
constexpr_assert(state.m_propagationQueue.empty());
|
|
||||||
|
|
||||||
std::array<VariableIDT, VariableIDMapT::size()> Buffer{};
|
|
||||||
WorldSizeT minEntropyCell{};
|
|
||||||
|
|
||||||
minEntropyCell = FindMinimumEntropyCells(Buffer, wave);
|
|
||||||
|
|
||||||
// randomly select a value from possible values
|
// randomly select a value from possible values
|
||||||
while (Buffer.size())
|
while (availableValues)
|
||||||
{
|
{
|
||||||
size_t randomIndex;
|
size_t randomIndex = state.m_randomSelector.rng(availableValues);
|
||||||
VariableIDT selectedValue;
|
VariableIDT selectedValue = possibleValues[randomIndex];
|
||||||
|
|
||||||
randomIndex = state.m_randomSelector.rng(Buffer.size());
|
|
||||||
selectedValue = Buffer[randomIndex];
|
|
||||||
|
|
||||||
{
|
{
|
||||||
// copy the state and branch out
|
// copy the state and branch out
|
||||||
auto stackFrame = state.m_allocator.createFrame();
|
auto stackFrame = state.m_allocator.createFrame();
|
||||||
auto queueFrame = state.m_propagationQueue.createBranchPoint();
|
auto queueFrame = state.m_propagationQueue.createBranchPoint();
|
||||||
|
|
||||||
auto newWave = wave;
|
auto newWave = wave;
|
||||||
CollapseCell(state, newWave, minEntropyCell, selectedValue);
|
CollapseCell(state, newWave, minEntropyCell, selectedValue);
|
||||||
state.m_propagationQueue.push(minEntropyCell);
|
state.m_propagationQueue.push(minEntropyCell);
|
||||||
|
|
||||||
if (RunLoop(state, newWave))
|
if (RunLoop(state, newWave))
|
||||||
{
|
{
|
||||||
// move the solution to the original state
|
// move the solution to the original state
|
||||||
wave = newWave;
|
wave = newWave;
|
||||||
@@ -258,8 +253,7 @@ private:
|
|||||||
constexpr_assert((wave.GetMask(minEntropyCell) & (MaskType(1) << selectedValue)) == 0, "Wave was not collapsed correctly");
|
constexpr_assert((wave.GetMask(minEntropyCell) & (MaskType(1) << selectedValue)) == 0, "Wave was not collapsed correctly");
|
||||||
|
|
||||||
// swap replacement value with the last value
|
// swap replacement value with the last value
|
||||||
std::swap(Buffer[randomIndex], Buffer[Buffer.size() - 1]);
|
std::swap(possibleValues[randomIndex], possibleValues[--availableValues]);
|
||||||
Buffer = Buffer.subspan(0, Buffer.size() - 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@@ -278,7 +272,7 @@ private:
|
|||||||
VariableIDT variableID = wave.GetVariableID(cellId);
|
VariableIDT variableID = wave.GetVariableID(cellId);
|
||||||
ConstrainerType constrainer(wave, state.m_propagationQueue);
|
ConstrainerType constrainer(wave, state.m_propagationQueue);
|
||||||
|
|
||||||
using ConstrainerFunctionPtrT = void(*)(WorldT&, WorldSizeT, WorldValue<VarT>, ConstrainerType&);
|
using ConstrainerFunctionPtrT = void(*)(WorldT&, size_t, WorldValue<VarT>, ConstrainerType&);
|
||||||
|
|
||||||
ConstrainerFunctionMapT::template GetFunction<ConstrainerFunctionPtrT>(variableID)(state.m_world, cellId, WorldValue<VarT>{VariableIDMapT::GetValue(variableID), variableID}, constrainer);
|
ConstrainerFunctionMapT::template GetFunction<ConstrainerFunctionPtrT>(variableID)(state.m_world, cellId, WorldValue<VarT>{VariableIDMapT::GetValue(variableID), variableID}, constrainer);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user