diff options
Diffstat (limited to '')
| -rw-r--r-- | TODO.txt | 2 | ||||
| -rw-r--r-- | cube.c | 237 | ||||
| -rw-r--r-- | cube.h | 2 |
3 files changed, 209 insertions, 32 deletions
| @@ -2,7 +2,7 @@ | |||
| 2 | 2 | ||
| 3 | See the sections below for details | 3 | See the sections below for details |
| 4 | 4 | ||
| 5 | * Implement some simple solver | 5 | * Tests for simple solver |
| 6 | * Extend cube and moves to include centers | 6 | * Extend cube and moves to include centers |
| 7 | * More complex optimal solvers, pruning tables | 7 | * More complex optimal solvers, pruning tables |
| 8 | * Benchmarks | 8 | * Benchmarks |
| @@ -9,6 +9,7 @@ | |||
| 9 | #ifdef DEBUG | 9 | #ifdef DEBUG |
| 10 | #include <stdio.h> | 10 | #include <stdio.h> |
| 11 | #define DBG_LOG(...) fprintf(stderr, __VA_ARGS__) | 11 | #define DBG_LOG(...) fprintf(stderr, __VA_ARGS__) |
| 12 | #define DBG_WARN(condition, ...) if (!(condition)) DBG_LOG(__VA_ARGS__); | ||
| 12 | #define DBG_ASSERT(condition, retval, ...) \ | 13 | #define DBG_ASSERT(condition, retval, ...) \ |
| 13 | if (!(condition)) { \ | 14 | if (!(condition)) { \ |
| 14 | DBG_LOG(__VA_ARGS__); \ | 15 | DBG_LOG(__VA_ARGS__); \ |
| @@ -16,6 +17,7 @@ | |||
| 16 | } | 17 | } |
| 17 | #else | 18 | #else |
| 18 | #define DBG_LOG(...) | 19 | #define DBG_LOG(...) |
| 20 | #define DBG_WARN(condition, ...) | ||
| 19 | #define DBG_ASSERT(condition, retval, ...) | 21 | #define DBG_ASSERT(condition, retval, ...) |
| 20 | #endif | 22 | #endif |
| 21 | 23 | ||
| @@ -255,6 +257,10 @@ typedef __m256i cube_fast_t; | |||
| 255 | #define _cocw_avx2 _mm256_set_epi64x(0, 0, 0, 0x2020202020202020) | 257 | #define _cocw_avx2 _mm256_set_epi64x(0, 0, 0, 0x2020202020202020) |
| 256 | #define _eo_avx2 _mm256_set_epi64x(0x10101010, 0x1010101010101010, 0, 0) | 258 | #define _eo_avx2 _mm256_set_epi64x(0x10101010, 0x1010101010101010, 0, 0) |
| 257 | #define zero_fast _mm256_set_epi64x(0, 0, 0, 0); | 259 | #define zero_fast _mm256_set_epi64x(0, 0, 0, 0); |
| 260 | #define solved_fast _mm256_set_epi8( \ | ||
| 261 | 0, 0, 0, 0, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, \ | ||
| 262 | 0, 0, 0, 0, 0, 0, 0, 0, 7, 6, 5, 4, 3, 2, 1, 0 \ | ||
| 263 | ) | ||
| 258 | 264 | ||
| 259 | static cube_fast_t cubetofast(cube_t); | 265 | static cube_fast_t cubetofast(cube_t); |
| 260 | static cube_t fasttocube(cube_fast_t); | 266 | static cube_t fasttocube(cube_fast_t); |
| @@ -1482,6 +1488,12 @@ equal_fast(cube_fast_t c1, cube_fast_t c2) | |||
| 1482 | return mask == 0xffffffffU; | 1488 | return mask == 0xffffffffU; |
| 1483 | } | 1489 | } |
| 1484 | 1490 | ||
| 1491 | static inline bool | ||
| 1492 | issolved_fast(cube_fast_t cube) | ||
| 1493 | { | ||
| 1494 | return equal_fast(cube, solved_fast); | ||
| 1495 | } | ||
| 1496 | |||
| 1485 | static inline cube_fast_t | 1497 | static inline cube_fast_t |
| 1486 | invertco_fast(cube_fast_t c) | 1498 | invertco_fast(cube_fast_t c) |
| 1487 | { | 1499 | { |
| @@ -1614,7 +1626,11 @@ typedef cube_t cube_fast_t; | |||
| 1614 | r[k] ^= _eobit; \ | 1626 | r[k] ^= _eobit; \ |
| 1615 | r[l] ^= _eobit; | 1627 | r[l] ^= _eobit; |
| 1616 | 1628 | ||
| 1617 | static const cube_fast_t zero_fast = { .corner = {0}, .edge = {0} }; | 1629 | static cube_fast_t zero_fast = { .corner = {0}, .edge = {0} }; |
| 1630 | static cube_t solved_fast = { | ||
| 1631 | .corner = {0, 1, 2, 3, 4, 5, 6, 7}, | ||
| 1632 | .edge = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11} | ||
| 1633 | }; | ||
| 1618 | 1634 | ||
| 1619 | static cube_fast_t cubetofast(cube_t); | 1635 | static cube_fast_t cubetofast(cube_t); |
| 1620 | static cube_t fasttocube(cube_fast_t); | 1636 | static cube_t fasttocube(cube_fast_t); |
| @@ -2842,6 +2858,12 @@ equal_fast(cube_fast_t c1, cube_fast_t c2) | |||
| 2842 | return ret; | 2858 | return ret; |
| 2843 | } | 2859 | } |
| 2844 | 2860 | ||
| 2861 | static inline bool | ||
| 2862 | issolved_fast(cube_fast_t cube) | ||
| 2863 | { | ||
| 2864 | return equal_fast(cube, solved_fast); | ||
| 2865 | } | ||
| 2866 | |||
| 2845 | static inline cube_fast_t | 2867 | static inline cube_fast_t |
| 2846 | inverse_fast(cube_fast_t cube) | 2868 | inverse_fast(cube_fast_t cube) |
| 2847 | { | 2869 | { |
| @@ -2930,7 +2952,7 @@ static void writecube_SRC(cube_t, char *); | |||
| 2930 | static uint8_t readmove(char); | 2952 | static uint8_t readmove(char); |
| 2931 | static uint8_t readmodifier(char); | 2953 | static uint8_t readmodifier(char); |
| 2932 | static uint8_t readtrans(char *); | 2954 | static uint8_t readtrans(char *); |
| 2933 | static void writemoves(uint8_t *, int, char *); | 2955 | static int writemoves(uint8_t *, int, char *); |
| 2934 | static void writetrans(uint8_t, char *); | 2956 | static void writetrans(uint8_t, char *); |
| 2935 | static cube_fast_t transform(cube_fast_t, uint8_t); | 2957 | static cube_fast_t transform(cube_fast_t, uint8_t); |
| 2936 | static cube_fast_t move(cube_fast_t, uint8_t); | 2958 | static cube_fast_t move(cube_fast_t, uint8_t); |
| @@ -3256,7 +3278,7 @@ readtrans(char *buf) | |||
| 3256 | return _error; | 3278 | return _error; |
| 3257 | } | 3279 | } |
| 3258 | 3280 | ||
| 3259 | static void | 3281 | static int |
| 3260 | writemoves(uint8_t *m, int n, char *buf) | 3282 | writemoves(uint8_t *m, int n, char *buf) |
| 3261 | { | 3283 | { |
| 3262 | int i; | 3284 | int i; |
| @@ -3271,6 +3293,8 @@ writemoves(uint8_t *m, int n, char *buf) | |||
| 3271 | *b = ' '; | 3293 | *b = ' '; |
| 3272 | } | 3294 | } |
| 3273 | *b = '\0'; | 3295 | *b = '\0'; |
| 3296 | |||
| 3297 | return b - buf; | ||
| 3274 | } | 3298 | } |
| 3275 | 3299 | ||
| 3276 | static void | 3300 | static void |
| @@ -3628,16 +3652,16 @@ Here you can find the implementation of all the solving algorithms. | |||
| 3628 | typedef struct { | 3652 | typedef struct { |
| 3629 | cube_fast_t cube; | 3653 | cube_fast_t cube; |
| 3630 | uint8_t depth; | 3654 | uint8_t depth; |
| 3631 | int maxsols; | 3655 | int64_t maxsols; |
| 3632 | uint8_t *sols; | 3656 | char *sols; |
| 3633 | int nsols; | 3657 | int64_t nsols; |
| 3634 | int nmoves; | 3658 | uint8_t nmoves; |
| 3635 | uint8_t moves[20]; | 3659 | uint8_t moves[20]; |
| 3636 | int (*estimate)(cube_fast_t); | 3660 | uint8_t (*estimate)(cube_fast_t); |
| 3637 | } dfs_arg_t; | 3661 | } dfsarg_generic_t; |
| 3638 | 3662 | ||
| 3639 | static bool | 3663 | static bool |
| 3640 | allowednextmove(dfs_arg_t arg, uint8_t m) | 3664 | allowednextmove(dfsarg_generic_t arg, uint8_t m) |
| 3641 | { | 3665 | { |
| 3642 | int n; | 3666 | int n; |
| 3643 | uint8_t mbase, l1base, l2base, maxis, l1axis, l2axis; | 3667 | uint8_t mbase, l1base, l2base, maxis, l1axis, l2axis; |
| @@ -3665,11 +3689,11 @@ allowednextmove(dfs_arg_t arg, uint8_t m) | |||
| 3665 | } | 3689 | } |
| 3666 | 3690 | ||
| 3667 | static int | 3691 | static int |
| 3668 | solve_generic_dfs(dfs_arg_t arg) | 3692 | solve_generic_dfs(dfsarg_generic_t arg) |
| 3669 | { | 3693 | { |
| 3670 | dfs_arg_t nextarg; | 3694 | dfsarg_generic_t nextarg; |
| 3671 | int bound, ret; | 3695 | uint8_t m, bound; |
| 3672 | uint8_t m; | 3696 | int64_t ret; |
| 3673 | 3697 | ||
| 3674 | bound = arg.estimate(arg.cube); | 3698 | bound = arg.estimate(arg.cube); |
| 3675 | 3699 | ||
| @@ -3679,11 +3703,13 @@ solve_generic_dfs(dfs_arg_t arg) | |||
| 3679 | if (bound == 0) { | 3703 | if (bound == 0) { |
| 3680 | if (arg.nmoves != arg.depth) | 3704 | if (arg.nmoves != arg.depth) |
| 3681 | return 0; | 3705 | return 0; |
| 3682 | memcpy(&arg.sols[arg.depth * arg.nsols], arg.moves, arg.depth); | 3706 | arg.sols += writemoves(arg.moves, arg.depth, arg.sols); |
| 3707 | *arg.sols = '\n'; | ||
| 3708 | arg.sols++; | ||
| 3683 | return 1; | 3709 | return 1; |
| 3684 | } | 3710 | } |
| 3685 | 3711 | ||
| 3686 | memcpy(&nextarg, &arg, sizeof(dfs_arg_t)); | 3712 | memcpy(&nextarg, &arg, sizeof(dfsarg_generic_t)); |
| 3687 | nextarg.nmoves = arg.nmoves + 1; | 3713 | nextarg.nmoves = arg.nmoves + 1; |
| 3688 | for (m = 0, ret = 0; m < 18; m++) { | 3714 | for (m = 0, ret = 0; m < 18; m++) { |
| 3689 | if (allowednextmove(arg, m)) { | 3715 | if (allowednextmove(arg, m)) { |
| @@ -3696,24 +3722,65 @@ solve_generic_dfs(dfs_arg_t arg) | |||
| 3696 | return ret; | 3722 | return ret; |
| 3697 | } | 3723 | } |
| 3698 | 3724 | ||
| 3699 | /* TODO | 3725 | static int64_t |
| 3700 | int | ||
| 3701 | solve_generic( | 3726 | solve_generic( |
| 3702 | cube_fast_t cube, | 3727 | cube_t cube, |
| 3703 | uint8_t depth, | 3728 | char *nisstype, |
| 3704 | int maxsols, | 3729 | /* TODO: handle NISS */ |
| 3705 | uint8_t *sols, | 3730 | int8_t minmoves, |
| 3706 | int (*estimate)(cube_fast_t) | 3731 | int8_t maxmoves, |
| 3732 | int64_t maxsols, | ||
| 3733 | int8_t optimal, | ||
| 3734 | char *sols, | ||
| 3735 | uint8_t (*estimate)(cube_fast_t) | ||
| 3736 | /* TODO: add validator */ | ||
| 3737 | /* TODO: maybe add data for estimate */ | ||
| 3738 | /* TODO: add moveset (and allowednext?) */ | ||
| 3707 | ) | 3739 | ) |
| 3708 | { | 3740 | { |
| 3709 | dfs_arg_t arg; | 3741 | dfsarg_generic_t arg; |
| 3742 | int64_t ret, tmp, first; | ||
| 3710 | 3743 | ||
| 3711 | if (!issolvable(cube) || depth > 20 || estimate == NULL) | 3744 | if (!issolvable(cube)) { |
| 3745 | DBG_LOG("solve: cube is not solvable\n"); | ||
| 3712 | return -1; | 3746 | return -1; |
| 3747 | } | ||
| 3713 | 3748 | ||
| 3714 | arg = (dfs_arg_t) { | 3749 | DBG_WARN(!strcmp(nisstype, ""), |
| 3715 | .cube = cube, | 3750 | "solve: NISS not implemented yet, 'nisstype' ignored\n"); |
| 3716 | .depth = depth, | 3751 | |
| 3752 | if (minmoves < 0) { | ||
| 3753 | DBG_LOG("solve: 'minmoves' is negative, setting to 0\n"); | ||
| 3754 | minmoves = 0; | ||
| 3755 | } | ||
| 3756 | |||
| 3757 | if (maxmoves < 0) { | ||
| 3758 | DBG_LOG("solve: invalid 'maxmoves', setting to 20\n"); | ||
| 3759 | maxmoves = 20; | ||
| 3760 | } | ||
| 3761 | |||
| 3762 | if (maxsols < 0) { | ||
| 3763 | DBG_LOG("solve: 'maxsols' is negative\n"); | ||
| 3764 | return -1; | ||
| 3765 | } | ||
| 3766 | |||
| 3767 | if (maxsols == 0) { | ||
| 3768 | DBG_LOG("solve: 'maxsols' is 0\n"); | ||
| 3769 | return 0; | ||
| 3770 | } | ||
| 3771 | |||
| 3772 | if (sols == NULL) { | ||
| 3773 | DBG_LOG("solve: return parameter 'sols' is NULL\n"); | ||
| 3774 | return -1; | ||
| 3775 | } | ||
| 3776 | |||
| 3777 | if (estimate == NULL) { | ||
| 3778 | DBG_LOG("solve: 'estimate' is NULL\n"); | ||
| 3779 | return -1; | ||
| 3780 | } | ||
| 3781 | |||
| 3782 | arg = (dfsarg_generic_t) { | ||
| 3783 | .cube = cubetofast(cube), | ||
| 3717 | .maxsols = maxsols, | 3784 | .maxsols = maxsols, |
| 3718 | .sols = sols, | 3785 | .sols = sols, |
| 3719 | .nsols = 0, | 3786 | .nsols = 0, |
| @@ -3722,6 +3789,116 @@ solve_generic( | |||
| 3722 | .estimate = estimate, | 3789 | .estimate = estimate, |
| 3723 | }; | 3790 | }; |
| 3724 | 3791 | ||
| 3725 | return solve_generic_dfs(arg); | 3792 | ret = 0; |
| 3793 | first = -1; | ||
| 3794 | for (arg.depth = minmoves; arg.depth <= maxmoves; arg.depth++) { | ||
| 3795 | tmp = solve_generic_dfs(arg); | ||
| 3796 | ret += tmp; | ||
| 3797 | if (tmp != 0) | ||
| 3798 | first = arg.depth; | ||
| 3799 | |||
| 3800 | DBG_LOG("Found %" PRId64 " solutions at depth %" PRIu8 "\n", | ||
| 3801 | tmp, arg.depth); | ||
| 3802 | |||
| 3803 | if (ret >= maxsols) | ||
| 3804 | break; | ||
| 3805 | |||
| 3806 | if (optimal >= 0 && first >= 0 && arg.depth - first == optimal) | ||
| 3807 | break; | ||
| 3808 | } | ||
| 3809 | |||
| 3810 | DBG_ASSERT(ret <= maxsols, ret, | ||
| 3811 | "solve: found more than 'maxsols' solutions\n"); | ||
| 3812 | |||
| 3813 | return ret; | ||
| 3814 | } | ||
| 3815 | |||
| 3816 | static uint8_t | ||
| 3817 | estimate_simple(cube_fast_t cube) | ||
| 3818 | { | ||
| 3819 | return issolved_fast(cube) ? 0 : 1; | ||
| 3820 | } | ||
| 3821 | |||
| 3822 | static int64_t | ||
| 3823 | solve_simple( | ||
| 3824 | cube_t cube, | ||
| 3825 | int8_t minmoves, | ||
| 3826 | int8_t maxmoves, | ||
| 3827 | int64_t maxsols, | ||
| 3828 | int8_t optimal, | ||
| 3829 | char *solutions | ||
| 3830 | ) | ||
| 3831 | { | ||
| 3832 | return solve_generic( | ||
| 3833 | cube, | ||
| 3834 | "", | ||
| 3835 | minmoves, | ||
| 3836 | maxmoves, | ||
| 3837 | maxsols, | ||
| 3838 | optimal, | ||
| 3839 | solutions, | ||
| 3840 | &estimate_simple | ||
| 3841 | ); | ||
| 3842 | } | ||
| 3843 | |||
| 3844 | int64_t | ||
| 3845 | solve( | ||
| 3846 | cube_t cube, | ||
| 3847 | char *solver, | ||
| 3848 | char *options, | ||
| 3849 | char *nisstype, | ||
| 3850 | int8_t minmoves, | ||
| 3851 | int8_t maxmoves, | ||
| 3852 | int64_t maxsols, | ||
| 3853 | int8_t optimal, | ||
| 3854 | void *data, | ||
| 3855 | char *solutions | ||
| 3856 | ) | ||
| 3857 | { | ||
| 3858 | DBG_WARN(!strcmp(options, ""), | ||
| 3859 | "solve: 'options' not implemented yet, ignoring\n"); | ||
| 3860 | |||
| 3861 | DBG_WARN(!strcmp(nisstype, ""), | ||
| 3862 | "solve: NISS not implemented yet, ignoring 'nisstype'\n"); | ||
| 3863 | |||
| 3864 | DBG_WARN(data == NULL, | ||
| 3865 | "solve: 'data' not implemented yet, ignoring\n"); | ||
| 3866 | |||
| 3867 | if (!strcmp(solver, "simple")) { | ||
| 3868 | return solve_simple( | ||
| 3869 | cube, | ||
| 3870 | minmoves, | ||
| 3871 | maxmoves, | ||
| 3872 | maxsols, | ||
| 3873 | optimal, | ||
| 3874 | solutions | ||
| 3875 | ); | ||
| 3876 | } else { | ||
| 3877 | DBG_LOG("solve: unknown solver\n"); | ||
| 3878 | return -1; | ||
| 3879 | } | ||
| 3880 | |||
| 3881 | DBG_LOG("solve: error\n"); | ||
| 3882 | return -1; | ||
| 3883 | } | ||
| 3884 | |||
| 3885 | void | ||
| 3886 | multisolve(int n, cube_t *cube, char *solver, void *data, char *sols) | ||
| 3887 | { | ||
| 3888 | char *s; | ||
| 3889 | int i; | ||
| 3890 | |||
| 3891 | s = sols; | ||
| 3892 | for (i = 0; i < n; i++) { | ||
| 3893 | solve(cube[i], solver, "", "normal", 0, -1, 1, 0, NULL, s); | ||
| 3894 | while (s++); | ||
| 3895 | } | ||
| 3896 | } | ||
| 3897 | |||
| 3898 | int64_t | ||
| 3899 | gendata(char *solver, void *data) | ||
| 3900 | { | ||
| 3901 | DBG_LOG("gendata: not implemented yet\n"); | ||
| 3902 | |||
| 3903 | return -1; | ||
| 3726 | } | 3904 | } |
| 3727 | */ | ||
| @@ -130,7 +130,7 @@ int64_t solve( | |||
| 130 | * maximum length is unlimited. | 130 | * maximum length is unlimited. |
| 131 | */ | 131 | */ |
| 132 | int64_t maxsols, /* The maximum number of solutions. */ | 132 | int64_t maxsols, /* The maximum number of solutions. */ |
| 133 | int64_t optimal, /* All solutions at most "optimal" moves from the | 133 | int8_t optimal, /* All solutions at most "optimal" moves from the |
| 134 | * shortest solution (respecting minmoves) are found. | 134 | * shortest solution (respecting minmoves) are found. |
| 135 | * If negative, this parameter is ignored. | 135 | * If negative, this parameter is ignored. |
| 136 | */ | 136 | */ |
