|  | @ -1,21 +1,22 @@ | 
			
		
	
		
		
			
				
					
					|  |  | #include <iostream> |  |  | #include "utility.h" | 
			
				
				
			
		
	
		
		
			
				
					|  |  | 
 |  |  |  | 
			
		
	
		
		
			
				
					|  |  | #include "reverse.h" |  |  |  | 
			
		
	
		
		
	
		
		
			
				
					|  |  | #include "all_cases.h" |  |  | #include "all_cases.h" | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  | //typedef uint32_t Range;
 |  |  | namespace klotski { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  | 
 |  |  | namespace cases { | 
			
				
				
			
		
	
		
		
			
				
					|  |  | using klotski::cases::BasicRanges; |  |  |  | 
			
		
	
		
		
			
				
					|  |  | using klotski::cases::range_reverse; |  |  |  | 
			
		
	
		
		
	
		
		
	
		
		
			
				
					|  |  | 
 |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  | inline int low_zero_num(uint32_t bin) { |  |  | /// Calculate all possible klotski heads.
 | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |     return __builtin_ctzl(bin); |  |  | static consteval std::array<int, 12> case_heads() { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  | 
 |  |  |     std::array<int, 12> heads = {}; | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |     // WARN: be aware of serious performance issues
 |  |  |     for (int i = 0, head = 0; head < 15; ++head) { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |     // return __builtin_popcount(~(bin ^ -bin)) - 1;
 |  |  |         if (head % 4 != 3) { | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					|  |  |  |  |  |             heads[i++] = head; | 
			
		
	
		
		
			
				
					|  |  |  |  |  |         } | 
			
		
	
		
		
			
				
					|  |  |  |  |  |     } | 
			
		
	
		
		
			
				
					|  |  |  |  |  |     return heads; | 
			
		
	
		
		
			
				
					|  |  | } |  |  | } | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  | int check_range(int head, uint32_t range) noexcept { |  |  | /// Check whether the combination of head and range is valid.
 | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					|  |  |  |  |  | static int check_range(int head, uint32_t range) noexcept { | 
			
		
	
		
		
			
				
					|  |  |     constexpr uint32_t MASK_1x1 = 0b00000001; |  |  |     constexpr uint32_t MASK_1x1 = 0b00000001; | 
			
		
	
		
		
			
				
					|  |  |     constexpr uint32_t MASK_1x2 = 0b00000011; |  |  |     constexpr uint32_t MASK_1x2 = 0b00000011; | 
			
		
	
		
		
			
				
					|  |  |     constexpr uint32_t MASK_2x1 = 0b00010001; |  |  |     constexpr uint32_t MASK_2x1 = 0b00010001; | 
			
		
	
	
		
		
			
				
					|  | @ -48,32 +49,9 @@ int check_range(int head, uint32_t range) noexcept { | 
			
		
	
		
		
			
				
					|  |  |     return 0; // pass check
 |  |  |     return 0; // pass check
 | 
			
		
	
		
		
			
				
					|  |  | } |  |  | } | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  | void demo() { |  |  | /// Build all valid ranges of the specified head.
 | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  | 
 |  |  | void AllCases::BuildCases(int head, Ranges &basic_ranges, Ranges &release) noexcept { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  | //    std::cout << __builtin_popcount(~(6 ^ -6)) - 1 << std::endl;
 |  |  |     release.reserve(ALL_CASES_NUM[head]); | 
			
				
				
			
		
	
		
		
			
				
					|  |  | //    return;
 |  |  |  | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  |  | 
			
		
	
		
		
			
				
					|  |  |     constexpr std::array<int, 12> heads = { |  |  |  | 
			
		
	
		
		
			
				
					|  |  |         0x0, 0x1, 0x2, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |         0x4, 0x5, 0x6, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |         0x8, 0x9, 0xA, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |         0xC, 0xD, 0xE, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |     }; |  |  |  | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  |  | 
			
		
	
		
		
			
				
					|  |  |     auto num = 0; |  |  |  | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  |  | 
			
		
	
		
		
			
				
					|  |  |     std::array<std::vector<uint32_t>, 16> data; |  |  |  | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  |  | 
			
		
	
		
		
			
				
					|  |  |     // TODO: vector reserve
 |  |  |  | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  |  | 
			
		
	
		
		
			
				
					|  |  |     auto basic_ranges = BasicRanges::Instance().Fetch(); |  |  |  | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  |  | 
			
		
	
		
		
			
				
					|  |  | //    std::vector<uint32_t> reversed {basic_ranges.begin(), basic_ranges.end()};
 |  |  |  | 
			
		
	
		
		
			
				
					|  |  | //    for (auto &x : reversed) {
 |  |  |  | 
			
		
	
		
		
			
				
					|  |  | //        x = range_reverse(x);
 |  |  |  | 
			
		
	
		
		
			
				
					|  |  | //    }
 |  |  |  | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  |  | 
			
		
	
		
		
			
				
					|  |  |     for (auto head : heads) { |  |  |  | 
			
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					|  |  |     for (uint32_t index = 0; index < basic_ranges.size(); ++index) { |  |  |     for (uint32_t index = 0; index < basic_ranges.size(); ++index) { | 
			
		
	
		
		
			
				
					|  |  |         auto offset = check_range(head, basic_ranges[index]); |  |  |         auto offset = check_range(head, basic_ranges[index]); | 
			
		
	
		
		
			
				
					|  |  |         if (offset) { // invalid case
 |  |  |         if (offset) { // invalid case
 | 
			
		
	
	
		
		
			
				
					|  | @ -84,33 +62,46 @@ void demo() { | 
			
		
	
		
		
			
				
					|  |  |             tmp += range_reverse(basic_ranges[index]) & ~(tmp - 1); |  |  |             tmp += range_reverse(basic_ranges[index]) & ~(tmp - 1); | 
			
		
	
		
		
			
				
					|  |  |             while (range_reverse(basic_ranges[++index]) < tmp); // located next range
 |  |  |             while (range_reverse(basic_ranges[++index]) < tmp); // located next range
 | 
			
		
	
		
		
			
				
					|  |  |             --index; |  |  |             --index; | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  |  | 
			
		
	
		
		
			
				
					|  |  | //                next += reversed[index] & ~(next - 1);
 |  |  |  | 
			
		
	
		
		
			
				
					|  |  | //                auto kk = std::lower_bound(reversed.begin() + index, reversed.end(), next);
 |  |  |  | 
			
		
	
		
		
			
				
					|  |  | //                index = kk - reversed.begin() - 1;
 |  |  |  | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  |  | 
			
		
	
		
		
			
				
					|  |  |             continue; |  |  |             continue; | 
			
		
	
		
		
			
				
					|  |  |         } |  |  |         } | 
			
		
	
		
		
			
				
					|  |  |  |  |  |         release.emplace_back(range_reverse(basic_ranges[index])); // release valid case
 | 
			
		
	
		
		
			
				
					|  |  |  |  |  |     } | 
			
		
	
		
		
			
				
					|  |  |  |  |  | } | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |             data[head].emplace_back(range_reverse(basic_ranges[index])); |  |  | void AllCases::Build() noexcept { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  | 
 |  |  |     if (available_) { // data already available
 | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  | //            ++index;
 |  |  |         return; | 
			
				
				
			
		
	
		
		
			
				
					|  |  | 
 |  |  |  | 
			
		
	
		
		
			
				
					|  |  |             ++num; |  |  |  | 
			
		
	
		
		
			
				
					|  |  | //            volatile auto r = range_reverse(basic_ranges[index]); // release valid cases
 |  |  |  | 
			
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					|  |  |     } |  |  |     } | 
			
		
	
		
		
			
				
					|  |  |  |  |  |     if (building_.try_lock()) { // mutex lock success
 | 
			
		
	
		
		
			
				
					|  |  |  |  |  |         if (available_) { | 
			
		
	
		
		
			
				
					|  |  |  |  |  |             building_.unlock(); | 
			
		
	
		
		
			
				
					|  |  |  |  |  |             return; | 
			
		
	
		
		
			
				
					|  |  |         } |  |  |         } | 
			
		
	
		
		
			
				
					
					|  |  | 
 |  |  |         auto basic_ranges = BasicRanges::Instance().Fetch(); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  | //    for (auto &x : data) {
 |  |  |         for (auto head : case_heads()) { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  | //        std::cout << x.size() << std::endl;
 |  |  |             BuildCases(head, basic_ranges, GetCases()[head]); | 
			
				
				
			
		
	
		
		
			
				
					|  |  | //    }
 |  |  |  | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  |  | 
			
		
	
		
		
			
				
					|  |  |     for (uint64_t head = 0; head < 15; ++head) { |  |  |  | 
			
		
	
		
		
			
				
					|  |  |         for (auto x : data[head]) { |  |  |  | 
			
		
	
		
		
			
				
					|  |  |             printf("%09llX\n", (head << 32) | x); |  |  |  | 
			
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					|  |  |         } |  |  |         } | 
			
		
	
		
		
			
				
					|  |  |  |  |  |         available_ = true; | 
			
		
	
		
		
			
				
					|  |  |  |  |  |     } else { | 
			
		
	
		
		
			
				
					|  |  |  |  |  |         building_.lock(); // blocking waiting
 | 
			
		
	
		
		
			
				
					|  |  |     } |  |  |     } | 
			
		
	
		
		
			
				
					|  |  |  |  |  |     building_.unlock(); // release mutex
 | 
			
		
	
		
		
			
				
					|  |  |  |  |  | } | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  | //    std::cout << num << std::endl;
 |  |  | AllRanges& AllCases::GetCases() noexcept { | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					|  |  |  |  |  |     static std::array<Ranges, 16> cases; | 
			
		
	
		
		
			
				
					|  |  |  |  |  |     return cases; | 
			
		
	
		
		
			
				
					|  |  |  |  |  | } | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  | 
 | 
			
		
	
		
		
			
				
					|  |  |  |  |  | AllCases& AllCases::Instance() noexcept { | 
			
		
	
		
		
			
				
					|  |  |  |  |  |     static AllCases instance; | 
			
		
	
		
		
			
				
					|  |  |  |  |  |     return instance; | 
			
		
	
		
		
			
				
					|  |  | } |  |  | } | 
			
		
	
		
		
			
				
					|  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					|  |  |  |  |  | AllRanges& AllCases::Fetch() noexcept { | 
			
		
	
		
		
			
				
					|  |  |  |  |  |     this->Build(); | 
			
		
	
		
		
			
				
					|  |  |  |  |  |     return GetCases(); | 
			
		
	
		
		
			
				
					|  |  |  |  |  | } | 
			
		
	
		
		
			
				
					|  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					|  |  |  |  |  | } // namespace cases
 | 
			
		
	
		
		
			
				
					|  |  |  |  |  | } // namespace klotski
 | 
			
		
	
	
		
		
			
				
					|  | 
 |