#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& 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; }