#include "zobrist.h" // =================================================================== // Globals // =================================================================== static uint64_t *zobrist[15]; // =================================================================== // Helpers // =================================================================== // =================================================================== // Exported method implementations // =================================================================== int zobrist_init(void) { for (int k=0; k<15; k++) { if (zobrist[k] != NULL) return EXIT_FAILURE; } for (int j=0; j<15; j++) { zobrist[j] = malloc(sizeof(uint64_t)*board_size*board_size*(2*3+1)); for (int k=0; k>= 1) hash ^= zobrist[h][l*(2*3+1)+(c&1)*3+s]; } return hash; } uint64_t zobrist_apply(const action_t action, uint64_t hash) { const enum A_TYPE type = GET_TYPE(action); const int8_t loc = GET_LOC(action); if (type == A_PLACE) { enum COLOUR c = (current_colour == C_BLACK) ? C_WHITE : C_BLACK; hash ^= zobrist[0][loc*(2*3+1) +c*3 +GET_DATA0(action)]; } else { const uint8_t gaps = GET_DATA0(action) & 0x7F, crush = GET_DATA0(action) & 0x80, num = GET_DATA1(action) & 0x0F, dir = GET_DATA1(action) >> 4; const int8_t delta = move_deltas[dir]; int8_t steps = 1; uint8_t gap_bit = 1, num_dropped = 1, total = COUNT_AT(loc); for (int8_t d = 1; d < num; d++, num_dropped++, gap_bit <<= 1) { if (gaps & gap_bit) { const int8_t target = loc+steps*delta, th = COUNT_AT(target); // Stash these stones to offset for the height at source total += num_dropped; // Apply XOR for stones at source and current target uint8_t point = 1; for (int k = 0, ht = th-1, hs = total-1; k < num_dropped; k++, ht--, hs--, point<<=1) { hash ^= zobrist[ht][target*(2*3+1) +(point & colours[target])*3 +STONE_FLAT]; hash ^= zobrist[hs][loc*(2*3+1) +(point & colours[target])*3 +STONE_FLAT]; } // Continue processing gap sequence num_dropped = 0; steps++; } } total += num_dropped; const int8_t target = loc+steps*delta, th = COUNT_AT(target); const enum STONE_VARIANT top_stone = STONE_AT(target); // Stash these stones to offset for the height at source // Apply XOR for stones at source and end target. After this // source will be correct, but we must account for crush @ target. uint8_t point = 1; for (int k = 0, ht = th-1, hs = total-1; k < num_dropped; k++, ht--, hs--, point<<=1) { if (k == 0) { hash ^= zobrist[ht][target*(2*3+1) +(point & colours[target])*3 +top_stone]; hash ^= zobrist[hs][loc*(2*3+1) +(point & colours[target])*3 +top_stone]; } else { hash ^= zobrist[ht][target*(2*3+1) +(point & colours[target])*3 +STONE_FLAT]; hash ^= zobrist[hs][loc*(2*3+1) +(point & colours[target])*3 +STONE_FLAT]; } } // Correct for crush if (crush) { hash ^= zobrist[th-1][target*(2*3+1) +(colours[target] & 1)*3 +STONE_FLAT]; hash ^= zobrist[th-1][target*(2*3+1) +(colours[target] & 1)*3 +STONE_STANDING]; } } return hash; }