mirror of https://github.com/dnomd343/klotski.git
Dnomd343
2 years ago
6 changed files with 170 additions and 133 deletions
@ -1,67 +1,85 @@ |
|||||
#include "common.h" |
#include "common.h" |
||||
#include "all_cases.h" |
#include "all_cases.h" |
||||
|
|
||||
using klotski::AllCases; |
namespace klotski { |
||||
|
|
||||
|
using Common::check_range; |
||||
|
using Common::range_reverse; |
||||
|
|
||||
/// static variable initialize
|
/// static variable initialize
|
||||
std::mutex AllCases::building; |
std::mutex AllCases::building_; |
||||
bool AllCases::available = false; |
bool AllCases::available_ = false; |
||||
std::vector<uint32_t> AllCases::data[]; |
std::vector<uint32_t> AllCases::data_[]; |
||||
|
|
||||
const std::vector<uint32_t> (&AllCases::fetch())[16] { // get all cases content
|
const std::vector<uint32_t> (&AllCases::fetch())[16] { |
||||
if (status() != AVAILABLE) { |
if (status() != AVAILABLE) { |
||||
AllCases::build(); // all cases initialize
|
build(); |
||||
} |
} |
||||
return AllCases::data; // return const ref
|
return data_; // return const reference
|
||||
} |
} |
||||
|
|
||||
AllCases::Status AllCases::status() { // get all cases status
|
AllCases::Status AllCases::status() { |
||||
if (AllCases::available) { |
if (available_) { |
||||
return AVAILABLE; // all cases already built
|
return AVAILABLE; // data already built
|
||||
} |
} |
||||
if (!AllCases::building.try_lock()) { // fail to lock mutex
|
if (!building_.try_lock()) { // fail to lock mutex
|
||||
return BUILDING; // another thread working
|
return BUILDING; // another thread working
|
||||
} |
} |
||||
AllCases::building.unlock(); // release mutex
|
building_.unlock(); // release mutex
|
||||
return NO_INIT; |
return NOT_INIT; |
||||
} |
} |
||||
|
|
||||
void AllCases::build() { // ensure that all cases available
|
void AllCases::build() { // ensure that data is available
|
||||
if (!AllCases::available) { |
if (!available_) { |
||||
if (AllCases::building.try_lock()) { // mutex lock success
|
if (building_.try_lock()) { // mutex lock success
|
||||
build_data(); // start build process
|
build_data(); // start build process
|
||||
AllCases::available = true; // set available flag
|
available_ = true; |
||||
} else { |
} else { |
||||
AllCases::building.lock(); // blocking waiting
|
building_.lock(); // blocking waiting
|
||||
|
} |
||||
|
building_.unlock(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
std::vector<uint64_t> AllCases::release() { |
||||
|
std::vector<uint64_t> data; |
||||
|
data.reserve(ALL_CASES_SIZE_SUM); // memory pre-allocated
|
||||
|
for (uint64_t head = 0; head < 16; ++head) { |
||||
|
for (const auto &range : fetch()[head]) { |
||||
|
data.emplace_back(head << 32 | range); // release common codes
|
||||
} |
} |
||||
AllCases::building.unlock(); |
|
||||
} |
} |
||||
|
return data; |
||||
} |
} |
||||
|
|
||||
void AllCases::build_data() { // find all cases
|
/// Search all possible layouts based on basic-ranges.
|
||||
|
void AllCases::build_data() { |
||||
const auto &basic_ranges = BasicRanges::fetch(); |
const auto &basic_ranges = BasicRanges::fetch(); |
||||
for (uint32_t head = 0; head < 15; ++head) { // address of 2x2 block
|
for (uint32_t head = 0; head < 15; ++head) { // address of 2x2 block
|
||||
|
/// head -> 0/1/2 / 4/5/6 / 8/9/10 / 12/13/14
|
||||
if ((head & 0b11) == 0b11) { |
if ((head & 0b11) == 0b11) { |
||||
++head; // skip invalid address
|
++head; // skip invalid address
|
||||
} |
} |
||||
/// head -> 0/1/2 / 4/5/6 / 8/9/10 / 12/13/14
|
data_[head].reserve(ALL_CASES_SIZE[head]); // memory pre-allocated
|
||||
data[head].reserve(ALL_CASES_SIZE[head]); // memory pre-allocated
|
|
||||
/// head(4-bits) + basic ranges(32-bits) --check--> valid cases
|
/// head(4-bit) + basic-range(32-bit) --check--> valid cases
|
||||
for (uint32_t index = 0; index < basic_ranges.size(); ++index) { |
for (uint32_t index = 0; index < basic_ranges.size(); ++index) { |
||||
auto broken_offset = Common::check_range(head, basic_ranges[index]); |
auto broken_offset = check_range(head, basic_ranges[index]); |
||||
if (broken_offset) { // case invalid
|
if (broken_offset) { // case invalid
|
||||
auto delta = (uint32_t)1 << (32 - broken_offset * 2); // delta to next possible range
|
auto delta = (uint32_t)1 << (32 - broken_offset * 2); // delta to next possible range
|
||||
/// !! -> broken
|
/// !! -> broken
|
||||
/// ( xx xx xx ) xx xx xx ... (reversed range)
|
/// ( xx xx xx ) xx xx xx ... (reversed range)
|
||||
/// +1 00 00 00 ... (delta)
|
/// +1 00 00 00 ... (delta)
|
||||
auto next_min = (Common::range_reverse(basic_ranges[index]) & ~(delta - 1)) + delta; |
auto at_least = (range_reverse(basic_ranges[index]) & ~(delta - 1)) + delta; |
||||
while (Common::range_reverse(basic_ranges[++index]) < next_min); // located next range
|
while (range_reverse(basic_ranges[++index]) < at_least); // located next range
|
||||
--index; |
--index; |
||||
} else { |
continue; |
||||
AllCases::data[head].emplace_back( |
|
||||
Common::range_reverse(basic_ranges[index]) // release valid cases
|
|
||||
); |
|
||||
} |
} |
||||
|
data_[head].emplace_back( |
||||
|
range_reverse(basic_ranges[index]) // release valid cases
|
||||
|
); |
||||
} |
} |
||||
} |
} |
||||
} |
} |
||||
|
|
||||
|
} // namespace klotski
|
||||
|
Loading…
Reference in new issue