diff options
Diffstat (limited to '')
| -rw-r--r-- | TODO.txt | 25 | ||||
| -rw-r--r-- | cube.c | 59 | ||||
| -rw-r--r-- | cube.h | 41 |
3 files changed, 94 insertions, 31 deletions
| @@ -1,11 +1,12 @@ | |||
| 1 | ## Generic solver | 1 | ## Solving |
| 2 | |||
| 3 | ### Generic solver | ||
| 2 | 4 | ||
| 3 | * finish implementation | ||
| 4 | * tests: solve full cube (max 7-8 moves?) | 5 | * tests: solve full cube (max 7-8 moves?) |
| 5 | * more tests: eo and other stuff | 6 | * more tests: eo and other stuff |
| 6 | * benchmarks | 7 | * benchmarks |
| 7 | 8 | ||
| 8 | ## Coordinates | 9 | ### Coordinates |
| 9 | 10 | ||
| 10 | * [done] eo | 11 | * [done] eo |
| 11 | * co | 12 | * co |
| @@ -17,22 +18,10 @@ | |||
| 17 | 18 | ||
| 18 | What about symcoord? | 19 | What about symcoord? |
| 19 | 20 | ||
| 20 | ## More I/O | 21 | ### More solvers |
| 21 | |||
| 22 | |||
| 23 | ## Solving | ||
| 24 | |||
| 25 | All solving functions take a cube and some parameters as input. | ||
| 26 | 22 | ||
| 27 | * Depth [uint, <= 20]: all solvers work at fixed depth. The caller | 23 | * solve_light: first based on solve_generic, then optimize; benchmark |
| 28 | implementation can implement an A* search. | 24 | to see up to what length it works best (7 moves? 10 moves?) |
| 29 | * max [int]: the maximum number of solutions to find. Set to a negative | ||
| 30 | value for all solutions. | ||
| 31 | * sol [move_t *]: the array for returning the solutions. The caller | ||
| 32 | should make sure that it can hold at least max * depth values. | ||
| 33 | * Table [uint8_t *]: table with all the necessare pre-computed info. | ||
| 34 | The table can be generated with a companion function, but reading | ||
| 35 | from and writing to file is delegated to the caller implementation. | ||
| 36 | 25 | ||
| 37 | ### Implement the following solvers: | 26 | ### Implement the following solvers: |
| 38 | 27 | ||
| @@ -3688,19 +3688,51 @@ implementation of all the solving algorithms. | |||
| 3688 | 3688 | ||
| 3689 | typedef struct { | 3689 | typedef struct { |
| 3690 | cube_t cube; | 3690 | cube_t cube; |
| 3691 | int (*estimate)(cube_t); | ||
| 3692 | uint8_t depth; | 3691 | uint8_t depth; |
| 3693 | int maxsols; | 3692 | int maxsols; |
| 3694 | move_t *sols; | 3693 | move_t *sols; |
| 3695 | int nsols; | 3694 | int nsols; |
| 3696 | int nmoves; | 3695 | int nmoves; |
| 3697 | move_t moves[20]; | 3696 | move_t moves[20]; |
| 3697 | int (*estimate)(cube_t); | ||
| 3698 | } dfs_arg_t; | 3698 | } dfs_arg_t; |
| 3699 | 3699 | ||
| 3700 | int | 3700 | static bool |
| 3701 | allowednextmove(dfs_arg_t arg, move_t m) | ||
| 3702 | { | ||
| 3703 | int n; | ||
| 3704 | move_t mbase, l1base, l2base, maxis, l1axis, l2axis; | ||
| 3705 | |||
| 3706 | n = arg.nmoves; | ||
| 3707 | |||
| 3708 | if (n == 0) | ||
| 3709 | return true; | ||
| 3710 | |||
| 3711 | mbase = m / 3; | ||
| 3712 | maxis = mbase / 2; | ||
| 3713 | l1base = arg.moves[n-1] / 3; | ||
| 3714 | l1axis = l1base / 2; | ||
| 3715 | |||
| 3716 | if (mbase == l1base || (maxis == l1axis && mbase < l1base)) | ||
| 3717 | return false; | ||
| 3718 | |||
| 3719 | if (n == 1) | ||
| 3720 | return true; | ||
| 3721 | |||
| 3722 | l2base = arg.moves[n-2] / 3; | ||
| 3723 | l2axis = l1base / 2; | ||
| 3724 | |||
| 3725 | return l1axis != l2axis || mbase != l2base; | ||
| 3726 | } | ||
| 3727 | |||
| 3728 | static int | ||
| 3701 | solve_generic_dfs(dfs_arg_t arg) | 3729 | solve_generic_dfs(dfs_arg_t arg) |
| 3702 | { | 3730 | { |
| 3703 | int bound = arg.estimate(arg.cube); | 3731 | dfs_arg_t nextarg; |
| 3732 | int bound, ret; | ||
| 3733 | move_t m; | ||
| 3734 | |||
| 3735 | bound = arg.estimate(arg.cube); | ||
| 3704 | 3736 | ||
| 3705 | if (arg.nsols == arg.maxsols || bound + arg.nmoves > arg.depth) | 3737 | if (arg.nsols == arg.maxsols || bound + arg.nmoves > arg.depth) |
| 3706 | return 0; | 3738 | return 0; |
| @@ -3714,36 +3746,43 @@ solve_generic_dfs(dfs_arg_t arg) | |||
| 3714 | return 1; | 3746 | return 1; |
| 3715 | } | 3747 | } |
| 3716 | 3748 | ||
| 3717 | /* TODO: loop over moves and recur */ | 3749 | memcpy(&nextarg, &arg, sizeof(dfs_arg_t)); |
| 3718 | return 0; | 3750 | nextarg.nmoves = arg.nmoves + 1; |
| 3751 | for (m = 0, ret = 0; m < 18; m++) { | ||
| 3752 | if (allowednextmove(arg, m)) { | ||
| 3753 | nextarg.cube = move(arg.cube, m); | ||
| 3754 | nextarg.moves[arg.nmoves] = m; | ||
| 3755 | ret += solve_generic_dfs(nextarg); | ||
| 3756 | } | ||
| 3757 | } | ||
| 3758 | |||
| 3759 | return ret; | ||
| 3719 | } | 3760 | } |
| 3720 | 3761 | ||
| 3721 | int | 3762 | int |
| 3722 | solve_generic( | 3763 | solve_generic( |
| 3723 | cube_t cube, | 3764 | cube_t cube, |
| 3724 | int (*estimate)(cube_t), | ||
| 3725 | uint8_t depth, | 3765 | uint8_t depth, |
| 3726 | int maxsols, | 3766 | int maxsols, |
| 3727 | move_t *sols | 3767 | move_t *sols |
| 3768 | int (*estimate)(cube_t), | ||
| 3728 | ) | 3769 | ) |
| 3729 | { | 3770 | { |
| 3730 | dfs_arg_t arg; | 3771 | dfs_arg_t arg; |
| 3731 | 3772 | ||
| 3732 | if (!issolvable(cube) || depth > 20) | 3773 | if (!issolvable(cube) || depth > 20 || estimate == NULL) |
| 3733 | return -1; | 3774 | return -1; |
| 3734 | 3775 | ||
| 3735 | arg = (dfs_arg_t) { | 3776 | arg = (dfs_arg_t) { |
| 3736 | .cube = cube, | 3777 | .cube = cube, |
| 3737 | .estimate = estimate, | ||
| 3738 | .depth = depth, | 3778 | .depth = depth, |
| 3739 | .maxsols = maxsols, | 3779 | .maxsols = maxsols, |
| 3740 | .sols = sols, | 3780 | .sols = sols, |
| 3741 | .nsols = 0, | 3781 | .nsols = 0, |
| 3742 | .nmoves = 0, | 3782 | .nmoves = 0, |
| 3743 | .moves = {0} | 3783 | .moves = {0} |
| 3784 | .estimate = estimate, | ||
| 3744 | }; | 3785 | }; |
| 3745 | 3786 | ||
| 3746 | return solve_generic_dfs(arg); | 3787 | return solve_generic_dfs(arg); |
| 3747 | |||
| 3748 | return 0; | ||
| 3749 | } | 3788 | } |
| @@ -169,9 +169,44 @@ int16_t coord_eo(cube_t); /* Edge orientation */ | |||
| 169 | /****************************************************************************** | 169 | /****************************************************************************** |
| 170 | Solvers | 170 | Solvers |
| 171 | 171 | ||
| 172 | Solvers return -1 in case of error, the number of solutions otherwise | 172 | All solvers work at fixed depth, i.e. they will only find solutions of the |
| 173 | specified length. Iterating over the possible lengths, if desired, is left as | ||
| 174 | an implementation detail for the user of this library. | ||
| 173 | 175 | ||
| 174 | TODO | 176 | The solutions are returned as a list of moves, which can then be converted to |
| 177 | a string using writemoves(). | ||
| 178 | |||
| 179 | Unless specified otherwise, all the solutions are not trivially simplifiable. | ||
| 180 | This means that sequences like U U2 or R L R will not appear in any solution. | ||
| 181 | Moreover, two consecutive parallel moves are always going to be sorted in | ||
| 182 | increasing order. For example, L R2 may never appear in a solution, but R2 L | ||
| 183 | could. | ||
| 184 | |||
| 185 | Solvers return -1 in case of error, the number of solutions found otherwise. | ||
| 186 | |||
| 187 | TODO NISS / INVERSE / LINEAR as a mask? | ||
| 188 | |||
| 189 | All solvers take at least the following parameters, satisfying the conditions | ||
| 190 | in square brackets: | ||
| 191 | - cube_t cube [issolvable(cube)]: The cube to solve. | ||
| 192 | - uint8_t depth [depth <= 20]: The lenght of the solution. | ||
| 193 | - int maxsols: The maximum number of solutions to find. The solver | ||
| 194 | stops when the limit is reached. If set to a negative number, all | ||
| 195 | the solutions are found. | ||
| 196 | - move_t *ret: The array where the moves of the solutions are stored. | ||
| 197 | There is no separator between different solutions; to read the | ||
| 198 | solutions, use the fact that all solutions has the same length: the | ||
| 199 | i-th move of the j-th solution is ret[j*depth + i]. | ||
| 200 | |||
| 201 | Some solvers take other parameters. See below for details. | ||
| 175 | ******************************************************************************/ | 202 | ******************************************************************************/ |
| 176 | 203 | ||
| 177 | int solve_generic(cube_t, int (*)(cube_t), uint8_t, int, move_t *); | 204 | int solve_generic( |
| 205 | cube_t cube, | ||
| 206 | uint8_t depth, | ||
| 207 | int maxsols, | ||
| 208 | move_t *ret | ||
| 209 | int (*estimate)(cube_t), | ||
| 210 | ); | ||
| 211 | |||
| 212 | int solve_light(cube_t, int | ||
