#ifndef SAND_H #define SAND_H #include #include #include #include #include namespace sand { struct type { uint16_t id; uint16_t default_result; }; using type_map = std::unordered_map; class RulesBuilder; class TypeBuilder { friend RulesBuilder; public: TypeBuilder(); TypeBuilder& add_type(const std::string& name); TypeBuilder& add_type(const std::string& name, const std::string& default_result); RulesBuilder finish(); private: uint16_t next_type_id = 0; type_map types; }; // class TypeBuilder class Rule; class Sand; class RulesBuilder { friend TypeBuilder; friend Rule; friend Sand; public: Rule add_rule(const std::string& source_name, const std::string& to); Sand build(uint16_t width, uint16_t height, const std::string& initial); private: RulesBuilder(const TypeBuilder& type_builder); void finish_rule(const Rule& rule); type_map types; std::unordered_map>> rules; }; // class RulesBuilder class Rule { friend RulesBuilder; public: using match_fn = std::function; ~Rule(); Rule& top_left(match_fn match); Rule& top_middle(match_fn match); Rule& top_right(match_fn match); Rule& middle_left(match_fn match); Rule& middle_right(match_fn match); Rule& bottom_left(match_fn match); Rule& bottom_middle(match_fn match); Rule& bottom_right(match_fn match); private: Rule(RulesBuilder& builder, uint16_t source, uint16_t to); RulesBuilder& builder; uint16_t source; uint16_t to; match_fn matches[8]; }; // class RuleBuilder class Sand { friend RulesBuilder; public: void set(uint16_t x, uint16_t y, const std::string& type); uint16_t get(uint16_t x, uint16_t y); void update(); private: Sand(const RulesBuilder& builder, uint16_t width, uint16_t height, const std::string& initial); uint16_t apply_rule(uint16_t tile, unsigned __int128 key) const; static unsigned __int128 apply_mask(unsigned __int128 key, uint8_t mask); uint16_t width; uint16_t height; type_map types; std::unordered_map default_conversions; std::unordered_map>> rules; std::vector elements; bool iter; }; // class Sand } // namespace sand #endif // SAND_H