git.haldean.org grandmaster / 68cc1c5
use arrays for access map haldean 6 months ago
14 changed file(s) with 98 addition(s) and 155 deletion(s). Raw diff Collapse all Expand all
3131 game_id_t g1;
3232
3333 gt = calloc(1, sizeof(struct game_tree));
34 init_gametree(gt);
34 init_game_tree(gt);
3535
3636 g1 = new_game(gt, 1, 2);
3737
4848 game_id_t g1, g2;
4949
5050 gt = calloc(1, sizeof(struct game_tree));
51 init_gametree(gt);
51 init_game_tree(gt);
5252
5353 g1 = new_game(gt, 12, 56);
5454 g2 = new_game(gt, 34, 56);
6969 game_id_t g1, g2, g3;
7070
7171 gt = calloc(1, sizeof(struct game_tree));
72 init_gametree(gt);
72 init_game_tree(gt);
7373
7474 g1 = new_game(gt, 12, 56);
7575 g2 = new_game(gt, 34, 56);
346346 return 1;
347347 }
348348
349 init_gametree(&gt);
349 init_game_tree(&gt);
350350 res = load_aol(&gt, aol);
351351 if (res != 0)
352352 return res;
353353 run_gm(&gt, aol, use_stdin);
354 free_game_tree(&gt);
354355 return 0;
355356 }
8787 color_t color;
8888 };
8989
90 #define NO_POS 0xFF
91
9092 struct position
9193 {
92 int8_t rank;
93 int8_t file;
94 uint8_t rank;
95 uint8_t file;
9496 };
9597
9698 struct move
104106 struct board *post_board;
105107 };
106108
107 struct access_map
108 {
109 struct
110 {
111 int n_accessors;
112 struct position *accessors;
113 } board[8][8];
114 };
109 #define MAX_ACCESSORS 16
115110
116111 struct board
117112 {
118113 struct piece board[8][8];
119 struct access_map *access_map;
114 struct position access[8][8][16];
120115 uint8_t available_castles;
121116 int8_t passant_file;
122117 /* ply index is the number of plys that have been played, inclusive. */
168163 bool in_stalemate(struct move *move, color_t player);
169164
170165 /* Finds all pieces of the given color and type that has access to move->end,
171 * respecting any preexisting values in move->start. Returns a list of
172 * positions where accessible pieces are located. */
166 * respecting any preexisting values in move->start. Fills out a list in the
167 * results array, which much be large enough to fit at least MAX_ACCESSORS
168 * position elements. */
173169 void find_all_with_access(
174 struct piece piece, struct move *move, int *n_results,
175 struct position **results);
170 struct piece piece, struct move *move, struct position *results);
176171
177172 /* Finds a piece of the given color and type that has access to move->end,
178173 * respecting any preexisting values in move->start. Populates the value at
5555 /* Asserts that the given color is either white or black. */
5656 void assert_valid_color(color_t color);
5757
58 /* Builds an access map from a move. */
59 void build_access_map(struct move *move, struct access_map *out);
60
61 /* Frees an access map. */
62 void free_access_map(struct access_map *map);
58 /* Builds an access map from a move, attaching it to the move's post_board */
59 void build_access_map(struct move *move);
6360
6461 /* Loads the opening position into a board object. */
6562 void load_default_board(struct board *b);
5454 struct game **games;
5555 };
5656
57 void init_gametree(struct game_tree *gt);
57 void init_game_tree(struct game_tree *gt);
58
59 void free_game_tree(struct game_tree *gt);
5860
5961 game_id_t new_game(struct game_tree *gt, player_id_t white, player_id_t black);
6062
7072 struct game_tree *gt, player_id_t white, player_id_t black,
7173 const char *pgn);
7274
73 void free_game_tree(struct game_tree *gt);
74
7575 json_t *game_tree_to_json(struct game_tree *gt);
7676
7777 void game_tree_from_json(json_t *doc, struct game_tree *gt);
2424 #include <string.h>
2525
2626 #define sign(x) (((x) > 0) - ((x) < 0))
27 #define MAX_PIECE_COUNT 16
2728
2829 void
2930 find_all_with_access(
30 struct piece piece, struct move *move, int *n_results,
31 struct position **results)
31 struct piece piece, struct move *move, struct position *access)
3232 {
3333 int8_t rank;
3434 int8_t file;
3535 struct move test_move;
3636 struct piece *board_piece;
37 struct position *res;
38 const int max_res = 16;
39 const int max_res_arraylen = max_res * sizeof(struct position);
37 int n = 0;
4038
41 *n_results = 0;
42 /* instead of repeatedly growing the result array, alloc an array large
43 * enough to store the maximum number of responses and then realloc at
44 * the end of the function down to the appropriate size. Even at max
45 * length, this is only 32 bytes of data. */
46 res = malloc(max_res_arraylen);
47 if (res == NULL)
48 {
49 return;
50 }
51 memset(res, 0xFF, max_res_arraylen);
39 memset(access, NO_POS, MAX_ACCESSORS * sizeof(struct position));
5240
5341 memset(&test_move, 0x00, sizeof(struct move));
5442 test_move.parent = move->parent;
5947 /* we could do this more efficiently by skipping the loop
6048 * altogether in this case, but I like the succinctness of
6149 * doing this all in one loop with no special cases. */
62 if (move->start.rank != -1 && move->start.rank != rank)
50 if (move->start.rank != NO_POS && move->start.rank != rank)
6351 continue;
6452 for (file = 0; file < 8; file++)
6553 {
66 if (move->start.file != -1 && move->start.file != file)
54 if (move->start.file != NO_POS
55 && move->start.file != file)
6756 continue;
6857 board_piece =
6958 &move->parent->post_board->board[rank][file];
8069 test_move.player = board_piece->color;
8170 apply_movement(&test_move);
8271 if (is_movement_valid(&test_move)
83 && *n_results < max_res)
84 {
85 res[*n_results] = test_move.start;
86 (*n_results)++;
87 }
72 && n < MAX_PIECE_COUNT)
73 access[n++] = test_move.start;
8874 free(test_move.post_board);
8975 test_move.post_board = NULL;
9076 }
91 }
92
93 *results = realloc(res, *n_results * sizeof(struct position));
94 if (*results == NULL && *n_results)
95 {
96 *n_results = 0;
97 free(res);
98 return;
9977 }
10078 }
10179
11694 /* we could do this more efficiently by skipping the loop
11795 * altogether in this case, but I like the succinctness of
11896 * doing this all in one loop with no special cases. */
119 if (move->start.rank != -1 && move->start.rank != rank)
97 if (move->start.rank != NO_POS && move->start.rank != rank)
12098 continue;
12199 for (file = 0; file < 8; file++)
122100 {
123 if (move->start.file != -1 && move->start.file != file)
101 if (move->start.file != NO_POS
102 && move->start.file != file)
124103 continue;
125104 board_piece =
126105 &move->parent->post_board->board[rank][file];
155134 struct piece constraint;
156135
157136 test_move.parent = move;
158 test_move.start.rank = -1;
159 test_move.start.file = -1;
137 test_move.start.rank = NO_POS;
138 test_move.start.file = NO_POS;
160139 test_move.end.rank = position.rank;
161140 test_move.end.file = position.file;
162141
165144
166145 find_piece_with_access(constraint, &test_move);
167146
168 return test_move.start.rank != -1;
147 return test_move.start.rank != NO_POS;
169148 }
170149
171150 bool
194173 d_file = file_step;
195174
196175 test_move.parent = move;
197 test_move.start.rank = -1;
198 test_move.start.file = -1;
176 test_move.start.rank = NO_POS;
177 test_move.start.file = NO_POS;
199178 constraint.color = to_move;
200179 constraint.piece_type = 0;
201180
206185 test_move.end.file = mover.file + d_file;
207186
208187 find_piece_with_access(constraint, &test_move);
209 if (test_move.start.rank != -1)
210 {
188 if (test_move.start.rank != NO_POS)
211189 return true;
212 }
213190
214191 d_rank += rank_step;
215192 d_file += file_step;
4444 bool
4545 is_valid_position(const struct position pos)
4646 {
47 return 0 <= pos.rank && pos.rank < 8 && 0 <= pos.file && pos.file < 8;
47 return pos.rank < 8 && pos.file < 8;
4848 }
4949
5050 bool
112112 out->post_board = calloc(1, sizeof(struct board));
113113 memcpy(out->post_board, last_move->post_board, sizeof(struct board));
114114
115 out->post_board->access_map = NULL;
115 memset(
116 out->post_board->access, NO_POS, sizeof out->post_board->access);
116117
117118 /* update available castles */
118119 out->post_board->available_castles =
342343 {
343344 notation[i] = '\0';
344345 }
345 result->end.rank = -1;
346 result->end.file = -1;
346 result->end.rank = NO_POS;
347 result->end.file = NO_POS;
347348 read_location(&notation[strlen(notation) - 2], &result->end);
348 if (result->end.rank == -1 || result->end.file == -1)
349 if (result->end.rank == NO_POS || result->end.file == NO_POS)
349350 {
350351 alg_fail("end location didn't parse");
351352 }
370371
371372 /* put in sentinel values so we can tell what was initialized (if
372373 * anything) during disambiguation loading. */
373 result->start.rank = -1;
374 result->start.file = -1;
374 result->start.rank = NO_POS;
375 result->start.file = NO_POS;
375376 if (disambig_len == 2)
376377 {
377378 /* easiest case: we have two disambig characters that give us
396397 }
397398
398399 find_piece_with_access(piece, result);
399 if (result->start.rank == -1 || result->end.rank == -1)
400 if (result->start.rank == NO_POS || result->end.rank == NO_POS)
400401 alg_fail("no pieces with access to end location");
401402
402403 done:
457458 result->parent->post_board->fifty_move_counter + 1;
458459 }
459460
460 result->post_board->access_map = calloc(1, sizeof(struct access_map));
461 build_access_map(result, result->post_board->access_map);
461 build_access_map(result);
462
462463 result->post_board->ply_index =
463464 1 + result->parent->post_board->ply_index;
464465 result->post_board->pgn = create_pgn(result);
7373 (struct piece){ .color = BLACK, .piece_type = KNIGHT };
7474 b->board[7][7] = (struct piece){ .color = BLACK, .piece_type = ROOK };
7575
76 b->access_map = calloc(1, sizeof(struct access_map));
76 memset(b->access, NO_POS, sizeof b->access);
7777 b->termination = AVAILABLE_MOVE;
7878 b->draws = DRAW_NONE;
7979 b->in_check = false;
227227
228228 /* TODO: en passant square */
229229
230 board->access_map = calloc(1, sizeof(struct access_map));
231 build_access_map(result, board->access_map);
230 build_access_map(result);
232231 return result;
233232
234233 error:
150150 int rank;
151151 int file;
152152 int i;
153 int n_accessors;
154153 const struct position *a;
155154 const struct piece *p;
156155 json_t *board_root;
202201 for (file = 0; file < 8; file++)
203202 {
204203 access_array = json_array();
205 n_accessors =
206 board->access_map->board[rank][file].n_accessors;
207 for (i = 0; i < n_accessors; i++)
208 {
209 a = &board->access_map->board[rank][file]
210 .accessors[i];
204 for (i = 0; i < MAX_ACCESSORS; i++)
205 {
206 a = &board->access[rank][file][i];
207 if (a->rank == NO_POS || a->file == NO_POS)
208 break;
211209 temp = json_array();
212210 json_array_append_new(
213211 temp, json_integer(a->rank));
7676 in_checkmate(struct move *move, color_t player)
7777 {
7878 struct position king_position;
79 struct position test_pos;
79 struct position p;
8080 struct piece constraints;
8181 struct move *test_move;
82 struct position *threats;
82 struct position threats[MAX_ACCESSORS];
8383 struct board *b;
8484 char *cap_str;
8585 char move_str[6];
105105 {
106106 if (d_file == 0 && d_rank == 0)
107107 continue;
108 test_pos.rank = king_position.rank + d_rank;
109 test_pos.file = king_position.file + d_file;
110 if (0 > test_pos.rank || test_pos.rank > 7)
111 continue;
112 if (0 > test_pos.file || test_pos.file > 7)
113 continue;
114 if (b->board[test_pos.rank][test_pos.file].color
115 == player)
116 continue;
117 if (b->board[test_pos.rank][test_pos.file].piece_type
118 == 0)
108 p.rank = king_position.rank + d_rank;
109 p.file = king_position.file + d_file;
110 if (p.rank > 7)
111 continue;
112 if (p.file > 7)
113 continue;
114 if (b->board[p.rank][p.file].color == player)
115 continue;
116 if (!b->board[p.rank][p.file].piece_type)
119117 cap_str = "";
120118 else
121119 cap_str = "x";
122120
123121 snprintf(
124122 move_str, 6, "K%s%c%c", cap_str,
125 test_pos.file + 'a', test_pos.rank + '1');
123 p.file + 'a', p.rank + '1');
126124 parse_algebraic(move_str, move, &test_move);
127125 if (test_move != NULL)
128126 {
142140
143141 test_move = calloc(1, sizeof(struct move));
144142 test_move->parent = move;
145 test_move->start.rank = -1;
146 test_move->start.file = -1;
143 test_move->start.rank = NO_POS;
144 test_move->start.file = NO_POS;
147145 test_move->end.rank = king_position.rank;
148146 test_move->end.file = king_position.file;
149147
150 find_all_with_access(constraints, test_move, &n_threats, &threats);
148 find_all_with_access(constraints, test_move, threats);
149 /* Count how many threats are in the threats array */
150 for (n_threats = 0;
151 n_threats < MAX_ACCESSORS && threats[n_threats].rank != NO_POS
152 && threats[n_threats].file != NO_POS;
153 n_threats++);
151154 assert(n_threats > 0);
152155
153156 /* If more than one threat exists, double check! We're hosed. */
154157 if (n_threats > 1)
155 {
156 free(threats);
157158 return true;
158 }
159159
160160 /* See if anything can capture the threatening piece. */
161161 debugf("threat: %c%c\n", threats[0].file + 'a', threats[0].rank + '1');
162162 if (can_attack(move, threats[0], player))
163 {
164 free(threats);
165 return false;
166 }
163 return false;
167164
168165 /* Last check: see if we can block the threatening piece. */
169166 if (can_block(move, threats[0], king_position, player))
170 {
171 free(threats);
172 return false;
173 }
174
175 free(threats);
167 return false;
168
176169 return true;
177170 }
178171
180173 in_stalemate(struct move *move, color_t player)
181174 {
182175 struct piece *piece;
183 struct position *position;
184 struct access_map *map;
176 struct position *p;
185177 struct board *board;
186178 int rank;
187179 int file;
194186 * our color that can access them. If we find one, it means that this
195187 * player has a valid move and we're not in forced stalemate. */
196188 board = move->post_board;
197 map = board->access_map;
198189 for (rank = 0; rank < 8; rank++)
199190 {
200191 for (file = 0; file < 8; file++)
201192 {
202 for (i = 0; i < map->board[rank][file].n_accessors;
203 i++)
193 for (i = 0; i < MAX_ACCESSORS; i++)
204194 {
205 position =
206 &map->board[rank][file].accessors[i];
207 piece = &board->board[position->rank]
208 [position->file];
195 p = &board->access[rank][file][i];
196 if (p->rank == NO_POS || p->file == NO_POS)
197 break;
198 piece = &board->board[p->rank][p->file];
209199 if (piece->color == player)
210200 return false;
211201 }
2121 #include <stdlib.h>
2222
2323 void
24 build_access_map(struct move *move, struct access_map *out)
24 build_access_map(struct move *move)
2525 {
2626 int rank;
2727 int file;
3737 {
3838 for (file = 0; file < 8; file++)
3939 {
40 test_move.start.rank = -1;
41 test_move.start.file = -1;
40 test_move.start.rank = NO_POS;
41 test_move.start.file = NO_POS;
4242 test_move.end.rank = rank;
4343 test_move.end.file = file;
4444
4545 find_all_with_access(
4646 constraints, &test_move,
47 &out->board[rank][file].n_accessors,
48 &out->board[rank][file].accessors);
47 move->post_board->access[rank][file]);
4948 }
5049 }
5150 }
52
53 void
54 free_access_map(struct access_map *map)
55 {
56 int rank;
57 int file;
58 for (rank = 0; rank < 8; rank++)
59 for (file = 0; file < 8; file++)
60 if (map->board[rank][file].n_accessors > 0)
61 free(map->board[rank][file].accessors);
62 free(map);
63 }
307307 struct piece *piece;
308308 struct piece *captured;
309309
310 if (0 > move->start.rank || 7 < move->start.rank)
311 return false;
312 if (0 > move->start.file || 7 < move->start.file)
313 return false;
314 if (0 > move->end.rank || 7 < move->end.rank)
315 return false;
316 if (0 > move->end.file || 7 < move->end.file)
310 if (7 < move->start.rank)
311 return false;
312 if (7 < move->start.file)
313 return false;
314 if (7 < move->end.rank)
315 return false;
316 if (7 < move->end.file)
317317 return false;
318318
319319 piece = &move->parent->post_board
2424 #include <string.h>
2525
2626 void
27 init_gametree(struct game_tree *gt)
27 init_game_tree(struct game_tree *gt)
2828 {
2929 gt->n_states = 1;
3030 gt->states = calloc(1, sizeof(struct state_node *));
179179 out->player = BLACK;
180180 out->post_board = calloc(1, sizeof(struct board));
181181 load_default_board(out->post_board);
182 build_access_map(out, out->post_board->access_map);
182 build_access_map(out);
183183 }
184184
185185 void
195195 {
196196 if (move->post_board != NULL)
197197 {
198 if (move->post_board->access_map != NULL)
199 free(move->post_board->access_map);
200198 free(move->post_board);
201199 }
202200 if (move->algebraic != NULL)