aboutsummaryrefslogtreecommitdiff
path: root/include/action_list.c
diff options
context:
space:
mode:
authortslil clingman <tslil@posteo.de>2021-01-24 21:31:59 -0500
committertslil <tslil@posteo.de>2026-08-28 19:37:41 +0100
commitcb143299411851667a8e3aae4d7a55f729694b12 (patch)
tree3add82c4e7a893d0a7068b59d91033c861d05e2e /include/action_list.c
parentcf921b2e647136dc34568e0fff78b67c14c8e2fa (diff)
This is the basic idea, there's ≥ 1 bug (generates illegals...)
Diffstat (limited to 'include/action_list.c')
-rw-r--r--include/action_list.c176
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;
+ }
}