diff --git a/src/core/group/group.h b/src/core/group/group.h new file mode 100644 index 0000000..4971f4c --- /dev/null +++ b/src/core/group/group.h @@ -0,0 +1,65 @@ +#pragma once + +/// Group is a concept in klotski. For any valid cases, moving all its blocks +/// any finite number of times can generate a limited number of layouts, they +/// are called a `group`. Of course, there are some special groups whose size +/// is only 1, that is, only itself. (all blocks can no longer be moved) + +/// For a case, by definition, it must have a `2x2` block, at least two spaces, +/// and the others are filled by any number of `1x1`, `1x2` and `2x1`, so their +/// numbers satisfy the following inequality. +/// +/// => n_1x1 + (n_1x2 + n_2x1) * 2 + n_2x2 * 4 < (20 - 2) +/// => n_1x1 + (n_1x2 + n_2x1) * 2 < 14 +/// +/// Through calculation, it can be known that these three independent variables +/// can get 204 permutations. However, on a 5x4 chessboard, it's never possible +/// to put seven 2x1 blocks, so there are actually 203 combinations, and they +/// are numbered from 0 to 202, called `type_id`. + +/// According to the number of blocks in the layout, you can use the following +/// formula to get an intermediate value `flag`, and arrange the flags in 203 +/// cases from small to large to get the `type_id` value. Similarly, `type_id` +/// can also be reversed to get the number of blocks, which are one by one +/// corresponding. +/// +/// flag => | 0xxx | 0xxx | xxxx | +/// (12-bit) | (n_1x2 + n_2x1) | (n_2x1) | (n_1x1) | +/// | (0 ~ 7) | (0 ~ 7) | (0 ~ 14) | +/// +/// flag => ((n_1x2 + n_2x1) << 8) | (n_2x1 << 4) | (n_1x1) +/// +/// Using the table lookup method, the `type_id` of any case can be obtained +/// within O(1), which is encapsulated in `GroupType`. + +/// Since the `type_id` cannot change when moving, all cases belonging to the +/// same `type_id` must be divided into different groups (of course there may +/// be only one). For a group, list the CommonCodes of all its cases, the +/// smallest of which is called the group's `seed`. List all the groups under +/// the same `type_id`, and arrange them from large to small, and arrange the +/// groups of the same size from small to large according to the `seed`, and +/// start numbering from 0 to get the `group_id`. + +/// All cases of the same group will have the same `type_id` and `group_id`, +/// that is to say, for cases with the same two values, there must be a +/// reachable path for them, otherwise they will never be reachable. Arrange +/// the CommonCodes of all cases in the group from small to large, and start +/// numbering from 0 to get `case_id`, which will uniquely determine a legal +/// layout. Use the following method to express. +/// +/// {type_id}-{group_id}-{case_id} +/// +/// Eg1: 1A9BF0C00 -> `169-1-7472` +/// Eg2: 4FEA13400 -> `164-0-30833` +/// +/// The range of `type_id` is [0, 203), the maximum `group_id` is 2652 (there +/// are 2653 groups when `type_id` is 164), the maximum `case_id` is 964655 +/// (there are 964656 cases when `type_id` is 58 and `group_id` is 0). +/// Therefore, these three numbers meet the following range requirements. +/// +/// type_id < 203 | group_id < 2653 | case_id < 964656 +/// (8-bit ~ 256) | (12-bit ~ 4096) | (20-bit ~ 1048576) +/// +/// Typically, these three variables are generally recorded in decimal and +/// displayed in the form of strings. They can facilitate the relationship +/// between multiple cases.