96 lines
2.2 KiB
C++
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;
|
|
}
|