-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathdobutsutable.h
202 lines (183 loc) · 7.53 KB
/
dobutsutable.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
/*-
* Copyright (c) 2016--2017 Robert Clausecker. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <assert.h>
#include "atomics.h"
#include "tablebase.h"
#include "dobutsu.h"
/*
* This header contains the low-level interface to the endgame tablebase
* as well as prototypes for functions used to implement it.
*/
/*
* the endgame tablebase is organized on four levels:
* 1. by piece ownership.
* 2. by the cohort, that is, which pieces are on the board
* 3. by the position of the lions on the board
* 4. by the position of the other pieces on the board
*
* For each cohort, there is a an array containing the distance-to-mate
* (dtm) information for this cohort. The index into this array is
* is computed by multiplying lion position, map, and piece ownership
* into one offset. Separate arrays for each cohort are needed because
* depending on how many pieces are on the board and which of the pieces
* are distinguishable, the size of the cohort changes.
*
* The following constants describe how many of each encoding level
* exist. If some values of an encoding level are possible but not
* stored in the endgame tablebase, a corresponding _TOTAL macro is
* present as well.
*/
enum {
COHORT_COUNT = 63,
LIONPOS_COUNT = 21,
LIONPOS_TOTAL_COUNT = 41,
OWNERSHIP_COUNT = 42,
OWNERSHIP_TOTAL_COUNT = 64,
/* total positions in the table base */
POSITION_TOTAL_COUNT = 255280704,
/* number of positions saved to disk (167527962) */
POSITION_COUNT = POSITION_TOTAL_COUNT / OWNERSHIP_TOTAL_COUNT * OWNERSHIP_COUNT,
MAX_PCALIAS = 16,
};
/*
* cohort_table contains information for each cohort. The following
* information is stored:
*
* - in pieces, how many of each kind of piece there are
* - in status, the chicken promotion bits
* - in sizes, how large the encoding space for each piece group
* ignoring the lions is.
*
* One byte of padding is added to make each entry eight bytes long.
*/
extern const struct cohort_info {
unsigned char pieces[3]; /* 0: chicks, 1: giraffes, 2: elephants */
unsigned char status; /* only promotion bits are set */
unsigned char sizes[3];
unsigned char padding; /* for alignment */
} cohort_info[COHORT_COUNT];
/*
* cohort_size contains size information for each cohort. The following
* information is stored:
*
* - the offset of the beginning of data for that cohort in the tablebase
* - the number of ways to arrange chicks, giraffes, and elephants in that
* cohort.
*
* this table is separate from cohort_info so that a record in each
* table is 8 bytes long, allowing an indexed addressing mode to be used
* on x86.
*/
extern const struct cohort_size {
unsigned offset, size;
} cohort_size[COHORT_COUNT];
/*
* This table contains a bitmap with a 1 for every combination of ownership
* cohort that is valid. This table is used by has_valid_ownweship().
*/
extern const unsigned long long valid_ownership_map[COHORT_COUNT];
/*
* To save space, we only store positions in the table base where Sente
* has no less pieces than Gote. To facilate this, we permute the order
* in which ownership is stored in the table such that all positions
* with an equal or higher amount of pieces for Sente appear first.
* This table contains a permutation of the ownership values such that
* does values where Sente owns not less than three pieces are first.
*/
extern const unsigned char ownership_map[OWNERSHIP_TOTAL_COUNT];
/*
* The tablebase struct contains a complete tablebase. It is essentially
* just a huge array of position evaluations (win/draw/loss).
*/
struct tablebase {
atomic_schar positions[POSITION_COUNT];
};
/*
* A poscode (position code) is an encoded position directly suitable as
* an index into the endgame tablebase. A typedef is provided so we can
* easily switch to an implementation where poscode is a numeric type.
*
* The poscode comprises the following pieces:
* - (0 -- 63) ownership is a bitmap indicating who owns which piece
* - (0 -- 62) cohort is a number indicating what pieces are on the
* board and if they are promoted
* - (0 -- 49) lionpos is a number indicating where the lions are
* placed. All positions with lionpos 24 -- 49 are checkmates.
* - (0 -- 18899) map is a number indicating which pieces occupy what
* square. The maximum value for this field depends on the value in
* cohort.
*
* Not all positions are stored in the tablebase: positions with both
* lions adjacent or one lion already ascended aren't. Neverthless,
* even these positions are encodeable for simplicity.
*
* Before a position is encoded, it is normalized. This means:
* - if it's Gote's move, the board is turned so a position with Sente
* to move obtains.
* - the board is flipped horizontally under certain conditions
* - pieces of the same kind are interchanged such that the _G piece
* always occupies a higher square than the _S piece where "in hand"
* is a higher square than all other squares.
*/
typedef struct {
unsigned ownership;
unsigned cohort;
unsigned lionpos;
unsigned map;
} poscode;
extern void encode_position(poscode*, const struct position*);
extern void decode_poscode(struct position*, poscode);
extern int position_mirror(struct position*);
static inline size_t position_offset(poscode);
static inline int has_valid_ownership(poscode);
/* inline functions */
/*
* position_offset() returns the offset of pc in the tablebase. It is
* assumed that pc represents a valid position code that is in the table
* base (i.e. with lionpos < LIONPOS_TOTAL).
*/
static inline size_t
position_offset(poscode pc)
{
size_t index;
assert(pc.lionpos < LIONPOS_COUNT);
index = ownership_map[pc.ownership] * (POSITION_TOTAL_COUNT / OWNERSHIP_TOTAL_COUNT);
index += cohort_size[pc.cohort].offset;
index += cohort_size[pc.cohort].size * pc.lionpos;
index += pc.map;
return (index);
}
/*
* To reduce the computational load, we only consider poscodes where for
* each kind of piece, if both pieces are in hand, the _G piece is owned
* by Gote only if the _S piece is owned by Gote, too (i.e. the allowed
* ownership combinations are 11, 01, and 00). This function checks if
* this assertion holds and returns 1 if it does, 0 if it doesn't.
*/
static inline int
has_valid_ownership(poscode pc)
{
return !!(valid_ownership_map[pc.cohort] & 1ULL << pc.ownership);
}