diff --git a/src/core/all_cases/all_cases.cc b/src/core/all_cases/all_cases.cc index 089f0d5..18ce5fe 100644 --- a/src/core/all_cases/all_cases.cc +++ b/src/core/all_cases/all_cases.cc @@ -8,96 +8,50 @@ using klotski::cases::BasicRanges; using klotski::cases::range_reverse; -uint32_t check_range(uint32_t head, uint32_t range) noexcept { - /// M_1x1 | M_1x2 | M_2x1 | M_2x2 - /// 1 0 0 0 | 1 1 0 0 | 1 0 0 0 | 1 1 0 0 - /// 0 0 0 0 | 0 0 0 0 | 1 0 0 0 | 1 1 0 0 - /// ... | ... | ... | ... - constexpr uint32_t M_1x1 = 0b1; - constexpr uint32_t M_1x2 = 0b11; - constexpr uint32_t M_2x1 = 0b10001; - constexpr uint32_t M_2x2 = 0b110011; - - uint32_t offset = 1; - uint32_t tmp = M_2x2 << head; // fill 2x2 block - for (int addr = 0; range; range >>= 2, ++offset) { // traverse every 2-bits - while ((tmp >> addr) & 0b1) { - ++addr; // search next unfilled block - } - switch (range & 0b11) { - case 0b00: /// space - case 0b11: /// 1x1 block - tmp |= M_1x1 << addr; // fill space or 1x1 block - break; - case 0b10: /// 2x1 block - if (addr > 15 || tmp >> (addr + 4) & 0b1) { // invalid address - return offset; // broken block number - } - tmp |= M_2x1 << addr; // fill 2x1 block - break; - case 0b01: /// 1x2 block - if ((addr & 0b11) == 0b11 || tmp >> (addr + 1) & 0b1) { // invalid address - return offset; // broken block number - } - tmp |= M_1x2 << addr; // fill 1x2 block - break; - } - } - return 0; // pass check +inline int low_zero_num(uint32_t bin) { + return __builtin_ctzl(bin); + + // WARN: be aware of serious performance issues + // return __builtin_popcount(~(bin ^ -bin)) - 1; } -int check_range_v2(int head, uint32_t range) noexcept { +int check_range(int head, uint32_t range) noexcept { constexpr uint32_t MASK_1x1 = 0b00000001; constexpr uint32_t MASK_1x2 = 0b00000011; constexpr uint32_t MASK_2x1 = 0b00010001; constexpr uint32_t MASK_2x2 = 0b00110011; - uint32_t flags = MASK_2x2 << head; - - for (int addr = 0; range; range >>= 2) { - - int nn = __builtin_ctz(~flags); - addr += nn; - flags >>= nn; - + uint32_t flags = MASK_2x2 << head; // fill 2x2 block + for (int addr = 0, offset = 1; range; range >>= 2, ++offset) { // traverse every 2-bit + auto num = low_zero_num(~flags); + addr += num; // next unfilled block + flags >>= num; switch (range & 0b11) { - case 0b00: - case 0b11: + case 0b00: // space + case 0b11: // 1x1 block flags |= MASK_1x1; continue; - case 0b10: - if ((flags >> 4) & 0b1 || addr > 15) { // invalid address - return -1; // broken block number + case 0b10: // 2x1 block + if ((flags >> 4) & 0b1 || addr > 15) { // invalid case + return offset; // broken offset } flags |= MASK_2x1; continue; - case 0b01: - if ((flags >> 1) & 0b1 || (addr & 0b11) == 0b11) { // invalid address - return -1; // broken block number + case 0b01: // 1x2 block + if ((flags >> 1) & 0b1 || (addr & 0b11) == 0b11) { // invalid case + return offset; // broken offset } flags |= MASK_1x2; continue; } } - - return 0; + return 0; // pass check } void demo() { -// std::cout << check_range(1, 0x003F78CE) << std::endl; -// std::cout << check_range_v3(1, 0x003F78CE) << std::endl; -// return; - -// uint32_t demo = 0x61; -// std::cout << __builtin_ctz(demo) << std::endl; -// return; - - // 0xA9BF0C00 -// auto ret = check_range_v2(1, range_reverse(0xA9BF0C00)); -// std::cout << ret << std::endl; +// std::cout << __builtin_popcount(~(6 ^ -6)) - 1 << std::endl; // return; -// std::cout << ret << std::endl; constexpr std::array heads = { 0x0, 0x1, 0x2, @@ -107,33 +61,56 @@ void demo() { }; auto num = 0; + + std::array, 16> data; + + // TODO: vector reserve + + auto basic_ranges = BasicRanges::Instance().Fetch(); + +// std::vector reversed {basic_ranges.begin(), basic_ranges.end()}; +// for (auto &x : reversed) { +// x = range_reverse(x); +// } + for (auto head : heads) { - for (auto x : BasicRanges::Instance().Fetch()) { - if (check_range_v2(head, x) == 0) { - ++num; + for (uint32_t index = 0; index < basic_ranges.size(); ++index) { + auto offset = check_range(head, basic_ranges[index]); + if (offset) { // invalid case + auto tmp = (uint32_t)0b1 << (32 - offset * 2); // distance to next possible range + /// !! <- broken + /// ( xx xx xx ) xx xx xx ... [reversed range] + /// +1 00 00 00 ... (delta) + tmp += range_reverse(basic_ranges[index]) & ~(tmp - 1); + while (range_reverse(basic_ranges[++index]) < tmp); // located next range + --index; + +// next += reversed[index] & ~(next - 1); +// auto kk = std::lower_bound(reversed.begin() + index, reversed.end(), next); +// index = kk - reversed.begin() - 1; + + continue; } - } - } + data[head].emplace_back(range_reverse(basic_ranges[index])); + +// ++index; -// auto basic_ranges = BasicRanges::Instance().Fetch(); -// for (auto head : heads) { -// for (uint32_t index = 0; index < basic_ranges.size(); ++index) { -// auto broken_offset = check_range(head, basic_ranges[index]); -// if (broken_offset) { // case invalid -// auto delta = (uint32_t)1 << (32 - broken_offset * 2); // delta to next possible range -// /// !! -> broken -// /// ( xx xx xx ) xx xx xx ... (reversed range) -// /// +1 00 00 00 ... (delta) -// auto at_least = (range_reverse(basic_ranges[index]) & ~(delta - 1)) + delta; -// while (range_reverse(basic_ranges[++index]) < at_least); // located next range -// --index; -// continue; -// } + ++num; // volatile auto r = range_reverse(basic_ranges[index]); // release valid cases -// } + } + } + +// for (auto &x : data) { +// std::cout << x.size() << std::endl; // } + for (uint64_t head = 0; head < 15; ++head) { + for (auto x : data[head]) { + printf("%09llX\n", (head << 32) | x); + } + } + // std::cout << num << std::endl; }