sand/src/rule_builder.cpp

96 lines
2.2 KiB
C++

#include "sand/rule_builder.h"
#include "sand/sand.h"
using namespace sand;
// -------------------
// rules datastructure
// -------------------
// `conversions` - possible result types of a rule
// `metas` - refers to slices of `conversions` for a
// specific tile type
// `masks` - bitmask that represents which conversions are
// *invalid* for given tile types (to, from) and a neighbor position
rule rule::builder::add_rule(type from, type to)
{
return rule(*this, from, to);
}
::sand::sand rule::builder::build(uint16_t width, uint16_t height,
type initial)
{
return ::sand::sand(types, conversions, metas, masks, width, height,
initial);
}
rule::builder::builder(type::range types,
const std::vector<type>& default_conversions) :
types(types),
conversions(default_conversions),
metas(types.size()),
masks(types.size() * types.size() * 8, -1U)
{
for (const auto& type : types)
{
metas[type] = { .begin = type, .end = type + 1u };
}
}
void rule::builder::finish_rule(const rule& rule)
{
unsigned int position = insert_conversion(rule.from, rule.to);
for (int i = 0; i < 8; i++)
{
// not wildcard
// ------------
// include `position` only for matching types
if (rule.matches[i])
{
for (const auto& type : types)
{
if (rule.matches[i](type))
{
// mask out default conversion
masks[i + type * 8 + rule.from * types.size() * 8] &= ~(1 << 0);
}
else
{
// mask out rule.to from
masks[i + type * 8 + rule.from * types.size() * 8]
&= ~(1 << position);
}
}
}
}
}
unsigned int rule::builder::get_mask_index(type from, type to)
{
for (int i = metas[from].begin; i < metas[from].end; i++)
{
if (conversions[i] == to)
{
return i;
}
}
return insert_conversion(from, to);
}
unsigned int rule::builder::insert_conversion(type from, type to)
{
uint32_t position = metas[from].end;
metas[from].end += 1;
conversions.insert(conversions.begin() + position, to);
for (auto& meta : metas)
{
if (meta.begin >= position)
{
meta.begin += 1;
meta.end += 1;
}
}
return position - metas[from].begin;
}