aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortslil clingman <tslil@posteo.de>2021-01-26 17:42:53 -0500
committertslil <tslil@posteo.de>2026-08-28 19:37:41 +0100
commitde4f20f28afe23ecfc546ad242e5bb44710996cc (patch)
tree32cd0cf0757327cee4ee4d4631920284d54816f3
parentd45db690ce92cb2c847175cfd9ac497f3dd40cea (diff)
Storing best moves!
-rw-r--r--include/actions.c (renamed from include/action_list.c)139
-rw-r--r--include/actions.h (renamed from include/action_list.h)21
-rw-r--r--include/negamax.c21
-rw-r--r--include/negamax.h2
-rw-r--r--include/tt_treap.c20
-rw-r--r--include/tt_treap.h15
6 files changed, 115 insertions, 103 deletions
diff --git a/include/action_list.c b/include/actions.c
index 30ca918..9b3534b 100644
--- a/include/action_list.c
+++ b/include/actions.c
@@ -1,4 +1,4 @@
-#include "action_list.h"
+#include "actions.h"
// ===================================================================
// Helper method declarations
@@ -8,45 +8,50 @@
#define CLR_STONE NUM_MASK
+#define TYPE_SHIFT 24
+#define LOC_SHIFT 16
+#define DATA0_SHIFT 8
+
+#define GET_TYPE(a) (enum A_TYPE)((a)>>TYPE_SHIFT)
+#define GET_LOC(a) (int8_t)(((a)>>LOC_SHIFT) & 0xFF)
+#define GET_DATA0(a) (uint8_t)(((a)>>DATA0_SHIFT) & 0xFF)
+#define GET_DATA1(a) (uint8_t)((a) & 0xFF)
+
static inline void
-action_list_append(action_list_t *list, const enum A_TYPE type,
- const int8_t loc, const uint8_t data0,
- const uint8_t data1);
+list_append(action_list_t *list, const enum A_TYPE type,
+ const int8_t loc, const uint8_t data0,
+ const uint8_t data1);
+
static inline void
inline_next_ply(void);
static inline void
inline_prev_ply(void);
-
// ===================================================================
// Exported method implementations
// ===================================================================
-/*
- * void action_list_ensure_at_front(const action_node_t *action,
- * const action_list_t *list) {
- * action_node_t *copy = action_copy(action), *n = list->head, *nn;
- * // ensure it's not there already
- * while (n) {
- * nn = n->next;
- * }
- *
- * copy->next = list->head;
- * }
- */
-
-action_node_t *action_copy(const action_node_t *action) {
- action_node_t *copy = malloc(sizeof(struct action_node_s));
- // TODO: trap
- copy->data0 = action->data0;
- copy->data1 = action->data1;
- copy->loc = action->loc;
- copy->type = action->type;
- copy->next = NULL;
- return copy;
+int action_move_to_front(const action_t action,
+ action_list_t *list) {
+ action_node_t *n = list->head;
+
+ // TODO: what if it's not in the list?
+
+ while (n) {
+ if (n->action == action) {
+ const action_t t = list->head->action;
+ list->head->action = action;
+ n->action = t;
+ return EXIT_SUCCESS;
+ }
+ n = n->next;
+ }
+
+ return EXIT_FAILURE;
}
+
void action_list_free(action_list_t *list) {
if (list) {
action_node_t *n = list->head, *nn;
@@ -156,9 +161,9 @@ action_list_t *action_list_generate(void) {
(steps == end_stops[dir]) && crushes[dir];
// Store the move
- action_list_append(list, A_MOVE, loc,
- (crush << 7) | gaps,
- (dir<<4) | num);
+ list_append(list, A_MOVE, loc,
+ (crush << 7) | gaps,
+ (dir<<4) | num);
}
/*
* With thanks to
@@ -178,23 +183,23 @@ action_list_t *action_list_generate(void) {
else if (material) {
// Empty square, generate placements
if (flat) {
- action_list_append(list, A_PLACE, loc, STONE_FLAT, 0);
+ list_append(list, A_PLACE, loc, STONE_FLAT, 0);
if (standing)
- action_list_append(list, A_PLACE, loc, STONE_STANDING,0);
+ list_append(list, A_PLACE, loc, STONE_STANDING,0);
}
if (cap)
- action_list_append(list, A_PLACE, loc, STONE_CAPSTONE, 0);
+ list_append(list, A_PLACE, loc, STONE_CAPSTONE, 0);
}
}
}
return list;
}
-void action_take(action_node_t *action) {
- const int8_t loc = action->loc;
- if (action->type == A_PLACE) {
+void action_take(const action_t action) {
+ const int8_t loc = GET_LOC(action);
+ if (GET_TYPE(action) == A_PLACE) {
const uint8_t black = (current_colour == C_BLACK);
- switch (action->data0) {
+ switch (GET_DATA0(action)) {
case STONE_FLAT: {
if (black) black_count--;
else white_count--;
@@ -218,16 +223,12 @@ void action_take(action_node_t *action) {
}
}
} else {
- 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;
+ // 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.
+ const uint8_t gaps = GET_DATA0(action) & 0x7F,
+ num = GET_DATA1(action) & 0x0F, // unpack
+ dir = GET_DATA1(action) >> 4;
int8_t delta = deltas[dir];
// Use the Kernighan method to count the set bits
@@ -270,15 +271,15 @@ void action_take(action_node_t *action) {
inline_next_ply();
}
-void action_undo(action_node_t *action) {
+void action_undo(const action_t action) {
// Previous ply
inline_prev_ply();
- const int8_t loc = action->loc;
- if (action->type == A_PLACE) {
+ const int8_t loc = GET_LOC(action);
+ if (GET_TYPE(action) == A_PLACE) {
const uint8_t black = (current_colour == C_BLACK);
celldat[loc] = 0;
- if (action->data0 == STONE_CAPSTONE) {
+ if (GET_DATA0(action) == STONE_CAPSTONE) {
if (black) black_count |= 0x80;
else white_count |= 0x80;
} else {
@@ -288,10 +289,10 @@ void action_undo(action_node_t *action) {
} else {
// See action_take for comments, this is the time reversal, but
// there is one caveat -- undoing a crush! (*)
- const uint8_t gaps = action->data0 & 0x7F,
- crush = action->data0 & 0x80,
- num = action->data1 & 0x0F,
- dir = action->data1 >> 4;
+ 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 = deltas[dir];
int8_t steps = 1;
@@ -324,14 +325,14 @@ void action_undo(action_node_t *action) {
}
}
-void action_to_ptn(action_node_t* action, char* out_ptn) {
- const int8_t loc = action->loc;
- if (action->type == A_PLACE) {
- generate_place(loc, action->data0, out_ptn);
+void action_to_ptn(const action_t action, char* out_ptn) {
+ const int8_t loc = GET_LOC(action);
+ if (GET_TYPE(action) == A_PLACE) {
+ generate_place(loc, GET_DATA0(action), out_ptn);
} else {
- const uint8_t gaps = action->data0 & 0x7F,
- num = action->data1 & 0x0F, // unpack
- dir = action->data1 >> 4;
+ const uint8_t gaps = GET_DATA0(action) & 0x7F,
+ num = GET_DATA1(action) & 0x0F, // unpack
+ dir = GET_DATA1(action) >> 4;
uint8_t drops[board_size]; // we only ever need board_size-1 in
// drops actually, the last spot is to
@@ -357,17 +358,17 @@ void action_to_ptn(action_node_t* action, char* out_ptn) {
// ===================================================================
static inline void
-action_list_append(action_list_t *list, const enum A_TYPE type,
- const int8_t loc, const uint8_t data0,
- const uint8_t data1) {
+list_append(action_list_t *list, const enum A_TYPE type,
+ const int8_t loc, const uint8_t data0,
+ const uint8_t data1) {
action_node_t *new = malloc(sizeof(action_list_t));
// TODO: trap errno
- new->loc = loc;
- new->type = type;
- new->data0 = data0;
- new->data1 = data1;
new->next = NULL;
+ new->action = (type << TYPE_SHIFT)
+ | (loc << LOC_SHIFT)
+ | (data0 << DATA0_SHIFT)
+ | data1;
if (list->length) {
list->tail->next = new;
diff --git a/include/action_list.h b/include/actions.h
index b6fd13a..661f11e 100644
--- a/include/action_list.h
+++ b/include/actions.h
@@ -1,19 +1,18 @@
+#ifndef ACTIONS_H
+#define ACTIONS_H
+
#include <stdlib.h>
#include <stdint.h>
#include <tak.h>
-#ifndef ACTION_LIST_H
-#define ACTION_LIST_H
-
enum A_TYPE { A_PLACE, A_MOVE };
+typedef uint32_t action_t;
+
typedef struct action_node_s {
struct action_node_s *next;
- enum A_TYPE type;
- int8_t loc;
- uint8_t data0;
- uint8_t data1;
+ action_t action;
} action_node_t;
typedef struct action_list_s {
@@ -24,11 +23,11 @@ typedef struct action_list_s {
void action_list_init(void);
void action_list_free(action_list_t *list);
action_list_t *action_list_generate(void);
-action_node_t *action_copy(const action_node_t* action);
+int action_move_to_front(const action_t action, action_list_t *list);
-void action_take(action_node_t *action);
-void action_undo(action_node_t *action);
+void action_take(const action_t action);
+void action_undo(const action_t action);
-void action_to_ptn(action_node_t* action, char* out_ptn);
+void action_to_ptn(const action_t action, char* out_ptn);
#endif
diff --git a/include/negamax.c b/include/negamax.c
index f6a7525..7f05040 100644
--- a/include/negamax.c
+++ b/include/negamax.c
@@ -131,6 +131,7 @@ negamax(const uint8_t cur_depth, float alpha, float beta,
uint64_t hash = zobrist_compute();
tt_entry_t *entry = tt_seek(hash);
+ // CAUTION: >= breaks search stability
if (entry != NULL && entry->depth == cur_depth) {
if (entry->flag == TT_EXACT) {
return entry->value;
@@ -146,15 +147,16 @@ negamax(const uint8_t cur_depth, float alpha, float beta,
if ((list = action_list_generate()) == NULL)
return alpha; // should never happen!
+ if (entry != NULL) {
+ action_move_to_front(entry->action, list);
+ }
- /*
- * action_node_t *best = NULL;
- */
-
+ action_t best_action;
float value = -infty;
+
for (action_node_t *node=list->head; node!=NULL; node=node->next) {
- action_take(node);
+ action_take(node->action);
// Compute the value of the node
float node_value;
if (ply >= 2*board_size - 2 && (w = check_win()) < 0xFF) {
@@ -168,14 +170,15 @@ negamax(const uint8_t cur_depth, float alpha, float beta,
} else {
node_value = colour * cnn1986_evaluate_black_win();
}
- action_undo(node);
+ action_undo(node->action);
negamax_display_progress(cur_depth, list->length);
if (node_value > value) {
value = node_value;
+ best_action = node->action;
if (cur_depth == negamax_search_depth)
- action_to_ptn(node, negamax_ptn);
+ action_to_ptn(node->action, negamax_ptn);
}
alpha = fmax(value, alpha);
@@ -189,12 +192,12 @@ negamax(const uint8_t cur_depth, float alpha, float beta,
else if (value <= alpha) flag = TT_UPPERBOUND;
if (entry == NULL) {
- tt_insert(hash, flag, cur_depth, value);
+ tt_insert(hash, flag, cur_depth, value, best_action);
} else {
entry->flag = flag;
entry->value = value;
entry->depth = cur_depth;
- // entry->action = best;
+ entry->action = best_action;
}
return value;
diff --git a/include/negamax.h b/include/negamax.h
index c902d3c..43995d1 100644
--- a/include/negamax.h
+++ b/include/negamax.h
@@ -2,7 +2,7 @@
#include <math.h>
#include <tak.h>
-#include <action_list.h>
+#include <actions.h>
#include <xorshift64.h>
#include <cnn1986.h>
#include <tt_treap.h>
diff --git a/include/tt_treap.c b/include/tt_treap.c
index b48ffd4..369d767 100644
--- a/include/tt_treap.c
+++ b/include/tt_treap.c
@@ -12,10 +12,14 @@ static tt_entry_t * root;
// ===================================================================
void recurse_tree(tt_entry_t *n);
-tt_entry_t *new_treap_node(const uint64_t key, const enum TT_FLAG flag,
- const uint8_t depth, const float value);
void bubble_up(tt_entry_t *n);
+tt_entry_t *
+new_treap_node(const uint64_t key, const enum TT_FLAG flag,
+ const uint8_t depth, const float value,
+ const action_t action);
+
+
// ===================================================================
// Exported functions
// ===================================================================
@@ -43,8 +47,9 @@ tt_entry_t *tt_seek(const uint64_t key) {
}
int tt_insert(const uint64_t key, const enum TT_FLAG flag,
- const uint8_t depth, const float value) {
- tt_entry_t *m = new_treap_node(key, flag, depth, value);
+ const uint8_t depth, const float value,
+ const action_t action) {
+ tt_entry_t *m = new_treap_node(key, flag, depth, value, action);
if (root == NULL) {
root = m;
tt_num_cached = 1;
@@ -78,8 +83,10 @@ void recurse_tree(tt_entry_t *n) {
free(n);
}
-tt_entry_t *new_treap_node(const uint64_t key, const enum TT_FLAG flag,
- const uint8_t depth, const float value) {
+tt_entry_t *
+new_treap_node(const uint64_t key, const enum TT_FLAG flag,
+ const uint8_t depth, const float value,
+ const action_t action) {
tt_entry_t *n = malloc(sizeof(struct treap_node_s));
// TODO: trap
n->key = key;
@@ -89,6 +96,7 @@ tt_entry_t *new_treap_node(const uint64_t key, const enum TT_FLAG flag,
n->left = NULL;
n->right = NULL;
n->parent = NULL;
+ n->action = action;
XORSHIFT64; n->weight = RANDOM32;
return n;
}
diff --git a/include/tt_treap.h b/include/tt_treap.h
index 1a15e1b..3991e79 100644
--- a/include/tt_treap.h
+++ b/include/tt_treap.h
@@ -1,10 +1,11 @@
+#ifndef TT_TREAP_H
+#define TT_TREAP_H
+
#include <stdlib.h>
#include <stdint.h>
-#include <action_list.h>
-#include <xorshift64.h>
-#ifndef TT_TREAP_H
-#define TT_TREAP_H
+#include <actions.h>
+#include <xorshift64.h>
// ===================================================================
// Types
@@ -19,7 +20,7 @@ typedef struct treap_node_s {
enum TT_FLAG flag;
uint8_t depth;
float value;
- action_node_t *action;
+ action_t action;
} tt_entry_t;
// ===================================================================
@@ -38,7 +39,7 @@ void tt_free(void);
tt_entry_t *tt_seek(uint64_t key);
int tt_insert(const uint64_t key, const enum TT_FLAG flag,
- const uint8_t depth, const float value);
- // const action_node_t* action);
+ const uint8_t depth, const float value,
+ const action_t action);
#endif