h48

A prototype for an optimal Rubik's cube solver, work in progress.
git clone https://git.tronto.net/h48
Download | Log | Files | Refs | README | LICENSE

commit 28ad019d62583b7e89b4e76922aa73857d5876eb
parent 49b9c4a516f72e03d53277075f4580e2df8f0e63
Author: Sebastiano Tronto <sebastiano@tronto.net>
Date:   Tue, 28 May 2024 15:42:26 +0200

Added roadmap for refactor and some simple routines

Diffstat:
MTODO.txt | 29++++++++++++++++++++++-------
Msrc/cube.c | 6++----
Msrc/cube_avx2.h | 25++++++++++++++++++++++++-
Msrc/cube_portable.h | 22+++++++++++++++++++++-
Msrc/cube_routines.h | 41+++++++++++++++++++++++++++++++++++++++++
Rtest/001_cube_conversion/00_solved.in -> test/001_pieces/01_solved.in | 0
Atest/001_pieces/01_solved.out | 2++
Atest/001_pieces/02_scrambled.in | 1+
Atest/001_pieces/02_scrambled.out | 2++
Atest/001_pieces/pieces_tests.c | 28++++++++++++++++++++++++++++
Rtest/001_cube_conversion/00_solved.out -> test/002_cube_conversion/00_solved.in | 0
Rtest/001_cube_conversion/00_solved.in -> test/002_cube_conversion/00_solved.out | 0
Rtest/001_cube_conversion/01_scrambled.in -> test/002_cube_conversion/01_scrambled.in | 0
Rtest/001_cube_conversion/01_scrambled.out -> test/002_cube_conversion/01_scrambled.out | 0
Rtest/001_cube_conversion/cube_conversion_tests.c -> test/002_cube_conversion/cube_conversion_tests.c | 0
15 files changed, 143 insertions(+), 13 deletions(-)

diff --git a/TODO.txt b/TODO.txt @@ -1,12 +1,30 @@ -Correctness - - check all bitwise operations specifically - - consider adding more warnings (-pedantic?) or using more static analyzers +Refactoring: remove cube_fast_t and add b32 format + x added b32 converter by piece (not tested, will be tested automatically) + x added piece functions (e.g. corner(cube, i)) + (would be more efficient to just convert the whole thing to arrays...) + - replace all usages of cube_t with cube_fast_t and piece functions + (this is mainly in cube_routines) + (fix tests in tandem with main code) + cubetofast fasttocube + zero and solved + solvedcube(void) + [cube.h] isconsistent, issolvable, issolved, equal, iserror + [cube.h] compose, inverse + [cube.h] applymoves, applytrans + [cube.h] readcube writecube + [cube.h] solve + - add b32 i/o format as default + - remove cube_t type + - rename cube_fast_t to cube_t + - if all public functions work with strings, always use return value + as error code (solve already does this), and use string as buffer + to print error Solver - write a solver (how many tricks? some, but not all are needed) More utilities for tables (in cube.h) - - a "dryrun" function that only tells you the size needed + - for tables, a "dryrun" function that only tells you the size needed - check hash of generated data Goal: find out which k value is best @@ -15,9 +33,6 @@ Goal: find out which k value is best - benchmark for different sizes! Refactoring - - remove cube type and some low-level utilities from interface, - rename cube_fast_t to cube_t - - add b64 i/o format, base64 encoded cube, one 6-bit word per piece - transformations: remove switch to make shorter, but keep performance ## H48 optimal solver (some has already been implemented) diff --git a/src/cube.c b/src/cube.c @@ -9,10 +9,8 @@ #define DBG_LOG(...) fprintf(stderr, __VA_ARGS__) #define DBG_WARN(condition, ...) if (!(condition)) DBG_LOG(__VA_ARGS__); #define DBG_ASSERT(condition, retval, ...) \ - if (!(condition)) { \ - DBG_LOG(__VA_ARGS__); \ - return retval; \ - } + if (!(condition)) { DBG_LOG(__VA_ARGS__); return retval; } + #else #define _static static #define _static_inline static inline diff --git a/src/cube_avx2.h b/src/cube_avx2.h @@ -14,6 +14,8 @@ _static_inline cube_fast_t fastcube( uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t ); +_static uint8_t corner(cube_fast_t, int); +_static uint8_t edge(cube_fast_t, int); _static cube_fast_t cubetofast(cube_t); _static cube_t fasttocube(cube_fast_t); _static_inline bool equal_fast(cube_fast_t, cube_fast_t); @@ -68,6 +70,28 @@ fastcube( ); } +_static uint8_t +corner(cube_fast_t c, int i) +{ + uint8_t aux[32]; + + DBG_ASSERT(i >= 0 && i < 8, 255, "Corner must be between 0 and 7\n"); + _mm256_storeu_si256((__m256i_u *)aux, c); + + return aux[i]; +} + +_static uint8_t +edge(cube_fast_t c, int i) +{ + uint8_t aux[32]; + + DBG_ASSERT(i >= 0 && i < 12, 255, "Edge must be between 0 and 11\n"); + _mm256_storeu_si256((__m256i_u *)aux, c); + + return aux[i+16]; +} + _static cube_fast_t cubetofast(cube_t a) { @@ -338,4 +362,3 @@ invcoord_fast_esep(int64_t esep) return ret; } - diff --git a/src/cube_portable.h b/src/cube_portable.h @@ -1,4 +1,7 @@ -typedef cube_t cube_fast_t; +typedef struct { + uint8_t corner[8]; + uint8_t edge[12]; +} cube_fast_t; _static_inline cube_fast_t fastcube( uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, @@ -6,6 +9,8 @@ _static_inline cube_fast_t fastcube( uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t ); +_static uint8_t corner(cube_fast_t, int); +_static uint8_t edge(cube_fast_t, int); _static cube_fast_t cubetofast(cube_t); _static cube_t fasttocube(cube_fast_t); _static_inline bool equal_fast(cube_fast_t, cube_fast_t); @@ -66,6 +71,21 @@ fastcube( return cube; } +_static uint8_t +corner(cube_fast_t c, int i) +{ + DBG_ASSERT(i >= 0 && i < 8, 255, "Corner must be between 0 and 7\n"); + + return c.corner[i]; +} +_static uint8_t +edge(cube_fast_t c, int i) +{ + DBG_ASSERT(i >= 0 && i < 12, 255, "Edge must be between 0 and 11\n"); + + return c.edge[i]; +} + _static cube_fast_t cubetofast(cube_t cube) { diff --git a/src/cube_routines.h b/src/cube_routines.h @@ -12,6 +12,10 @@ _static cube_t readcube_LST(const char *); _static int writepiece_LST(uint8_t, char *); _static void writecube_H48(cube_t, char *); _static void writecube_LST(cube_t, char *); +_static uint8_t b32toedge(char); +_static uint8_t b32tocorner(char); +_static char edgetob32(uint8_t); +_static char cornertob32(uint8_t); _static uint8_t readmove(char); _static uint8_t readmodifier(char); _static uint8_t readtrans(const char *); @@ -494,6 +498,43 @@ writecube_LST(cube_t cube, char *buf) } _static uint8_t +b32toedge(char c) +{ + DBG_ASSERT((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'g'), 255, + "Error reading base32 piece"); + + return c <= 'Z' ? (uint8_t)(c - 'A') : (uint8_t)(c - 'a'); +} + +_static uint8_t +b32tocorner(char c) { + uint8_t val; + + DBG_ASSERT((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'g'), 255, + "Error reading base32 piece"); + + val = c <= 'Z' ? (uint8_t)(c - 'A') : (uint8_t)(c - 'a') + 26; + + return (val & 7) | ((val & 24) << 2); +} + +_static char +edgetob32(uint8_t edge) +{ + return edge <= 26 ? 'A' + (char)edge : 'a' + (char)(edge - 26); +} + +_static char +cornertob32(uint8_t corner) +{ + uint8_t val; + + val = (corner & 7) | ((corner & 96) >> 2); + + return val <= 26 ? 'A' + (char)val : 'a' + (char)(val - 26); +} + +_static uint8_t readmove(char c) { switch (c) { diff --git a/test/001_cube_conversion/00_solved.in b/test/001_pieces/01_solved.in diff --git a/test/001_pieces/01_solved.out b/test/001_pieces/01_solved.out @@ -0,0 +1,2 @@ +0 1 2 3 4 5 6 7 +0 1 2 3 4 5 6 7 8 9 10 11 diff --git a/test/001_pieces/02_scrambled.in b/test/001_pieces/02_scrambled.in @@ -0,0 +1 @@ +FL0 DB0 UB1 FR0 UR0 DF0 UF0 BR1 UL1 BL1 DL0 DR0 DFR1 UFR1 UBR1 UFL2 DBR2 DFL0 DBL2 UBL0 diff --git a/test/001_pieces/02_scrambled.out b/test/001_pieces/02_scrambled.out @@ -0,0 +1,2 @@ +38 32 37 68 67 2 71 1 +9 2 17 8 4 3 0 27 21 26 6 7 diff --git a/test/001_pieces/pieces_tests.c b/test/001_pieces/pieces_tests.c @@ -0,0 +1,28 @@ +#include "../test.h" + +uint8_t corner(cube_fast_t, int); +uint8_t edge(cube_fast_t, int); + +int main(void) { + int i; + char str[STRLENMAX], *aux; + cube_t cube; + cube_fast_t fast; + + aux = str; + while (fgets(aux, STRLENMAX, stdin) != NULL) + while (*aux != '\n') + aux++; + + cube = readcube("H48", str); + fast = cubetofast(cube); + + for (i = 0; i < 8; i++) + printf("%" PRIu8 " ", corner(fast, i)); + printf("\n"); + for (i = 0; i < 12; i++) + printf("%" PRIu8 " ", edge(fast, i)); + printf("\n"); + + return 0; +} diff --git a/test/001_cube_conversion/00_solved.out b/test/002_cube_conversion/00_solved.in diff --git a/test/001_cube_conversion/00_solved.in b/test/002_cube_conversion/00_solved.out diff --git a/test/001_cube_conversion/01_scrambled.in b/test/002_cube_conversion/01_scrambled.in diff --git a/test/001_cube_conversion/01_scrambled.out b/test/002_cube_conversion/01_scrambled.out diff --git a/test/001_cube_conversion/cube_conversion_tests.c b/test/002_cube_conversion/cube_conversion_tests.c