华容道高性能计算引擎
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

110 lines
3.4 KiB

#include <stdexcept>
#include <algorithm>
#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<uint8_t>(flag & 0b1111),
.n_1x2 = static_cast<uint8_t>((flag >> 8) - n_2x1),
.n_2x1 = static_cast<uint8_t>(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<uint32_t>(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