diff options
Diffstat (limited to 'include/action_list.c')
| -rw-r--r-- | include/action_list.c | 176 |
1 files changed, 125 insertions, 51 deletions
diff --git a/include/action_list.c b/include/action_list.c index 198cd08..9afb199 100644 --- a/include/action_list.c +++ b/include/action_list.c @@ -9,12 +9,8 @@ action_list_prepend(action_list_t *list, const enum A_TYPE type, const uint8_t loc, const uint8_t data0, const uint8_t data1); -static inline void previous_ply(void); - -static inline void -push_stones(const int8_t location, const uint8_t count, - const uint8_t new_colours, - const enum STONE_VARIANT top_stone); +static inline void inline_previous_ply(void); +static inline void inline_next_ply(void); // =================================================================== // Exported method implementations @@ -97,7 +93,7 @@ action_list_t *action_list_generate(void) { * summands as steps */ for (enum MOVE_DIRECTION dir = M_UP; dir <= M_RIGHT; dir++) { - uint8_t gaps, t, idx, mask; + uint8_t gaps, t; for (uint8_t num = 1; num <= count; num++) { for (uint8_t steps = 1; steps <= end_stops[dir][0] && steps <= num; @@ -146,14 +142,14 @@ void action_take(action_list_t *action) { if (action->type == A_PLACE) { const uint8_t black = (ply&1); switch (action->data0) { - STONE_FLAT: { + case STONE_FLAT: { if (black) black_count--; else white_count--; colours[loc] = current_colour; celldat[loc] = NUM_INC | STONE_FLAT; break; } - STONE_STANDING: { + case STONE_STANDING: { if (black) black_count--; else white_count--; colours[loc] = current_colour; @@ -169,42 +165,53 @@ void action_take(action_list_t *action) { } } } else { - uint8_t drops[board_size]; // we only ever need board_size-1 in - // drops actually, the last spot is to - // skip a bounds check at (*) later - const uint8_t gaps = action->data0, num = action->data1 & 0x0F, // unpack - dir = action->data1 & 0xF0; - uint8_t steps, mask; - // Translate to a drop sequence - drops[0] = 1; mask = 1; steps = 0; - for (uint8_t d = 0; d + 1 < num; d++) { - if (gaps & mask) { - steps++; - drops[steps] = 1; // (*) no bounds check - } else { - drops[steps] += 1; + dir = action->data1 & 0xF0, + delta = deltas[dir]; + + // Unfortunately num == 1 is a special case + if (num > 1) { + uint8_t steps, mask = 1<<(num-2), gaps_prime = gaps; + // Use the Kernighan method to count the set bits + for (steps = 1; gaps_prime; steps++) gaps_prime &= gaps_prime - 1; + // then from the destination to the source + for (uint8_t d = 0; d + 1 < num; d++) { + // transfer the top colour + colours[loc+steps*delta] <<= 1; + colours[loc+steps*delta] |= colours[loc] & 1; + colours[loc] >>= 1; + // increase the stone count, copy top stone if appropriate + celldat[loc+steps*delta] += NUM_INC; + if (d==0) { + celldat[loc+steps*delta] &= NUM_MASK; + celldat[loc+steps*delta] |= STONE_AT(loc); + celldat[loc] &= NUM_MASK; + celldat[loc] |= STONE_FLAT; // this should be optimised out :) + } + // decrement the count, the top colour + celldat[loc] -= NUM_INC; + + if (gaps & mask) steps--; + mask >>= 1; } - mask <<= 1; - } - // Push stones onto subesquent stack - uint8_t j = num; - for (uint8_t k = 0; k <= steps; k++) { - j -= drops[k]; - push_stones(loc+(k+1)*deltas[dir], - drops[k], - (colours[loc] >> j) & (0xFFFF >> (0x10 - drops[k])), - (k == steps - 1) ? STONE_AT(loc) : STONE_FLAT); + } else { + // Oh well + colours[loc+delta] <<= 1; + colours[loc+delta] |= colours[loc] & 1; + celldat[loc+delta] += NUM_INC; + celldat[loc+delta] &= NUM_MASK; + celldat[loc+delta] |= STONE_AT(loc); + + colours[loc] >>= 1; + celldat[loc] &= NUM_MASK; + celldat[loc] |= STONE_FLAT; // this should be optimised out :) + celldat[loc] -= NUM_INC; } - // Drop them from the source - colours[loc] >>= num; - const uint8_t dec_count = celldat[loc] - (num << NUM_SHIFT); - celldat[loc] = dec_count & NUM_MASK; } // Always - next_ply(); -}; + inline_next_ply(); +} void action_undo(action_list_t *action) { const uint8_t loc = action->loc; @@ -219,10 +226,74 @@ void action_undo(action_list_t *action) { else white_count++; } } else { - // TODO ??? + // See action_take for comments, this is the time reversal + const uint8_t gaps = action->data0, + num = action->data1 & 0x0F, // unpack + dir = action->data1 & 0xF0, + delta = deltas[dir]; + + uint8_t steps = 1, mask = 1; + if (num > 1) { + for (uint8_t d = 0; d + 1 < num; d++) { + colours[loc] <<= 1; + colours[loc] |= colours[loc+steps*delta] & 1; + colours[loc+steps*delta] >>= 1; + + celldat[loc] += NUM_INC; + if (d + 2 == num) { + celldat[loc] &= NUM_MASK; + celldat[loc] |= STONE_AT(loc+steps*delta); + celldat[loc+steps*delta] &= NUM_MASK; + celldat[loc+steps*delta] |= STONE_FLAT; + } + celldat[loc+steps*delta] -= NUM_INC; + + if (gaps & mask) steps++; + mask <<= 1; + } + } else { + colours[loc] <<= 1; + colours[loc] |= colours[loc+delta] & 1; + celldat[loc] += NUM_INC; + celldat[loc] &= NUM_MASK; + celldat[loc] |= STONE_AT(loc+delta); + + colours[loc+delta] >>= 1; + celldat[loc+delta] &= NUM_MASK; + celldat[loc+delta] |= STONE_FLAT; + celldat[loc+delta] -= NUM_INC; + } } - previous_ply(); -}; + inline_previous_ply(); +} + +void action_to_ptn(action_list_t* action, char* out_ptn) { + const uint8_t loc = action->loc; + if (action->type == A_PLACE) { + generate_place(loc, action->data0, out_ptn); + } else { + const uint8_t gaps = action->data0, + num = action->data1 & 0x0F, // unpack + dir = action->data1 & 0xF0; + + uint8_t drops[board_size]; // we only ever need board_size-1 in + // drops actually, the last spot is to + // skip a bounds check at (*) + uint8_t mask = 1, steps = 0; + // Translate to a drop sequence + drops[0] = 1; mask = 1; + for (uint8_t d = 0; d + 1 < num; d++) { + if (gaps & mask) { + steps++; + drops[steps] = 1; // (*) no bounds check + } else { + drops[steps] += 1; + } + mask <<= 1; + } + generate_move(loc, dir, steps+1, drops, out_ptn); + } +} // =================================================================== // Helper method implementations @@ -235,6 +306,7 @@ action_list_prepend(action_list_t *list, const enum A_TYPE type, action_list_t *new = malloc(sizeof(action_list_t)); // TODO: trap errno new->loc = loc; + new->type = type; new->next = list; new->data0 = data0; new->data1 = data1; @@ -242,9 +314,9 @@ action_list_prepend(action_list_t *list, const enum A_TYPE type, } static inline void -previous_ply(void) { - if (ply>0) ply--; - if (ply == 1) { +inline_next_ply(void) { + ply++; + if (ply == 2) { current_colour = C_WHITE; } else { if (current_colour == C_BLACK) current_colour = C_WHITE; @@ -253,10 +325,12 @@ previous_ply(void) { } static inline void -push_stones(const int8_t location, const uint8_t count, - const uint8_t new_colours, - const enum STONE_VARIANT top_stone) { - colours[location] = (colours[location] << count) | new_colours; - celldat[location] = top_stone - | ((celldat[location] + ((count << NUM_SHIFT))) & NUM_MASK); +inline_previous_ply(void) { + if (ply>0) ply--; + if (ply == 1) { + current_colour = C_WHITE; + } else { + if (current_colour == C_BLACK) current_colour = C_WHITE; + else current_colour = C_BLACK; + } } |
