#include #include #include "group.h" #include "common.h" #include "type_id.h" namespace klotski { using Common::range_reverse; /// ----------------------------------------- Type ID ----------------------------------------- TypeId::TypeId(uint32_t type_id) { if (type_id >= TYPE_ID_LIMIT) { // invalid type id throw std::invalid_argument("type id overflow"); } type_id_ = type_id; } TypeId::TypeId(const RawCode &raw_code) noexcept { type_id_ = type_id(block_num(raw_code)); } TypeId::TypeId(const CommonCode &common_code) noexcept { type_id_ = type_id(block_num(common_code)); } uint32_t TypeId::type_id(block_num_t &&block_num) noexcept { // block_num_t -> type_id /// flag -> ... 0000 0xxx 0xxx xxxx /// n_x2x n_2x1 n_1x1 auto n_x2x = block_num.n_1x2 + block_num.n_2x1; auto flag = (n_x2x << 8) | (block_num.n_2x1 << 4) | block_num.n_1x1; return std::lower_bound(TYPE_ID_INDEX, TYPE_ID_INDEX + TYPE_ID_LIMIT, flag) - TYPE_ID_INDEX; } /// -------------------------------------- Block Number --------------------------------------- TypeId::block_num_t TypeId::block_num() const noexcept { // type_id -> block_num_t auto flag = TYPE_ID_INDEX[type_id_]; auto n_2x1 = (flag >> 4) & 0b111; return block_num_t { .n_1x1 = static_cast(flag & 0b1111), .n_1x2 = static_cast((flag >> 8) - n_2x1), .n_2x1 = static_cast(n_2x1), }; } TypeId::block_num_t TypeId::block_num(const RawCode &raw_code) noexcept { block_num_t result; auto tmp = raw_code.unwrap(); for (int addr = 0; addr < 20; ++addr, tmp >>= 3) { switch (tmp & 0b111) { case B_1x1: ++result.n_1x1; continue; case B_1x2: ++result.n_1x2; continue; case B_2x1: ++result.n_2x1; continue; } } return result; } TypeId::block_num_t TypeId::block_num(const CommonCode &common_code) noexcept { block_num_t result; auto range = range_reverse(static_cast(common_code.unwrap())); for (; range; range >>= 2) { switch (range & 0b11) { case 0b01: /// 1x2 block ++result.n_1x2; continue; case 0b10: /// 2x1 block ++result.n_2x1; continue; case 0b11: /// 1x1 block ++result.n_1x1; continue; } } return result; } /// ---------------------------------------- Group ID ----------------------------------------- GroupId::GroupId(uint32_t type_id, uint32_t group_id) : type_id_(type_id) { if (group_id >= TYPE_ID_GROUP_NUM[type_id]) { throw std::invalid_argument("group id overflow"); } group_id_ = group_id; } GroupId::GroupId(const TypeId &type_id, uint32_t group_id) : type_id_(type_id) { if (group_id >= TYPE_ID_GROUP_NUM[type_id.unwrap()]) { throw std::invalid_argument("group id overflow"); } group_id_ = group_id; } GroupId::GroupId(const RawCode &raw_code) noexcept : type_id_(TypeId(raw_code)) { group_id_ = group_id(type_id_.unwrap(), GroupId::seed(raw_code)); } GroupId::GroupId(const CommonCode &common_code) noexcept : type_id_(TypeId(common_code)) { group_id_ = group_id(type_id_.unwrap(), GroupId::seed(common_code)); } } // namespace klotski