diff --git a/2021/RESULTS.txt b/2021/RESULTS.txt index ba61fe6..30ba396 100644 --- a/2021/RESULTS.txt +++ b/2021/RESULTS.txt @@ -283,12 +283,12 @@ aoc-c : res=1162571910364852 ========================================= aoc-c : res=11120 - time: 0:00.16 real, 0.14 user, 0.01 sys - context-switch: 34+1, page-faults: 0+4593 + time: 0:00.14 real, 0.13 user, 0.00 sys + context-switch: 3+1, page-faults: 0+3716 aoc-c : res=49232 - time: 0:00.09 real, 0.08 user, 0.00 sys - context-switch: 3+1, page-faults: 0+3454 + time: 0:00.08 real, 0.06 user, 0.01 sys + context-switch: 10+1, page-faults: 0+2768 ========================================= ================= day24 ================= diff --git a/2021/day23/aoc-c.c b/2021/day23/aoc-c.c index b8ccbce..456eb23 100644 --- a/2021/day23/aoc-c.c +++ b/2021/day23/aoc-c.c @@ -21,70 +21,55 @@ #include "bits.h" #include "list.h" -typedef enum { - A, B, C, D -} amphipod_t; - -static const u64 cost[] = { +static const u32 cost[] = { 1, 10, 100, 1000 }; -#define _ROOM_A 0x00000F00 /* 000000000000111100000000*/ -#define _ROOM_B 0x0000F000 /* 000000001111000000000000*/ -#define _ROOM_C 0x000F0000 /* 000011110000000000000000*/ -#define _ROOM_D 0x00F00000 /* 111100000000000000000000*/ -#define _ROOM 0x00FFFF00 /* 111111111111111100000000 */ -#define _HALLWAY 0x0000007F /* 000000000000000001111111 */ +#define ROOM_A 0x00000F00 /* 000000000000111100000000 */ +#define ROOM_B 0x0000F000 /* 000000001111000000000000 */ +#define ROOM_C 0x000F0000 /* 000011110000000000000000 */ +#define ROOM_D 0x00F00000 /* 111100000000000000000000 */ +#define ROOMS 0x00FFFF00 /* 111111111111111100000000 */ +#define HALLWAY 0x0000007F /* 000000000000000001111111 */ #define BIT(c) (1 << (c)) #define RAND_SEED 1337 /* seed for random generator */ -static u32 rooms[4] = { _ROOM_A, _ROOM_B, _ROOM_C, _ROOM_D }; -static u64 result = -1; +static u32 rooms[4] = { ROOM_A, ROOM_B, ROOM_C, ROOM_D }; +static u32 result = -1; +/* full position description + */ typedef struct pos { - u32 amp[4]; /* bitmask of amphipods position */ + u32 amp[4]; /* bitmask of amphipods positions */ u32 occupied; /* bitmask for all occupied cells */ u32 final; /* bitmask for correct position */ - u64 zobrist; /* for zobrist_2() */ - u64 cost; /* cost till this position */ - struct list_head list; /* */ + u32 zobrist; /* for zobrist_2() */ + u32 cost; /* cost till this position */ + struct list_head list; /* positions list */ } pos_t; +/* zobrist hash used to ignore positions already seen + */ typedef struct hash { - u64 zobrist; /* zobrist hash */ - u32 amp[4]; - u64 cost; - struct list_head list; + u32 zobrist; /* zobrist hash */ + u32 amp[4]; /* bitmask of amphipods positions */ + u32 cost; /* cost for this hash */ + struct list_head list; /* collision list */ } hash_t; -#define HASH_SIZE 131071 -#define HASH_SEEN (HASH_SIZE + 1) +//#define HASH_SIZE 131072 +#define HASH_SIZE 65536 -struct { - u32 count; - struct list_head list; -} hasht[HASH_SIZE]; - -static inline u32 get_occupancy(pos_t *pos) -{ - return pos->amp[A] | pos->amp[B] | pos->amp[C] | pos->amp[D]; -} +struct list_head hasht[HASH_SIZE]; pool_t *pool_pos; pool_t *pool_hash; LIST_HEAD(pos_queue); -static u64 zobrist_table[24][4]; - -/* from https://stackoverflow.com/a/33021408/3079831 - */ -#define IMAX_BITS(m) ((m)/((m)%255+1) / 255%255*8 + 7-86/((m)%255+12)) -#define RAND_MAX_WIDTH IMAX_BITS(RAND_MAX) -_Static_assert((RAND_MAX & (RAND_MAX + 1u)) == 0, "RAND_MAX not a Mersenne number"); - +static u32 zobrist_table[24][4]; /* * ############# @@ -98,111 +83,38 @@ _Static_assert((RAND_MAX & (RAND_MAX + 1u)) == 0, "RAND_MAX not a Mersenne numbe * We name a-g H1-H7, h & l are A1-A2, i & m are B1 & B2, etc... */ -/* note that to determine of hallway space is left or right, +/* note that to determine if hallway space is left or right, * we simply need to divide the room number by 4. + * Example: Room C cells are 16-19. + * We have: 16 / 4 = 16 >> 2 = 4, and 19 / 4 = 19 >> 2 = 4, meaning + * that H1 (0), H2 (1), H3 (2), H4 (3) are left. */ -typedef enum { - _H1 = 0, _H2, _H3, _H4, _H5, _H6, _H7, /* 0-6 */ - _WRONG = 7, /* 7 */ - _A1 = 8, _A2, _A3, _A4, /* 8-11 */ - _B1, _B2, _B3, _B4, /* 12-15 */ - _C1, _C2, _C3, _C4, /* 16-19 */ - _D1, _D2, _D3, _D4, /* 20-23 */ -} _space_t; +enum squares { + H1 = 0, H2, H3, H4, H5, H6, H7 = 6, /* 0-6 */ + A1 = 8, A2, A3, A4, /* 8-11 */ + B1, B2, B3, B4, /* 12-15 */ + C1, C2, C3, C4, /* 16-19 */ + D1, D2, D3, D4, /* 20-23 */ +}; -#define HALLWAY(b) ((b) & _HALLWAY) -#define ROOM(b) ((b) & _ROOM) - -#define IN_HALLWAY(c) ((int)(c) >= _H1 && (int)(c) <= _H7) -#define IN_ROOM(c) (((int)(c) >= _A1 && (int)(c) <= _A4) || \ - ((int)(c) >= _B1 && (int)(c) <= _B4) || \ - ((int)(c) >= _C1 && (int)(c) <= _C4) || \ - ((int)(c) >= _D1 && (int)(c) <= _D4)) - -#define LEFT 0 +#define LEFT 0 #define RIGHT 1 -static s32 room_exit[4][2][6] = { - { { _H2, _H1, -1 }, /* room A left */ - { _H3, _H4, _H5, _H6, _H7, -1 } /* room A right */ - }, - { { _H3, _H2, _H1, -1 }, /* room B left */ - { _H4, _H5, _H6, _H7, -1 } /* room B right */ - }, - { { _H4, _H3, _H2, _H1, -1 }, /* room C left */ - { _H5, _H6, _H7, -1 } /* room C right */ - }, - { { _H5, _H4, _H3, _H2, _H1, -1 }, /* room D left */ - { _H6, _H7, -1 } /* room D right */ - } -}; - - -char *cells[] = { - "H1", "H2", "H3", "H4", "H5", "H6", "H7", "BAD", - "A1", "A2", "A3", "A4", - "B1", "B2", "B3", "B4", - "C1", "C2", "C3", "C4", - "D1", "D2", "D3", "D4", -}; - -typedef enum { - H1 = BIT(_H1), H2 = BIT(_H2), H3 = (_H3), H4 = (_H4), - H5 = (_H5), H6 = (_H6), H7 = (_H7), - A1 = (_A1), A2 = (_A2), A3 = (_A3), A4 = (_A4), - B1 = (_B1), B2 = (_B2), B3 = (_B3), B4 = (_B4), - C1 = (_C1), C2 = (_C2), C3 = (_C3), C4 = (_C4), - D1 = (_D1), D2 = (_D2), D3 = (_D3), D4 = (_D4), -} space_t; - -/* Steps to move to hallway +/** + * set bits between 2 positions, excluding MSB one: + * setbits(2, 4) -> 0001100 + * pos: 4 2 */ -typedef enum { - A1H = 1, A2H = 2, A3H = 3, A4H = 4 -} out_t; +#define setbits(i, j) (((1 << ((j) - (i))) - 1) << (i)) -/* Mask which disallow moves to hallway +/* distance between position over rooms to other hallway positions. */ -typedef struct { - uint mask, dist; -} possible_move_t; - -/* Steps to move from space outside room to hallway destination - */ -typedef enum { - AH1 = 2, AH2 = 1, AH3 = 1, AH4 = 3, AH5 = 5, AH6 = 7 , AH7 = 8, - BH1 = 4, BH2 = 3, BH3 = 1, BH4 = 1, BH5 = 3, BH6 = 5 , BH7 = 6, - CH1 = 6, CH2 = 5, CH3 = 3, CH4 = 1, CH5 = 1, CH6 = 3 , CH7 = 4, - DH1 = 8, DH2 = 7, DH3 = 5, DH4 = 3, DH5 = 1, DH6 = 1 , DH7 = 2 -} steps_t; - -/* - * ############# - * #ab.c.d.e.fg# - * ###h#i#j#k### - * #l#m#n#o# - * #p#q#r#s# - * #t#u#v#w# - * ######### - */ - -/* set bits between 2 positions - * setbits(2, 4) -> 0011100 - */ -static u32 setbits(int from, int to) -{ - u32 ret = 0; - for (int i = from; i < to; ++i) - ret |= BIT(i); - log_f(4, "(%d, %d) = %d\n", from, to, ret); - return ret; -} - static int h2h[][7] = { - { 2, 1, 1, 3, 5, 7, 8 }, /* A */ - { 4, 3, 1, 1, 3, 5, 6 }, /* B */ - { 6, 5, 3, 1, 1, 3, 4 }, /* C */ - { 8, 7, 5, 3, 1, 1, 2 } /* D */ + /* H1 H2 H3 H4 H5 H6 H7 */ + { 2, 1, 1, 3, 5, 7, 8 }, /* from virtual cell on top of A */ + { 4, 3, 1, 1, 3, 5, 6 }, /* B */ + { 6, 5, 3, 1, 1, 3, 4 }, /* C */ + { 8, 7, 5, 3, 1, 1, 2 } /* D */ }; /* get a position from memory pool @@ -237,11 +149,8 @@ static void free_pos(pos_t *pos) */ static void push_pos(pos_t *pos) { - if (pos) { + if (pos) list_add(&pos->list, &pos_queue); - } else { - exit(1); - } } /* pop a position from stack @@ -255,61 +164,44 @@ static pos_t *pop_pos() return pos; } -static u64 rand64(void) { - u64 r = 0; - for (int i = 0; i < 64; i += RAND_MAX_WIDTH) { - r <<= RAND_MAX_WIDTH; - r ^= (unsigned) rand(); - } - return r; -} - static void zobrist_init() { - log_f(1, "seed=%d rand_max=%d\n", RAND_SEED, RAND_MAX); - srand(RAND_SEED); for (int i = 0; i < 24; ++i) { for (int j = 0; j < 4; ++j) { - zobrist_table[i][j] = rand64(); + zobrist_table[i][j] = rand(); } } } -static inline u64 zobrist_1(pos_t *pos) +static inline u32 zobrist_1(pos_t *pos) { u32 tmp; int bit; - u64 zobrist = 0; + u32 zobrist = 0; for (int amp = 0; amp < 4; ++amp) { bit_for_each32_2(bit, tmp, pos->amp[amp]) { - //log_f(2, "amp=%d/%c bit=%d\n", amp, amp+'A', bit); zobrist ^= zobrist_table[bit][amp]; } } - log_f(1, "zobrist=%lu -> %lu\n", zobrist, zobrist % HASH_SIZE); return zobrist; } /* calculate zobrist hash from previous zobrist value */ -static inline u64 zobrist_2(pos_t *pos, int amp, u32 from, u32 to) +static inline u32 zobrist_2(pos_t *pos, int amp, u32 from, u32 to) { - u64 zobrist = pos->zobrist; + u32 zobrist = pos->zobrist; zobrist ^= zobrist_table[from][amp]; zobrist ^= zobrist_table[to][amp]; - log_f(1, "zobrist(%d, %u, %u)=%lu -> %lu (amp=%d from=%u to=%u)\n", - amp, from, to, zobrist, zobrist % HASH_SIZE, amp, from, to); return zobrist; } static void hash_init() { - for (int i = 0; i < HASH_SIZE; ++i) { - hasht[i].count = 0; - INIT_LIST_HEAD(&hasht[i].list); - } + for (int i = 0; i < HASH_SIZE; ++i) + INIT_LIST_HEAD(&hasht[i]); } /* get a position from memory pool @@ -331,11 +223,10 @@ static hash_t *get_hash(pos_t *pos) static hash_t *hash(pos_t *pos) { hash_t *cur; - u32 hashpos; - u64 zobrist = pos->zobrist; + u32 hashpos, zobrist = pos->zobrist; hashpos = zobrist % HASH_SIZE; - list_for_each_entry(cur, &hasht[hashpos].list, list) { + list_for_each_entry(cur, &hasht[hashpos], list) { if (zobrist == cur->zobrist) { if (pos->amp[0] == cur->amp[0] && pos->amp[1] == cur->amp[1] && @@ -346,35 +237,55 @@ static hash_t *hash(pos_t *pos) } } } - hasht[hashpos].count++; cur = get_hash(pos); - list_add(&cur->list, &hasht[hashpos].list); + list_add(&cur->list, &hasht[hashpos]); return cur; } - -/* generate possible moves between hallway and rooms +/* Next table shows the hallway possible moves from rooms, nearest to farthest. + * When generating moves, this allows to stop one direction as soon as move + * is impossible. + * Example: Moving right from room C, if H6 is occupied, we won't try to + * evaluate a move on H7. */ +static int room_exit[4][2][6] = { + { { H2, H1, -1 }, /* room A left */ + { H3, H4, H5, H6, H7, -1 } }, /* right */ + { { H3, H2, H1, -1 }, /* room B left */ + { H4, H5, H6, H7, -1 } }, /* right */ + { { H4, H3, H2, H1, -1 }, /* room C left */ + { H5, H6, H7, -1 } }, /* right */ + { { H5, H4, H3, H2, H1, -1 }, /* room D left */ + { H6, H7, -1 } } /* right */ +}; + +/* Mask which disallow moves to hallway + */ +typedef struct { + uint mask; + uint dist; +} possible_move_t; + static possible_move_t moves[24][24]; -/* calculate distance and move mask for all possible moves - * (room -> hallway ans hallway -> room) +/* Generate all possible moves and moves masks + * (rooms -> hallway and hallway -> rooms) */ -static possible_move_t (*init_moves())[24] +static void init_moves(void) { int hallway, room, dist, pos; u32 mask_h, mask_r; - for (room = _A1; room <= _D4; ++room) { + for (room = A1; room <= D4; ++room) { pos = (room >> 2) - 2; - for (hallway = _H1; hallway <= _H7; ++hallway) { + for (hallway = H1; hallway <= H7; ++hallway) { dist = h2h[pos][hallway] + room % 4 + 1; /* from room to hallway */ - if (room >> 2 > hallway) + if (room >> 2 > hallway) /* left */ mask_h = setbits(hallway, room >> 2); - else + else /* right */ mask_h = setbits(room >> 2, hallway + 1); mask_r = setbits(room & ~3, room); moves[room][hallway].mask = mask_r | mask_h; @@ -388,19 +299,15 @@ static possible_move_t (*init_moves())[24] mask_r = setbits(room & ~3, room + 1); moves[hallway][room].mask = mask_r | mask_h; moves[hallway][room].dist = dist; - } - log(3, "\n"); } - return moves; } - -static pos_t *newmove(pos_t *pos, amphipod_t amp, u32 from, u32 to) +static pos_t *newmove(pos_t *pos, int amp, u32 from, u32 to) { + pos_t *newpos; int rows = popcount32(pos->amp[0]); possible_move_t *move = &moves[from][to]; - pos_t *newpos; u32 bit_from = BIT(from), bit_to = BIT(to); if (pos->cost + move->dist * cost[amp] >= result) @@ -414,15 +321,14 @@ static pos_t *newmove(pos_t *pos, amphipod_t amp, u32 from, u32 to) newpos->occupied |= bit_to; newpos->cost += move->dist * cost[amp]; - if (HALLWAY(bit_from)) { /* from hallway */ - newpos->final |= BIT(to); + if (bit_to & ROOMS) { /* to room => final position */ + newpos->final |= bit_to; if (popcount32(newpos->final) == rows * 4) { if (newpos->cost < result) result = newpos->cost; free_pos(newpos); return NULL; } - } newpos->zobrist = zobrist_2(newpos, amp, from, to); @@ -439,25 +345,23 @@ static pos_t *newmove(pos_t *pos, amphipod_t amp, u32 from, u32 to) */ static void genmoves(pos_t *pos) { - amphipod_t amp; + int amp, cell, rows = popcount32(pos->amp[0]); u32 tmp; - int bit; - int rows = popcount32(pos->amp[0]); - for (amp = A; amp <= D; ++amp) { - u32 cur = pos->amp[amp]; - bit_for_each32_2(bit, tmp, cur) { - if (bit >= _A1) { /* in a room */ - if (BIT(bit) & pos->final) + for (amp = 0; amp < 4; ++amp) { + u32 cur_amp = pos->amp[amp]; + bit_for_each32_2(cell, tmp, cur_amp) { + if (cell >= A1) { /* in a room */ + if (BIT(cell) & pos->final) continue; - int room = (bit >> 2) - 2; + int room = (cell >> 2) - 2; for (int side = LEFT; side <= RIGHT; ++side) { int *d = room_exit[room][side]; for (; *d != -1; ++d) { - possible_move_t *move = &moves[bit][*d]; + possible_move_t *move = &moves[cell][*d]; if (move->mask & pos->occupied) break; - newmove(pos, amp, bit, *d); + newmove(pos, amp, cell, *d); } } @@ -472,7 +376,7 @@ static void genmoves(pos_t *pos) if ((room & pos->final) != (room & pos->occupied)) continue; bit_for_each32_2(dest, tmp, room) { - possible_move_t *move = &moves[bit][dest]; + possible_move_t *move = &moves[cell][dest]; if (move->mask & pos->occupied) break; found = dest; @@ -480,7 +384,7 @@ static void genmoves(pos_t *pos) break; } if (found) - newmove(pos, amp, bit, found); + newmove(pos, amp, cell, found); } } } @@ -503,7 +407,6 @@ static pos_t *read_input(int part) while ((buflen = getline(&buf, &alloc, stdin)) > 0) { buf[--buflen] = 0; - log(1, "line=%d str=%s\n", line, buf); if (line == 2 || line == 3) { if (part == 2 && line == 3) { @@ -528,7 +431,7 @@ static pos_t *read_input(int part) line++; adjline++; } - pos->occupied = get_occupancy(pos); + pos->occupied = pos->amp[0] | pos->amp[1] | pos->amp[2] | pos->amp[3]; /* check if some amphipods are already in correct place */ for (int room = 0; room < 4; ++room) { @@ -581,6 +484,8 @@ int main(int ac, char **av) pool_pos = pool_create("pos", 1024, sizeof(pos_t)); pool_hash = pool_create("hash", 1024, sizeof(hash_t)); + //printf("b1 = %d\n", setbits(2, 4)); + //printf("b2 = %d\n", setbits(2, 4)); zobrist_init(); hash_init(); init_moves(); @@ -593,6 +498,6 @@ int main(int ac, char **av) free_pos(pos); } - printf("%s : res=%ld\n", *av, result); + printf("%s : res=%d\n", *av, result); exit(0); }