aboutsummaryrefslogtreecommitdiff
path: root/include/action_list.c
diff options
context:
space:
mode:
authortslil clingman <tslil@posteo.de>2021-01-25 22:23:38 -0500
committertslil <tslil@posteo.de>2026-08-28 19:37:41 +0100
commitc69c764a2202d745a3672a92bcb40ea180bd9740 (patch)
treeab159882d749d352af9c3f3b64513aad8a0e6a37 /include/action_list.c
parent8418ddf3187ec0f526ef5d8dbb0689fc786fac92 (diff)
Still bugs...
Diffstat (limited to 'include/action_list.c')
-rw-r--r--include/action_list.c100
1 files changed, 60 insertions, 40 deletions
diff --git a/include/action_list.c b/include/action_list.c
index b338627..b11bae7 100644
--- a/include/action_list.c
+++ b/include/action_list.c
@@ -4,6 +4,8 @@
// Helper method declarations
// ===================================================================
+#define DANGER_MIN(a,b) (((a)<(b))?(a):(b))
+
#define CLR_STONE NUM_MASK
static inline void
@@ -45,9 +47,9 @@ action_list_t *action_list_generate(void) {
const uint8_t black = (ply < 2) ? (ply==1) : (ply & 1),
material = (black) ? black_count : white_count,
- flat = material & 127,
- cap = (ply >= 2 && (material & 128)),
- standing = (ply >= 2 && (material & 127));
+ flat = material & 0x7F,
+ cap = (ply >= 2 && (material & 0x80)),
+ standing = (ply >= 2 && flat);
// Step across the board, reversed because we prepend to the list
for (int8_t row = board_size - 1; row >= 0; row--) {
@@ -55,39 +57,38 @@ action_list_t *action_list_generate(void) {
// We'll need these at various points: the location of this
// square and the maximum number of stones we could pick up
const int8_t loc = THE_COORDS(col, row);
- const uint8_t count = (COUNT_AT(loc) > board_size) ? board_size : COUNT_AT(loc);
+ const uint8_t count = DANGER_MIN(COUNT_AT(loc), board_size);
// Only try moves after CPS
if (ply >= 2 && count && ((colours[loc] & 1) == current_colour)) {
// There are stones, let's try moving them
- // Pre-compute end-stops
- uint8_t end_stops[4][2]; // (end, not_crush)
+ // Pre-compute end-stops and crushes
+ uint8_t end_stops[4], crushes[4] = {0, 0, 0, 0};
// These are upper bounds, not counting walls and such. UP DOWN LEFT RIGHT
- end_stops[0][0] = (board_size - row - 1 > count) ? count : board_size - row - 1;
- end_stops[1][0] = (row > count) ? count : row;
- end_stops[2][0] = (col > count) ? count : col;
- end_stops[3][0] = (board_size - col - 1 > count) ? count : board_size - col - 1;
+ end_stops[0] = DANGER_MIN(board_size - row - 1, count);
+ end_stops[1] = DANGER_MIN(row, count);
+ end_stops[2] = DANGER_MIN(col, count);
+ end_stops[3] = DANGER_MIN(board_size - col - 1, count);
// Now we check for caps and walls
const uint8_t cap_top = STONE_AT(loc) == STONE_CAPSTONE;
for (uint8_t d = 0; d < 4; d++){
const int8_t delta = deltas[d];
- end_stops[d][1] = 1;
- const uint8_t stop = end_stops[d][0];
- end_stops[d][0] = 0;
+ const uint8_t stop = end_stops[d];
+ end_stops[d] = 0;
for (uint8_t k = 1; k <= stop; k++) {
- const uint8_t stone = STONE_AT(loc+k*delta);
+ const enum STONE_VARIANT stone = STONE_AT(loc+k*delta);
if (stone == STONE_STANDING) {
if (cap_top) {
- end_stops[d][1] = 0;
- end_stops[d][0]++;
+ crushes[d] = 0xFF;
+ end_stops[d]++;
}
break;
} else if (stone == STONE_CAPSTONE) {
break;
}
- end_stops[d][0]++;
+ end_stops[d]++;
}
}
/*
@@ -99,7 +100,7 @@ action_list_t *action_list_generate(void) {
for (enum MOVE_DIRECTION dir = M_UP; dir <= M_RIGHT; dir++) {
for (uint8_t num = 1; num <= count; num++) {
for (uint8_t steps = 1;
- steps <= end_stops[dir][0] && steps <= num;
+ steps <= end_stops[dir] && steps <= num;
steps++) {
// TODO: Generalise to board_size!
uint8_t gaps = 0x07 >> (board_size-steps-1);
@@ -111,8 +112,14 @@ action_list_t *action_list_generate(void) {
*/
const uint8_t last_drop_check =
(num > 1) ? (gaps & 1<<(num - 2)) : 1;
- if (end_stops[dir][1] || last_drop_check)
- action_list_prepend(result, A_MOVE, loc, gaps, (dir<<4) | num);
+ if (crushes[dir] == 0 || last_drop_check) {
+ // We have to record a crush!
+ // THIS IS WHERE THE PROBLEM IS
+ const uint8_t crush = (steps == end_stops[dir]) && crushes[dir];
+ action_list_prepend(result, A_MOVE, loc,
+ (crush << 7) | gaps,
+ (dir<<4) | num);
+ }
/*
* With thanks to
* https://graphics.stanford.edu/~seander/bithacks.html#NextBitPermutation
@@ -163,15 +170,22 @@ void action_take(action_node_t *action) {
break;
}
default: {
- if (black) black_count &= 127;
- else white_count &= 127;
+ if (black) black_count &= 0x7F;
+ else white_count &= 0x7F;
colours[loc] = current_colour;
celldat[loc] = NUM_INC | STONE_CAPSTONE;
break;
}
}
} else {
- const uint8_t gaps = action->data0,
+ const uint8_t gaps = action->data0 & 0x7F, // not interested in
+ // whether we crushed,
+ // it will work out by
+ // anyway because we
+ // overwrite the top
+ // stone type. See (*)
+ // later for when we do
+ // need to know.
num = action->data1 & 0x0F, // unpack
dir = action->data1 >> 4;
int8_t delta = deltas[dir];
@@ -186,11 +200,11 @@ void action_take(action_node_t *action) {
celldat[loc] &= CLR_STONE;
celldat[loc] |= STONE_FLAT; // should be optimised out
- uint8_t gap_bit = 0, total = 1;
- // num == 1 is a special case
- if (num > 1) {
- gap_bit = 1 << (num - 2);
- }
+ uint8_t total = 1, gap_bit = 1 << (num - 2); // it's not important
+ // what negative
+ // shifts do here, we
+ // don't use gap_bit
+ // if num < 2
// move stuff starting at destination
for (uint8_t d = 1; d < num; d++, total++, gap_bit >>= 1) {
// We took a step, move everything over so far
@@ -237,22 +251,24 @@ void action_undo(action_node_t *action) {
const uint8_t black = (current_colour == C_BLACK);
celldat[loc] = 0;
if (action->data0 == STONE_CAPSTONE) {
- if (black) black_count |= 128;
- else white_count |= 128;
+ if (black) black_count |= 0x80;
+ else white_count |= 0x80;
} else {
if (black) black_count++;
else white_count++;
}
} else {
- // See action_take for comments, this is the time reversal
- const uint8_t gaps = action->data0,
+ // See action_take for comments, this is the time reversal, but
+ // there is one caveat -- undoing a crush! (*)
+ const uint8_t gaps = action->data0 & 0x75,
+ crush = action->data0 & 0x80,
num = action->data1 & 0x0F,
dir = action->data1 >> 4;
const int8_t delta = deltas[dir];
int8_t steps = 1;
uint8_t gap_bit = 1, total = 1;
- for (uint8_t d = 1; d < num; d++, total++, gap_bit <<= 1) {
+ for (int8_t d = 1; d < num; d++, total++, gap_bit <<= 1) {
if (gaps & gap_bit) {
colours[loc] <<= total;
colours[loc] |= colours[loc+steps*delta] & ((1 << total) - 1);
@@ -266,13 +282,17 @@ void action_undo(action_node_t *action) {
colours[loc] <<= total;
colours[loc] |= colours[loc+steps*delta] & ((1 << total) - 1);
colours[loc+steps*delta] >>= total;
- // celldat[loc] &= CLR_STONE; is not necessary, as STONE_FLAT == 0
+
celldat[loc] += total*NUM_INC;
- celldat[loc+steps*delta] -= total*NUM_INC;
- // Top stone type
+ // celldat[loc] &= CLR_STONE; is not necessary, as STONE_FLAT == 0
celldat[loc] |= STONE_AT(loc+steps*delta);
+ celldat[loc+steps*delta] -= total*NUM_INC;
celldat[loc+steps*delta] &= CLR_STONE;
- celldat[loc+steps*delta] |= STONE_FLAT; // should be optimised out
+ if (crush) {
+ celldat[loc+steps*delta] |= STONE_STANDING;
+ } else {
+ celldat[loc+steps*delta] |= STONE_FLAT; // should be optimised out
+ }
}
}
@@ -281,20 +301,20 @@ void action_to_ptn(action_node_t* action, char* out_ptn) {
if (action->type == A_PLACE) {
generate_place(loc, action->data0, out_ptn);
} else {
- const uint8_t gaps = action->data0,
+ const uint8_t gaps = action->data0 & 0x7F,
num = action->data1 & 0x0F, // unpack
dir = action->data1 >> 4;
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 (*)
+ // 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 = 1; d < num; d++) {
if (gaps & mask) {
steps++;
- drops[steps] = 1; // (*) no bounds check
+ drops[steps] = 1; // (**) no bounds check
} else {
drops[steps] += 1;
}