华容道高性能计算引擎
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

#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);
}
}