mirror of https://github.com/dnomd343/klotski.git
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.
408 lines
14 KiB
408 lines
14 KiB
#include <iostream>
|
|
|
|
#include "mover/s2_mover.h"
|
|
#include "raw_code/raw_code.h"
|
|
|
|
using klotski::mover::S2Mover;
|
|
using klotski::codec::RawCode;
|
|
|
|
#define APPLY_MASK(code, addr, mask) \
|
|
(((code) >> ((addr) * 3)) & (uint64_t)(mask))
|
|
|
|
#define UNSET_1x1(code, addr) \
|
|
((code) & ~((uint64_t)0b111 << ((addr) * 3)))
|
|
|
|
#define SET_1x1(code, addr) \
|
|
((code) | ((uint64_t)0b011 << ((addr) * 3)))
|
|
|
|
#define UNSET_1x2(code, addr) \
|
|
((code) & ~((uint64_t)0b111'111 << ((addr) * 3)))
|
|
|
|
#define SET_1x2(code, addr) \
|
|
((code) | ((uint64_t)0b111'001 << ((addr) * 3)))
|
|
|
|
#define UNSET_2x1(code, addr) \
|
|
((code) & ~((uint64_t)0b111'000'000'000'111 << ((addr) * 3)))
|
|
|
|
#define SET_2x1(code, addr) \
|
|
((code) | ((uint64_t)0b111'000'000'000'010 << ((addr) * 3)))
|
|
|
|
#define UNSET_2x2(code, addr) \
|
|
((code) & ~((uint64_t)0b111'111'000'000'111'111 << ((addr) * 3)))
|
|
|
|
#define SET_2x2(code, addr) \
|
|
((code) | ((uint64_t)0b111'111'000'000'111'100 << ((addr) * 3)))
|
|
|
|
void S2Mover::two_space_a(uint64_t code, int offset) const {
|
|
// ---------------- case up ----------------
|
|
|
|
do {
|
|
if (offset >= 4) {
|
|
const uint8_t up_c = APPLY_MASK(code, offset - 4, 0b111);
|
|
if (up_c == BLOCK_1x2) {
|
|
release_(SET_1x2(UNSET_1x2(code, offset - 4), offset));
|
|
break;
|
|
}
|
|
if (up_c == BLOCK_1x1) {
|
|
const auto tmp = UNSET_1x1(code, offset - 4);
|
|
release_(SET_1x1(tmp, offset));
|
|
release_(SET_1x1(tmp, offset + 1));
|
|
// -> check right
|
|
} else if (up_c == BLOCK_fill) {
|
|
if (offset >= 8) {
|
|
const uint8_t up_a = APPLY_MASK(code, offset - 8, 0b111);
|
|
if (up_a == BLOCK_2x2) {
|
|
release_(SET_2x2(UNSET_2x2(code, offset - 8), offset - 4));
|
|
break;
|
|
}
|
|
if (up_a == BLOCK_2x1) {
|
|
release_(SET_2x1(UNSET_2x1(code, offset - 8), offset - 4));
|
|
// -> check right
|
|
}
|
|
}
|
|
// -> check right
|
|
} else {
|
|
std::unreachable();
|
|
}
|
|
|
|
const uint8_t up_d = APPLY_MASK(code, offset - 3, 0b111);
|
|
if (up_d == BLOCK_1x1) {
|
|
const auto tmp = UNSET_1x1(code, offset - 3);
|
|
release_(SET_1x1(tmp, offset + 1));
|
|
release_(SET_1x1(tmp, offset));
|
|
break;
|
|
}
|
|
if (up_d == BLOCK_fill) {
|
|
if (offset >= 8) {
|
|
const uint8_t up_b = APPLY_MASK(code, offset - 7, 0b111);
|
|
if (up_b == BLOCK_2x1) {
|
|
release_(SET_2x1(UNSET_2x1(code, offset - 7), offset - 3));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} while (false);
|
|
|
|
// ---------------- case down ----------------
|
|
|
|
do {
|
|
if (offset < 16) {
|
|
const uint8_t down_a = APPLY_MASK(code, offset + 4, 0b111);
|
|
if (down_a == BLOCK_1x2) {
|
|
release_(SET_1x2(UNSET_1x2(code, offset + 4), offset));
|
|
break;
|
|
}
|
|
if (down_a == BLOCK_2x2) {
|
|
release_(SET_2x2(UNSET_2x2(code, offset + 4), offset));
|
|
break;
|
|
}
|
|
|
|
if (down_a == BLOCK_2x1) {
|
|
release_(SET_2x1(UNSET_2x1(code, offset + 4), offset));
|
|
} else if (down_a == BLOCK_1x1) {
|
|
const auto tmp = UNSET_1x1(code, offset + 4);
|
|
release_(SET_1x1(tmp, offset));
|
|
release_(SET_1x1(tmp, offset + 1));
|
|
}
|
|
|
|
const uint8_t down_b = APPLY_MASK(code, offset + 5, 0b111);
|
|
if (down_b == BLOCK_1x1) {
|
|
const auto tmp = UNSET_1x1(code, offset + 5);
|
|
release_(SET_1x1(tmp, offset + 1));
|
|
release_(SET_1x1(tmp, offset));
|
|
break;
|
|
}
|
|
if (down_b == BLOCK_2x1) {
|
|
release_(SET_2x1(UNSET_2x1(code, offset + 5), offset + 1));
|
|
break;
|
|
}
|
|
}
|
|
} while (false);
|
|
|
|
// ---------------- case left ----------------
|
|
|
|
do {
|
|
if ((offset % 4) != 0) { // 1x1
|
|
if (APPLY_MASK(code, offset - 1, 0b111) == 0b011) {
|
|
release_(SET_1x1(UNSET_1x1(code, offset - 1), offset));
|
|
release_(SET_1x1(UNSET_1x1(code, offset - 1), offset + 1));
|
|
break;
|
|
}
|
|
}
|
|
if ((offset % 4) == 2) { // 1x2
|
|
if (APPLY_MASK(code, offset - 2, 0b111'111) == 0b111'001) {
|
|
release_(SET_1x2(UNSET_1x2(code, offset - 2), offset - 1));
|
|
release_(SET_1x2(UNSET_1x2(code, offset - 2), offset));
|
|
break;
|
|
}
|
|
}
|
|
} while (false);
|
|
|
|
// ---------------- case right ----------------
|
|
|
|
do {
|
|
if ((offset % 4) != 2) { // 1x1
|
|
if (APPLY_MASK(code, offset + 2, 0b111) == 0b011) {
|
|
release_(SET_1x1(UNSET_1x1(code, offset + 2), offset + 1));
|
|
release_(SET_1x1(UNSET_1x1(code, offset + 2), offset));
|
|
break;
|
|
}
|
|
}
|
|
if ((offset % 4) == 0) { // 1x2
|
|
if (APPLY_MASK(code, offset + 2, 0b111'111) == 0b111'001) {
|
|
release_(SET_1x2(UNSET_1x2(code, offset + 2), offset + 1));
|
|
release_(SET_1x2(UNSET_1x2(code, offset + 2), offset));
|
|
break;
|
|
}
|
|
}
|
|
} while (false);
|
|
}
|
|
|
|
void S2Mover::two_space_b(uint64_t code, int offset) const {
|
|
// ---------------- case up ----------------
|
|
|
|
do {
|
|
if (offset >= 4) {
|
|
if (APPLY_MASK(code, offset - 4, 0b111) == 0b011) { // 1x1
|
|
release_(SET_1x1(UNSET_1x1(code, offset - 4), offset));
|
|
release_(SET_1x1(UNSET_1x1(code, offset - 4), offset + 4));
|
|
break;
|
|
}
|
|
}
|
|
if (offset >= 8) {
|
|
if (APPLY_MASK(code, offset - 8, 0b111'000'000'000'111) == 0b111'000'000'000'010) { // 2x1
|
|
release_(SET_2x1(UNSET_2x1(code, offset - 8), offset - 4));
|
|
release_(SET_2x1(UNSET_2x1(code, offset - 8), offset));
|
|
break;
|
|
}
|
|
}
|
|
} while (false);
|
|
|
|
// ---------------- case down ----------------
|
|
|
|
do {
|
|
if (offset < 12) {
|
|
if (APPLY_MASK(code, offset + 8, 0b111) == 0b011) { // 1x1
|
|
release_(SET_1x1(UNSET_1x1(code, offset + 8), offset + 4));
|
|
release_(SET_1x1(UNSET_1x1(code, offset + 8), offset));
|
|
break;
|
|
}
|
|
}
|
|
if (offset < 8) {
|
|
if (APPLY_MASK(code, offset + 8, 0b111'000'000'000'111) == 0b111'000'000'000'010) { // 2x1
|
|
release_(SET_2x1(UNSET_2x1(code, offset + 8), offset + 4));
|
|
release_(SET_2x1(UNSET_2x1(code, offset + 8), offset));
|
|
break;
|
|
}
|
|
}
|
|
} while (false);
|
|
|
|
// ---------------- case left ----------------
|
|
|
|
do {
|
|
if ((offset % 4) != 0) {
|
|
const uint8_t left_b = APPLY_MASK(code, offset - 1, 0b111);
|
|
if (left_b == BLOCK_2x1) {
|
|
release_(SET_2x1(UNSET_2x1(code, offset - 1), offset));
|
|
break;
|
|
}
|
|
if (left_b == BLOCK_1x1) {
|
|
const auto tmp = UNSET_1x1(code, offset - 1);
|
|
release_(SET_1x1(tmp, offset));
|
|
release_(SET_1x1(tmp, offset + 4));
|
|
// -> check down
|
|
} else if (left_b == BLOCK_fill) {
|
|
if ((offset % 4) >= 2) {
|
|
const uint8_t left_d = APPLY_MASK(code, offset - 2, 0b111);
|
|
if (left_d == BLOCK_2x2) {
|
|
release_(SET_2x2(UNSET_2x2(code, offset - 2), offset - 1));
|
|
break;
|
|
}
|
|
if (left_d == BLOCK_1x2) {
|
|
release_(SET_1x2(UNSET_1x2(code, offset - 2), offset - 1));
|
|
// -> check down
|
|
}
|
|
}
|
|
// -> check down
|
|
} else {
|
|
std::unreachable();
|
|
}
|
|
|
|
const uint8_t left_d = APPLY_MASK(code, offset + 3, 0b111);
|
|
if (left_d == BLOCK_1x1) {
|
|
const auto tmp = UNSET_1x1(code, offset + 3);
|
|
release_(SET_1x1(tmp, offset + 4));
|
|
release_(SET_1x1(tmp, offset));
|
|
break;
|
|
}
|
|
if (left_d == BLOCK_fill) {
|
|
if ((offset % 4) >= 2) {
|
|
const uint8_t left_c = APPLY_MASK(code, offset + 2, 0b111);
|
|
if (left_c == BLOCK_1x2) {
|
|
release_(SET_1x2(UNSET_1x2(code, offset + 2), offset + 3));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} while (false);
|
|
|
|
// ---------------- case right ----------------
|
|
|
|
do {
|
|
if ((offset % 4) != 3) {
|
|
const uint8_t right_a = APPLY_MASK(code, offset + 1, 0b111);
|
|
if (right_a == BLOCK_2x1) {
|
|
release_(SET_2x1(UNSET_2x1(code, offset + 1), offset));
|
|
break;
|
|
}
|
|
if (right_a == BLOCK_2x2) {
|
|
release_(SET_2x2(UNSET_2x2(code, offset + 1), offset));
|
|
break;
|
|
}
|
|
if (right_a == BLOCK_1x2) {
|
|
release_(SET_1x2(UNSET_1x2(code, offset + 1), offset));
|
|
} else if (right_a == BLOCK_1x1) {
|
|
const auto tmp = UNSET_1x1(code, offset + 1);
|
|
release_(SET_1x1(tmp, offset));
|
|
release_(SET_1x1(tmp, offset + 4));
|
|
}
|
|
|
|
const uint8_t right_c = APPLY_MASK(code, offset + 5, 0b111);
|
|
if (right_c == BLOCK_1x1) {
|
|
const auto tmp = UNSET_1x1(code, offset + 5);
|
|
release_(SET_1x1(tmp, offset + 4));
|
|
release_(SET_1x1(tmp, offset));
|
|
break;
|
|
}
|
|
if (right_c == BLOCK_1x2) {
|
|
release_(SET_1x2(UNSET_1x2(code, offset + 5), offset + 4));
|
|
break;
|
|
}
|
|
}
|
|
} while (false);
|
|
}
|
|
|
|
void S2Mover::one_space(uint64_t code, int offset) const {
|
|
// ---------------- case up ----------------
|
|
|
|
do {
|
|
if (offset >= 4) {
|
|
/// 1x1
|
|
if (APPLY_MASK(code, offset - 4, 0b111) == 0b011) {
|
|
release_(SET_1x1(UNSET_1x1(code, offset - 4), offset));
|
|
break;
|
|
}
|
|
}
|
|
if (offset >= 8) {
|
|
/// 2x1
|
|
if (APPLY_MASK(code, offset - 8, 0b111'000'000'000'111) == 0b111'000'000'000'010) {
|
|
release_(SET_2x1(UNSET_2x1(code, offset - 8), offset - 4));
|
|
break;
|
|
}
|
|
}
|
|
} while (false);
|
|
|
|
// ---------------- case down ----------------
|
|
|
|
do {
|
|
if (offset < 16) {
|
|
/// 1x1
|
|
if (APPLY_MASK(code, offset + 4, 0b111) == 0b011) {
|
|
release_(SET_1x1(UNSET_1x1(code, offset + 4), offset));
|
|
break;
|
|
}
|
|
}
|
|
if (offset < 12) {
|
|
/// 2x1
|
|
if (APPLY_MASK(code, offset + 4, 0b111'000'000'000'111) == 0b111'000'000'000'010) {
|
|
release_(SET_2x1(UNSET_2x1(code, offset + 4), offset));
|
|
break;
|
|
}
|
|
}
|
|
} while (false);
|
|
|
|
// ---------------- case left ----------------
|
|
|
|
do {
|
|
if ((offset % 4) != 0) {
|
|
/// 1x1
|
|
if (APPLY_MASK(code, offset - 1, 0b111) == 0b011) {
|
|
release_(SET_1x1(UNSET_1x1(code, offset - 1), offset));
|
|
break;
|
|
}
|
|
}
|
|
if ((offset % 4) >= 2) {
|
|
/// 1x2
|
|
if (APPLY_MASK(code, offset - 2, 0b111'111) == 0b111'001) {
|
|
release_(SET_1x2(UNSET_1x2(code, offset - 2), offset - 1));
|
|
break;
|
|
}
|
|
}
|
|
} while (false);
|
|
|
|
// ---------------- case right ----------------
|
|
|
|
do {
|
|
if ((offset % 4) != 3) {
|
|
/// 1x1
|
|
if (APPLY_MASK(code, offset + 1, 0b111) == 0b011) {
|
|
release_(SET_1x1(UNSET_1x1(code, offset + 1), offset));
|
|
break;
|
|
}
|
|
}
|
|
if ((offset % 4) <= 1) {
|
|
/// 1x2
|
|
if (APPLY_MASK(code, offset + 1, 0b111'111) == 0b111'001) {
|
|
release_(SET_1x2(UNSET_1x2(code, offset + 1), offset));
|
|
break;
|
|
}
|
|
}
|
|
} while (false);
|
|
}
|
|
|
|
void S2Mover::next_cases(uint64_t code) {
|
|
// std::cout << RawCode::unsafe_create(code) << std::endl;
|
|
|
|
// constexpr int space_1 = 17, space_2 = 18;
|
|
// constexpr int space_1 = 1, space_2 = 2;
|
|
// constexpr int space_1 = 18, space_2 = 19;
|
|
// constexpr int space_1 = 16, space_2 = 17;
|
|
// two_space_a(code, space_1);
|
|
|
|
// constexpr int space_1 = 12, space_2 = 16;
|
|
// constexpr int space_1 = 0, space_2 = 4;
|
|
// constexpr int space_1 = 15, space_2 = 19;
|
|
// constexpr int space_1 = 12, space_2 = 16;
|
|
// two_space_b(code, space_1);
|
|
|
|
// constexpr int space = 12;
|
|
// constexpr int space = 4;
|
|
// constexpr int space = 19;
|
|
// constexpr int space = 16;
|
|
// one_space(code, space);
|
|
|
|
int space_1 = -1;
|
|
int space_2 = -1;
|
|
for (int addr = 0; addr < 20; ++addr) {
|
|
if (((code >> (addr * 3)) & 0b111) == 0) {
|
|
if (space_1 == -1) {
|
|
space_1 = addr;
|
|
continue;
|
|
}
|
|
space_2 = addr;
|
|
}
|
|
}
|
|
// std::cout << space_1 << std::endl;
|
|
// std::cout << space_2 << std::endl;
|
|
|
|
if (space_1 + 1 == space_2 && space_1 % 4 != 3) {
|
|
two_space_a(code, space_1);
|
|
} else if (space_1 + 4 == space_2) {
|
|
two_space_b(code, space_1);
|
|
} else {
|
|
one_space(code, space_1);
|
|
one_space(code, space_2);
|
|
}
|
|
}
|
|
|