├── .gitignore
├── COPYING.txt
├── README.md
├── checksums
├── dtz345.txt
├── dtz6.txt
├── dtz7.txt
├── wdl345.txt
├── wdl6.txt
└── wdl7.txt
├── interface
├── main.cpp
├── search.cpp
├── tbcore.c
├── tbcore.h
├── tbprobe.cpp
├── tbprobe.h
└── types.h
└── src
├── Makefile
├── Makefile.atomic
├── Makefile.general
├── Makefile.giveaway
├── Makefile.regular
├── Makefile.shatranj
├── Makefile.suicide
├── atbgen.c
├── atbgenp.c
├── atbver.c
├── atbverp.c
├── bmi2.c
├── bmi2.h
├── board.c
├── board.h
├── checksum.c
├── checksum.h
├── city-c.c
├── city-c.h
├── citycrc.h
├── compress.c
├── compress.h
├── compress_tmpl.c
├── crc32c.c
├── decompress.c
├── decompress.h
├── defs.h
├── generic.c
├── genericp.c
├── generics.c
├── huffman.c
├── huffman.h
├── hyper.c
├── hyper.h
├── jtbgen.c
├── jtbgenp.c
├── lz4.c
├── lz4.h
├── lz4_decoder.h
├── lz4_encoder.h
├── magic.c
├── magic.h
├── permute.c
├── permute.h
├── permute_tmpl.c
├── probe.c
├── probe.h
├── reduce.c
├── reduce_tmpl.c
├── reducep.c
├── reducep_tmpl.c
├── rtbgen.c
├── rtbgenp.c
├── rtbver.c
├── rtbverp.c
├── run.pl
├── sprobe.c
├── stats.c
├── statsp.c
├── stbgen.c
├── stbgenp.c
├── tbcheck.c
├── tbgen.c
├── tbgenp.c
├── tbver.c
├── tbverp.c
├── threads.c
├── threads.h
├── types.h
├── util.c
└── util.h
/.gitignore:
--------------------------------------------------------------------------------
1 | *.o
2 | *.P
3 | *.swp
4 | *.txt
5 | *.rtbw
6 | *.rtbz
7 | rtbgen
8 | rtbgenp
9 | rtbver
10 | rtbverp
11 | tbcheck
12 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ### Overview
2 |
3 | Included are a tablebase generator and probing code for adding tablebase
4 | probing to a chess engine. The tablebase generator is able to generate
5 | all tablebases for up to 6 pieces.
6 |
7 | Requirements for the generator:
8 | * 16 GB of RAM for 6-piece tables (much less for 5-piece tables).
9 | * x86-64 CPU.
10 | * 64-bit OS.
11 | * Sufficiently recent gcc (producing 64-bit executables).
12 |
13 |
14 | ### Tablebase files
15 |
16 | File names encode the type of tablebase: K+R+P vs K+R becomes KRPvKR.
17 | Each tablebase corresponds to two files: KRPvKR.rtbw and KRPvKR.rtbz.
18 | Note that KRPvKR also covers K+R vs K+R+P.
19 |
20 | The .rtbw files store win/draw/loss information including, where applicable,
21 | information on the 50-move rule. During the search only the .rtbw files
22 | are accessed. These files are "two-sided": they store information for both
23 | white to move and black to move.
24 |
25 | The .rtbz files store the distance-to-zero: the number of moves to the next
26 | capture or pawn move. These files only need to be accessed when the root
27 | position has 6 pieces or less. They are "single-sided".
28 |
29 | The 6-piece WDL tables are 68.2 GB in total. The DTZ tables take up 81.9 GB.
30 | For up to 5 pieces, the numbers are 378 MB and 561 MB. Ideally, the WDL
31 | tables are stored on an SSD.
32 |
33 |
34 | ### Tablebase generator
35 |
36 | The directory src/ contains the tablebase generator code. It should be
37 | easy to build on x86-64 Linux system and on 64-bit Windows with MinGW
38 | ("make all"). It might be necessary to edit src/Makefile. In particular,
39 | **if your CPU does not support the popcnt instruction**, the line `FLAGS +=
40 | -DUSE_POPCNT` should be commented out.
41 |
42 | There are five programs:
43 | * rtbgen for generating pawnless tablebases.
44 | * rtbgenp for generating pawnful tablebases.
45 | * rtbver for verifying pawnless tablebases.
46 | * rtbverp for verifying pawnful tablebases.
47 | * tbcheck for verifying integrity of tablebase files based on an embedded
48 | checksum.
49 |
50 | **Note 1:** Since a correct set of checksums is known, there is no need for anyone to run rtbver and rtbverp.
51 |
52 | **Note 2:** The checksums are **not** md5sums. However, correct md5sums are known as well, and these can also be used to verify integrity. See http://kirill-kryukov.com/chess/tablebases-online/
53 |
54 | **Usage:** `rtbgen KQRvKR` (or `rtbgenp KRPvKR`)
55 | Produces two compressed files: KQRvKR.rtbw and KQRvKR.rtbz. Both files
56 | contain an embedded checksum.
57 |
58 | **Options:**
59 | --threads n (or -t n)
60 | Use n threads. If no other tasks are running, it is recommended to
61 | set n to the number of CPU cores, or if the CPU supports hyperthreading,
62 | to the number of CPU hyperthreads.
63 |
64 | --wdl (or -w)
65 | Only compress and save the WDL file (with .rtbw suffix).
66 |
67 | --dtz (or -z)
68 | Only compress and save the DTZ file (with .rtbz suffix).
69 |
70 | -g
71 | Generate the table but do not compress and save.
72 |
73 | --stats (or -s)
74 | Save statistics. Statistics are written to $RTBSTATSDIR/KQRvKR.txt
75 | or to ./KQRvKR.txt if $RTBSTATSDIR is not set.
76 |
77 | --disk (or -d)
78 | Reduce RAM usage during compression. This takes a bit more time because
79 | tables are temporarily saved to disk. **This option is necessary to
80 | generate 6-piece tables on systems with 16 GB RAM.** This option is
81 | not needed on systems with 24 GB RAM or more.
82 |
83 | **Usage:** `rtbver KQRvKR` (or `rtbverp KRPvKR`)
84 | Verifies consistency of KQRvKR.rtbw and KQRvKR.rtbz. This should detect
85 | (hardware) errors during generation and compression. For technical reasons
86 | pawnful tables with symmetric material such as KPvKP and KRPvKRP cannot
87 | (at least currently) be verified.
88 |
89 | **Options:**
90 | --threads n (or -t n)
91 | See above.
92 |
93 | --log (or -l)
94 | Log verification results to rtblog.txt.
95 |
96 | -d
97 | Look for the WDL file in directory $RTBWDIR and look for the DTZ file in
98 | directory $RTBZDIR. Without this option, both files should be present in
99 | the current working directory.
100 |
101 | **Usage:** `tbcheck KQRvKR.rtbw KRPvKR.rtbz`
102 | Recalculates a checksum for each specified tablebase file and compares with
103 | the embedded checksums. This should detect disk errors and transmission
104 | errors.
105 |
106 | **Options:**
107 | --threads n (or -t n)
108 | See above.
109 |
110 | --print (or -p)
111 | Print embedded checksums. Do not check correctness.
112 |
113 | **Alternative usage:** `tbcheck --compare wdl345.txt`
114 | Compares the embedded checksum for each tablebase file listed in wdl345.txt
115 | with the checksum specified in wdl345.txt. Note that these are not md5sums.
116 |
117 | Note: The programs rtbgen, rtbgenp, rtbver and rtbverp require access
118 | to WDL tablebase files for "subtables". These should be present in
119 | the directory $RTBWDIR. The program tbcheck only looks in the current working
120 | directory.
121 |
122 |
123 | ### Scripts
124 |
125 | The somewhat primitive perl script src/run.pl can be used for generating
126 | and verifying all or part of the tables. Make sure the location of rtbgen,
127 | rtbgenp, rtbver and rtbverp is in your $PATH variable.
128 |
129 | **Usage:** `run.pl --generate`
130 |
131 | **Options:**
132 | --threads n (or -t n)
133 | See above.
134 |
135 | --generate
136 | Generate tablebases. Tablebases that already have been generated and are
137 | found in the current working directory are skipped.
138 |
139 | --verify
140 | Verify tablebases.
141 |
142 | --min n
143 | Only treat tablebases with at least n pieces.
144 |
145 | --max n
146 | Only treat tablebases with at most n pieces.
147 |
148 | --disk
149 | Use this option to generate 6-piece tables on a system with 16 GB of RAM.
150 |
151 |
152 | ### Probing code
153 |
154 | The directory interface/ contains probing code. It does not come in the
155 | form of a shared library, and requires some work to integrate into an
156 | engine. The main reason for this is efficiency. There are four files:
157 | tbcore.c, tbcore.h, tbprobe.cpp, tbprobe.h.
158 |
159 | The files tbcore.c and tbcore.h should not require many changes, although
160 | engine authors might want to replace some printf()s with suitable logging
161 | statements. The files tbprobe.cpp and tbprobe.h do require some changes
162 | but these should be fairly straightforward when following the comments.
163 | The only reason for tbprobe.cpp having the .cpp extension is that I have
164 | used Stockfish as example. The probing code is initialised by calling
165 | init_tablebases(path), where path contains the directories (separated with
166 | a colon on Linux and with a semicolon on Windows) where the WDL and DTZ
167 | files are to be found.
168 |
169 | The files main.cpp, search.cpp and types.h are from Stockfish with calls
170 | to the probing code added (see // TB comments). The change in types.h is
171 | necessary in order to make room for "tablebase win in n" values distinct
172 | from "mate in n" values. Please note that the integration of probing code
173 | into Stockfish is merely intended as a proof of concept.
174 |
175 | Note that when properly integrating the interface code in an engine that is
176 | not Stockfish, no trace of Stockfish will be left. The engine author will
177 | have to rewrite the Stockfish-specific glueing code to match his or her
178 | engine. Therefore no copyright issues can arise (see also below).
179 |
180 |
181 | ### Terms of use
182 |
183 | The files lz4.c and lz4.h in src/ are copyrighted by Yann Collet and were
184 | released under the BSD 2-Clause License. The files city-c.c, city-c.h and
185 | citycrc.h in src/ (ported by me from C++ to C) are copyrighted by Google,
186 | Inc. and were released under an even more liberal license. Both licenses
187 | are compatible with the GPL. All other files in src/ are released under
188 | the GNU Public License, version 2 (only).
189 |
190 | The files main.cpp, search.cpp and types.h in interface/ obviously are
191 | copyrighted by the Stockfish authors and covered by the Stockfish GPL with
192 | the exception of the code fragments preceded by // TB comments. These
193 | fragments may be freely modified and redistributed in source and/or binary
194 | format.
195 |
196 | All tablebase files generated using this generator may be freely redistributed.
197 | In fact, those files are free of copyright at least under US law (following
198 | Feist Publications, Inc., v. Rural Telephone Service Co., 499 U.S. 340 (1991))
199 | and under EU law (following Football Dataco and Others v. Yahoo! UK Ltd and
200 | Others (C-604/10)).
201 |
202 |
203 | Ronald de Man
204 | syzygy_tb@yahoo.com
205 |
206 |
--------------------------------------------------------------------------------
/checksums/dtz345.txt:
--------------------------------------------------------------------------------
1 | KBBBvK.rtbz: ca8b529e20b607b3ce74e3c4c43e955e
2 | KBBNvK.rtbz: 220568265777e7bb975ce09957b9e98f
3 | KBBPvK.rtbz: cf2cc6ddb965288a320cec3a6c6c53d9
4 | KBBvKB.rtbz: 74853ece120149b95227979e66d14d63
5 | KBBvKN.rtbz: 74ff1d0e462b0559bb86d83c3c3e2e08
6 | KBBvKP.rtbz: 83afa467ed4d5795d8c07eff2177f05f
7 | KBBvKQ.rtbz: c069132ad7de822f5235cbc563e4e3bf
8 | KBBvKR.rtbz: 411ea8c9ff9e1bc99660463d2d999914
9 | KBBvK.rtbz: 13d29f3861591beb4be3758fb7a9edf1
10 | KBNNvK.rtbz: 1523aaf16b68f0c2027dd26a0ca7a75d
11 | KBNPvK.rtbz: 1e6a1395e41d44ec99a5d1448438f065
12 | KBNvKB.rtbz: 7da46a8afb37d66751ccb3128cd796db
13 | KBNvKN.rtbz: 8b12a093be330f366631f4918ff9eaac
14 | KBNvKP.rtbz: 18f72e15d8579e428026800135699456
15 | KBNvKQ.rtbz: bbaa52d915ac58fcfa40ab7addba9be6
16 | KBNvKR.rtbz: 573c0fc05955cafa850a28035962156d
17 | KBNvK.rtbz: bf069a4b0e2e0b292f8b3951b7b7e7ee
18 | KBPPvK.rtbz: 9b8417f7ffcb97285b135f2ac80e2515
19 | KBPvKB.rtbz: cab7048e0076c29f37322b6ecb0dd661
20 | KBPvKN.rtbz: 9c3628d9a1d01e5c2900d31cbaa76742
21 | KBPvKP.rtbz: 661e5e970e04bd20d2aac3fab6bf1788
22 | KBPvKQ.rtbz: dad709ca5c1b1f2261d261fc094f56d4
23 | KBPvKR.rtbz: d7ec4dc15f46c83990599fd5fd5da950
24 | KBPvK.rtbz: d8080286697e3885a71ffc31f821c1f7
25 | KBvKB.rtbz: 9ca7bb25b5d2077aa209ceac0bb1d9f7
26 | KBvKN.rtbz: 7fd6ea834cdbc9bcbc46adbb68bb4a2b
27 | KBvKP.rtbz: 697bffeddc8ee22d3e01cd12f2cbbbb5
28 | KBvK.rtbz: 338f272b119c02ca67b03a450c375b2e
29 | KNNNvK.rtbz: 90f9e152a36da76f42236bf0449193cb
30 | KNNPvK.rtbz: 46047bdf0f864591f5ad611e6da2249d
31 | KNNvKB.rtbz: 5ef1e8e6a1adc943a7e81afe13beefe2
32 | KNNvKN.rtbz: 4b9d6086b75006d778b3818ac7a22d5b
33 | KNNvKP.rtbz: b8a98868239ede8aca6913ae921a4f97
34 | KNNvKQ.rtbz: 1bc6d65112bd4d5e60f7ffb9a62867c5
35 | KNNvKR.rtbz: df62208af31506e1dd39554361518087
36 | KNNvK.rtbz: 9e91f9fe4d7f7f8dfb47484a532430bf
37 | KNPPvK.rtbz: 03190582b90c80b273cac2fd4d03c2ab
38 | KNPvKB.rtbz: 5c4768bc12a048e00eeeedd550a742de
39 | KNPvKN.rtbz: 722e9889474fe1821eca5151eaada0fa
40 | KNPvKP.rtbz: fe999e2b1611f2477c569c58edff3082
41 | KNPvKQ.rtbz: a10bcfaad2612c862fcf475b2428fdd4
42 | KNPvKR.rtbz: 654a0ef113634a8e2fca9c2d53a13807
43 | KNPvK.rtbz: e8886f6c52dad3bb43d1c3de0c3f1a8e
44 | KNvKN.rtbz: 2da62bda60bfb92cbd4672db2cd6b6c5
45 | KNvKP.rtbz: cd4ad308e4d126deae3d33111d990f56
46 | KNvK.rtbz: 796ab960a6140d5b030f785e91086175
47 | KPPPvK.rtbz: ac2aec5973516d32f8860c7e78d4fff5
48 | KPPvKB.rtbz: d8758cb73538749cc97faecc8f2cd3b6
49 | KPPvKN.rtbz: c135a90aeba8aaa0e602a5d17308b32e
50 | KPPvKP.rtbz: ba1085022fff7fa179ba2fef92131684
51 | KPPvKQ.rtbz: 0f5f4712be067fccfbf1c9e39dbb3219
52 | KPPvKR.rtbz: 94cd3614a44c9049d7fb7c1c7c2cd493
53 | KPPvK.rtbz: 09bd75efbaaead72a1e4e4b63fa35224
54 | KPvKP.rtbz: 77ea7a20bdb4ed4244fff34bc4c99a85
55 | KPvK.rtbz: f72a3a4f9b1b4afb6e8335bed985b891
56 | KQBBvK.rtbz: 4bf06892e80a7e9503838d40152926f7
57 | KQBNvK.rtbz: 971ad48c660330c8ab7630f0b7704048
58 | KQBPvK.rtbz: 3e2d75a713623625b9a8f6b9b4a082aa
59 | KQBvKB.rtbz: bbede31cd59532ccdacf107e33693abc
60 | KQBvKN.rtbz: 6a4aa51c635793f74f8fc37bdcdd423b
61 | KQBvKP.rtbz: f511d9d9e62439bd717d26d6b626e77d
62 | KQBvKQ.rtbz: 94bede5ae0bb048fdecf93ab5965fec2
63 | KQBvKR.rtbz: e8c2f6ad70a5991960a54fa235974bef
64 | KQBvK.rtbz: 40cca181034afa79be1781b03cc1029e
65 | KQNNvK.rtbz: d014333bd6e32a92f94e61e5f658caee
66 | KQNPvK.rtbz: 7c817e26d90b1c013f3a1584950e89e4
67 | KQNvKB.rtbz: 8a521fc65e36e09ab07bcbaebdac7975
68 | KQNvKN.rtbz: cade7170506b3b4c677ad20c2d8beb28
69 | KQNvKP.rtbz: a3f18e2f2288efadec53890134af6a8b
70 | KQNvKQ.rtbz: c7ad85c3a38b4e0ff55fe8852ddca8eb
71 | KQNvKR.rtbz: a0a9fdfa0829ce9455a3b20ad2c9ebd1
72 | KQNvK.rtbz: 0cf5ab472ed2e50cb396294e18095499
73 | KQPPvK.rtbz: 674f17307a6ab5c31dbdbbbc446399a3
74 | KQPvKB.rtbz: a0d00a8834472f21cfea4d4d97ba5aec
75 | KQPvKN.rtbz: c16a5d070ad866526f8ffbf2fbd4cbd2
76 | KQPvKP.rtbz: bd6dec6a6a089051d16ff9c3ec72b1c2
77 | KQPvKQ.rtbz: 2d226cbcba844ae906924d57090e13c8
78 | KQPvKR.rtbz: 17bacde708f0e419983705fc132de51d
79 | KQPvK.rtbz: f081fb6c078f7cec6c3a9d457c5a29ef
80 | KQQBvK.rtbz: 5529f3da5e37089b8e179a6739aa21e5
81 | KQQNvK.rtbz: fae7e2a2b4940d6a1ff01c4847d2628c
82 | KQQPvK.rtbz: c07b4c79e8b0b7c725c699a8574d9484
83 | KQQQvK.rtbz: 49e50e7dea8e72ba2286cb29dad72a02
84 | KQQRvK.rtbz: c564d585b1123312e2bf87051008dbeb
85 | KQQvKB.rtbz: 0c83247dbdf060745274dc0243128aa9
86 | KQQvKN.rtbz: b97def864be70cb96020cd7429ce0ee7
87 | KQQvKP.rtbz: 1bd8e4258b180c5bb4181af4d8c3cab7
88 | KQQvKQ.rtbz: 956b37275fa6cc0b6c5d0c0632eca421
89 | KQQvKR.rtbz: 671a0ca64b208f0f1066f507357e9d4d
90 | KQQvK.rtbz: 29ff276c0dd3e18d72cf33e4fa47d8a9
91 | KQRBvK.rtbz: 503cbdbcb3f454dd804669066f92036c
92 | KQRNvK.rtbz: d3f5af2faa5702bb5d65837ef9790eb3
93 | KQRPvK.rtbz: f49d0ac91e50596c8090184ca7079243
94 | KQRRvK.rtbz: 6e24af14e5b122e7e203f08b819ed744
95 | KQRvKB.rtbz: 6e0544a3d584502cbbeb1b016a1d6c8c
96 | KQRvKN.rtbz: 249aac92b94293baf561c05f4b4d857e
97 | KQRvKP.rtbz: fb38e6ee887700ebe2d7cefdf2058f85
98 | KQRvKQ.rtbz: 67f894380070bf0981f73ccaabf8687e
99 | KQRvKR.rtbz: 205ff93e24d8444c330c892eb6025c16
100 | KQRvK.rtbz: 1aebce5058a9bc16611934662bb04323
101 | KQvKB.rtbz: 8210ba4ad1615a09696e732a0cd4a025
102 | KQvKN.rtbz: 93190fa62b5e29f11200670810c92666
103 | KQvKP.rtbz: ccb559befcf80b7e63e5e804da5bf33e
104 | KQvKQ.rtbz: d3449ba56b4a43aa3532529ae0504e77
105 | KQvKR.rtbz: 9ab3ebd50443b9e9a930358658cfe83f
106 | KQvK.rtbz: c51fa4b08478f04272ec668ce70d6ca7
107 | KRBBvK.rtbz: 32ca770f2e4e00eb95fb80d3a9c5b2a5
108 | KRBNvK.rtbz: 6643520d61e8d83006bde9fcdfdaa086
109 | KRBPvK.rtbz: a34592083c50eace63563958431d9ed9
110 | KRBvKB.rtbz: fb3431aadb257a9a93e6bed124f176fe
111 | KRBvKN.rtbz: 5c2cc4b345d5e840fc1a3d3c4ab1c1b3
112 | KRBvKP.rtbz: afd5fb5f64f87541673658dd062c7316
113 | KRBvKQ.rtbz: 65d188cf3b0e536bd5b92bbbc4b4ee7c
114 | KRBvKR.rtbz: 3747f83c9919d5a8e3406b25ae7e0423
115 | KRBvK.rtbz: 818d893c77de2e6137fec1304ba72cff
116 | KRNNvK.rtbz: 2ddb0d5385eb5042a01c967a6c31bb9e
117 | KRNPvK.rtbz: 2f05b44c197521fb3925a5151c191cc7
118 | KRNvKB.rtbz: 27f9f26f3fa909bc266f3b69754b575a
119 | KRNvKN.rtbz: 86b892caf3c7cbb8909fde610cfc3aef
120 | KRNvKP.rtbz: fd988d55e02a565b8818b6cf569721f8
121 | KRNvKQ.rtbz: 239db89cd3e90c7452af655f28e67c11
122 | KRNvKR.rtbz: e17c6fe04d71ea6c341aa5df7ec06697
123 | KRNvK.rtbz: f2ba04ea762c4b8edd91df1095bfd56f
124 | KRPPvK.rtbz: d084c65cc2e91060ee64f5d6195f2e1e
125 | KRPvKB.rtbz: 11e7240947019ac69df8503ee75a4898
126 | KRPvKN.rtbz: a302375fea4bc00fb6a43358506ea2ab
127 | KRPvKP.rtbz: f20d2a5710466b6b90b033f87659062e
128 | KRPvKQ.rtbz: 7d247cad8fd367d4d680e91bcd7948b2
129 | KRPvKR.rtbz: 3ca9b954b05bcdb777877d435fab781a
130 | KRPvK.rtbz: cdf66f526890d211400e2239ea290f50
131 | KRRBvK.rtbz: f2fded97da3604c580e9a422ee2d49f9
132 | KRRNvK.rtbz: a9e5fd560050284900a1d5194039baa1
133 | KRRPvK.rtbz: f92ee6ff367c396146b55a8e6b9401cf
134 | KRRRvK.rtbz: 879c8f84839ebe510ae4d54db522d568
135 | KRRvKB.rtbz: 1fc169defb6c8e5127336ce99c82023e
136 | KRRvKN.rtbz: 51c0997dda83bc48ba4a7db534e823bf
137 | KRRvKP.rtbz: d1d3a77d9cfc5b56bfee42dbc3b4483f
138 | KRRvKQ.rtbz: adfa646310009e60d45c0b9743d50476
139 | KRRvKR.rtbz: e0d530830a4aa8f7cba0546e01403ddd
140 | KRRvK.rtbz: 706fd9c3ba4c539aa413aeb0bd7a9809
141 | KRvKB.rtbz: a571bf1f5995f512d17843be314767ba
142 | KRvKN.rtbz: 9993860c9c1422e83a2474e94c38cc9c
143 | KRvKP.rtbz: 3ec7dd03aa7e10846e4a45c4588ad8b4
144 | KRvKR.rtbz: 0779bffa326eca37b0e242bc9ec89968
145 | KRvK.rtbz: 1df564d7e7056f15d9a1d776e8fe5884
146 |
--------------------------------------------------------------------------------
/checksums/wdl345.txt:
--------------------------------------------------------------------------------
1 | KBBBvK.rtbw: fe211316630db82fd1a355740639b715
2 | KBBNvK.rtbw: 59bed619025bc69a54d93832f4312e42
3 | KBBPvK.rtbw: eeb2a21bb6c52efbc41b8f29590d5f31
4 | KBBvKB.rtbw: 1d948fff757950a1214668360d56ee74
5 | KBBvKN.rtbw: 16cb3dc1a1cb5ce0b9d7bb8978ea8c16
6 | KBBvKP.rtbw: 5e92cd639d1b9fd3fb683d098c87b20e
7 | KBBvKQ.rtbw: 2c2df4bdcbd04ac0d335b47ed5a401f1
8 | KBBvKR.rtbw: 7d1d28df6cab9dc72d05653f170867c7
9 | KBBvK.rtbw: 457a28e5df290b59ef4448bafad18bd3
10 | KBNNvK.rtbw: 3f7a7ec41d472caaab3def5716bac004
11 | KBNPvK.rtbw: 3a755fd9141e3813a20491aec20daedc
12 | KBNvKB.rtbw: cd1d6adb575089e853b306d110de5173
13 | KBNvKN.rtbw: d5020ca24fe16a568b5cf70d69565366
14 | KBNvKP.rtbw: f67e12f3d62a5ac094e635d562a9a84d
15 | KBNvKQ.rtbw: 2ec5a10d3bd99d8d11920b1331df254e
16 | KBNvKR.rtbw: e0129148383c5f95e631b7758a22162c
17 | KBNvK.rtbw: 046312caaebd34f798e1a112c1a79208
18 | KBPPvK.rtbw: f1a46f13fc1bdc0c4f453bcc996ea811
19 | KBPvKB.rtbw: 9dab7c4c323d18523e2da51cba30aa49
20 | KBPvKN.rtbw: 28415af3f800b2857b3edd84542a9922
21 | KBPvKP.rtbw: 9d66971b0a1a598cd65e04268dc622f3
22 | KBPvKQ.rtbw: 73800c70a614bfe60f57d18bd1d77808
23 | KBPvKR.rtbw: 460c6ff0d6a18cdb76586d434460193a
24 | KBPvK.rtbw: 080d6f2484c00d0ae161909f86e49684
25 | KBvKB.rtbw: cbcf6c04bc042c6dfb2c2d2ebf1af073
26 | KBvKN.rtbw: e83441cecee257c97a12b5ad33be16fd
27 | KBvKP.rtbw: 47f54e30a61705aab5b2a6cd577c2c1e
28 | KBvK.rtbw: 4b37ef623e69eadb6756777c16034e6f
29 | KNNNvK.rtbw: d79465eca6697da78997320da531fabb
30 | KNNPvK.rtbw: 252f89f33bacc96d51c6bfc951d1157a
31 | KNNvKB.rtbw: 0a98fb4f58b773d1fb6ef8a48cecda89
32 | KNNvKN.rtbw: feaf420ff86398b6049e972c1ed27bf0
33 | KNNvKP.rtbw: b2ad4c6c257cd7f90ac5c2545ec083ec
34 | KNNvKQ.rtbw: 3d1b6dc34ea6380e9efc18cd13ab752a
35 | KNNvKR.rtbw: 6231eac2d4ddcfce370d384e8bd7af14
36 | KNNvK.rtbw: 55ace050bca06a89fb262b1471653da3
37 | KNPPvK.rtbw: b5600e730d1c243178d635fb0434d174
38 | KNPvKB.rtbw: bac540b324c49fada2be5b6aa5c8f722
39 | KNPvKN.rtbw: 3f57d5be4bab20026be22ed2f3f57296
40 | KNPvKP.rtbw: 05d00d8934c19354e449e62180dc83aa
41 | KNPvKQ.rtbw: 17da8e4f62c446341883c46a3ee3cdfb
42 | KNPvKR.rtbw: f2bcbd21959d515559c1bfab9fe6867b
43 | KNPvK.rtbw: 20690936ac6147bd4d8aa0584b5ae570
44 | KNvKN.rtbw: 2c4a1fbe4cc50a112a60628c6092f5b7
45 | KNvKP.rtbw: 083853c1df58dbfa035231fe93f572be
46 | KNvK.rtbw: b9eccbff19c677158e928b1b641248b7
47 | KPPPvK.rtbw: d8e30143a16cd3358293ba3963df546b
48 | KPPvKB.rtbw: 20b644468517fbfe6937e446289c578d
49 | KPPvKN.rtbw: 1420882e55063ed51b951047229b9105
50 | KPPvKP.rtbw: 07554169bb42f4aa37779aff765c98da
51 | KPPvKQ.rtbw: 767d9d91dbdd47d90426699e56562b79
52 | KPPvKR.rtbw: 15e1247d764296636faff1c9bcae729b
53 | KPPvK.rtbw: d60773ec35afacea512cfef89aab439b
54 | KPvKP.rtbw: 5862ab22bb995b8462651a536c9938e0
55 | KPvK.rtbw: 7e72bcffff0fc0fa6928728e92d3f652
56 | KQBBvK.rtbw: e0d379b9c3f7acab2357706abdbc1a5d
57 | KQBNvK.rtbw: d271f2e3184f1a208572dce771c6f3dc
58 | KQBPvK.rtbw: 0ed9d5f02fca6830dff0e3e5bbcd806d
59 | KQBvKB.rtbw: e603347f05b5cdd6eb5c72914ab799a9
60 | KQBvKN.rtbw: a0096730eab1b5c72270459c423400c9
61 | KQBvKP.rtbw: 5423eb4db831200cd341689a54378476
62 | KQBvKQ.rtbw: 2fdb3d39f55bf2037aaac4d386acf227
63 | KQBvKR.rtbw: 12683b1470398a8592c713de9c2fd064
64 | KQBvK.rtbw: f6286f9cf996cfe4987b28eadbf73cf0
65 | KQNNvK.rtbw: 47a080d6a4d7c256e97b9924df0c2897
66 | KQNPvK.rtbw: 07bd200e02fd1b0ed0660f54e6fd77a3
67 | KQNvKB.rtbw: 44e7932ad5711f39dd8901da9f8fbece
68 | KQNvKN.rtbw: 51ab8a6d96cb49dea6d82f16c6956ffc
69 | KQNvKP.rtbw: d4b988255b6bac0700e0243526701f69
70 | KQNvKQ.rtbw: b4df34c0cbea62a81d7dd29d71471049
71 | KQNvKR.rtbw: 4927b35fb9291cfd47764e0abb4c8746
72 | KQNvK.rtbw: 23586c56d3c0936b0907b6c10037c991
73 | KQPPvK.rtbw: c9c9d802e2493ec59d99789d40a82a1c
74 | KQPvKB.rtbw: 8fc1303227589cf4fb3910723ddb5c5a
75 | KQPvKN.rtbw: 6ba9b28d40d2cd4278231fe8e491369d
76 | KQPvKP.rtbw: 023e995507431d8d4b4297f5d80f5a65
77 | KQPvKQ.rtbw: 339bfad60f4f0e3739d40d0db4e216a1
78 | KQPvKR.rtbw: fc6274cb1a0f40bd241cf1c1b172b9df
79 | KQPvK.rtbw: d048a1892d608582fe41910a30aee226
80 | KQQBvK.rtbw: 8287520ac70067445c7d90532c5c7ce4
81 | KQQNvK.rtbw: 46a3727484d2d53355cb0f9c3a4bdb9f
82 | KQQPvK.rtbw: d62278816974f77b9cb8c6fc6e2a3a0c
83 | KQQQvK.rtbw: 7237e304f79d8c1bfe788fc3fb7342f8
84 | KQQRvK.rtbw: e8a14b36b0569aba2bd338a52eab2f49
85 | KQQvKB.rtbw: 7a8c5dd524ae329375cd28a4d6aac49a
86 | KQQvKN.rtbw: 759f5b2b22cb1b3158ce134f25787ed1
87 | KQQvKP.rtbw: 14564d216da2fbcf1512373ab890c2c3
88 | KQQvKQ.rtbw: 5c437d52c07aa3812e3078793baec738
89 | KQQvKR.rtbw: 9ea8d8bdfe7bd6ff8c14d9c8193f35d2
90 | KQQvK.rtbw: a76adeac6e2317a1cac7f683f22d5a0b
91 | KQRBvK.rtbw: 35daa17904dca38d7c794d6f0461025c
92 | KQRNvK.rtbw: c328e103836246928d6fef2c28bf1aab
93 | KQRPvK.rtbw: 04d83759a1026eac3cb3cf8ec899fd36
94 | KQRRvK.rtbw: 10e3e259c09b66b48dce634d6af80832
95 | KQRvKB.rtbw: f586707360fc7ea2a9271990c17d474d
96 | KQRvKN.rtbw: b3618e6fd1cdb418a62a88fc722f20b4
97 | KQRvKP.rtbw: 110fd7b4ad872e96a008ac97bb7c4fe1
98 | KQRvKQ.rtbw: d84e64e4795cb492ee794127e95ddb93
99 | KQRvKR.rtbw: c92f6db50c3dae81c8e1c227131e208c
100 | KQRvK.rtbw: c44670b6146a4dc2c08acb47e49b2ed1
101 | KQvKB.rtbw: 67814033b8dfbb2d1763e477f9e735ce
102 | KQvKN.rtbw: d70c73199e5966591d673d5a6fea7552
103 | KQvKP.rtbw: 7cbb934c70e3ebab255199dc68c96690
104 | KQvKQ.rtbw: bef44c115ac8cc8b1cb8292b021c62dd
105 | KQvKR.rtbw: a559e2154b6f9d4f21597fc3e20c36b2
106 | KQvK.rtbw: af0d561da4523cb21a8cf05e9bc5cc6e
107 | KRBBvK.rtbw: 69f86982b070543d4e5dd3f7721ffc13
108 | KRBNvK.rtbw: 926b5d99bc6987d97dc951a26a8c24bd
109 | KRBPvK.rtbw: 49733d63b5fbdf90bb0a7d066f6d724e
110 | KRBvKB.rtbw: b7b549ab560d0683d6940b31dc2eca06
111 | KRBvKN.rtbw: 31eb8255d13db666295a0853fec73f2f
112 | KRBvKP.rtbw: 7d7e545b3a3c3728912a5644a60cf801
113 | KRBvKQ.rtbw: a78865b5d54d0f1012de47ba06113090
114 | KRBvKR.rtbw: c94340e54cd7f53125d46fd199fbeac1
115 | KRBvK.rtbw: f79e38334bf75a20abbf940ec65ba63c
116 | KRNNvK.rtbw: 3afcabf83c525ab4d664959938108559
117 | KRNPvK.rtbw: 2b0cc20a4912752e05ff78cf81e2c61c
118 | KRNvKB.rtbw: 068c4a45f71e12a845111816ebf4bfcb
119 | KRNvKN.rtbw: 9828e7cb6355be1c5c0dd534f21d1b61
120 | KRNvKP.rtbw: ea57cc946dbab01c814ac55f3164a97e
121 | KRNvKQ.rtbw: c9cab5c2bb9fd428b8982d091cad9900
122 | KRNvKR.rtbw: 624257762a14b51847e8c14fd6bbd8f4
123 | KRNvK.rtbw: db1301ac142efac26d3cffa550325c27
124 | KRPPvK.rtbw: 7d1112a58006a1256b978a2bb6cb5f68
125 | KRPvKB.rtbw: 1b33d7fa0204c04198533498fd9a6b30
126 | KRPvKN.rtbw: f9e616a1ed7857f3e37097f418ff332a
127 | KRPvKP.rtbw: 88acfd00293fa0b585fe95654ac6cb04
128 | KRPvKQ.rtbw: 0ab5eb70732dd0a7832372b8e9d8d97d
129 | KRPvKR.rtbw: 128467234e544d83dd0e3057058e2ea3
130 | KRPvK.rtbw: 569ce2d76171513ddaa1f749d081c994
131 | KRRBvK.rtbw: 0968f65dcad88c8546d56ba00b49e6e2
132 | KRRNvK.rtbw: 3694eb78451545ebab5c4aab4b5eaf52
133 | KRRPvK.rtbw: 9b6a4283f7310eba27f17146f0a1f3cd
134 | KRRRvK.rtbw: 623028d0956fa8fbd2dc07618f4e12e6
135 | KRRvKB.rtbw: 3ea9948843579e8cafcca081865be99a
136 | KRRvKN.rtbw: 1c5b0736dacf95bc6b920104110261ab
137 | KRRvKP.rtbw: 6954568f6a22244b5f186f41998be95c
138 | KRRvKQ.rtbw: dd8810a987fe4dcbe8456cc72f84eaec
139 | KRRvKR.rtbw: 14428b45668f3bdb7facce3a9d866c74
140 | KRRvK.rtbw: 6084d485d555eb716d0fb1b3860d0282
141 | KRvKB.rtbw: 751112b5b8e4d7a2c1dd8a7e437c9d53
142 | KRvKN.rtbw: 50aeaaf346a237d8be48b18c186bac1e
143 | KRvKP.rtbw: ef10001a306b8f226db23b296b2b4d4b
144 | KRvKR.rtbw: 7d73b0fd3cbd4490510c2c229eee3b8d
145 | KRvK.rtbw: 81da63fe25b9ed66f459001558f83ca5
146 |
--------------------------------------------------------------------------------
/interface/main.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | Stockfish, a UCI chess playing engine derived from Glaurung 2.1
3 | Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
4 | Copyright (C) 2008-2013 Marco Costalba, Joona Kiiski, Tord Romstad
5 |
6 | Stockfish is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | Stockfish is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | #include
21 | #include
22 |
23 | #include "bitboard.h"
24 | #include "evaluate.h"
25 | #include "position.h"
26 | #include "search.h"
27 | #include "thread.h"
28 | #include "tt.h"
29 | #include "ucioption.h"
30 |
31 | // TB
32 | #include "tbprobe.h"
33 |
34 | int main(int argc, char* argv[]) {
35 |
36 | std::cout << engine_info() << std::endl;
37 |
38 | UCI::init(Options);
39 | Bitboards::init();
40 | Zobrist::init();
41 | Bitbases::init_kpk();
42 | Search::init();
43 | Eval::init();
44 | Threads.init();
45 | TT.set_size(Options["Hash"]);
46 |
47 | // TB
48 | init_tablebases();
49 |
50 | std::string args;
51 |
52 | for (int i = 1; i < argc; i++)
53 | args += std::string(argv[i]) + " ";
54 |
55 | UCI::loop(args);
56 |
57 | Threads.exit();
58 | }
59 |
--------------------------------------------------------------------------------
/interface/tbcore.h:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2011-2015 Ronald de Man
3 | */
4 |
5 | #ifndef TBCORE_H
6 | #define TBCORE_H
7 |
8 | #ifndef __WIN32__
9 | #include
10 | #define SEP_CHAR ':'
11 | #define FD int
12 | #define FD_ERR -1
13 | #else
14 | #include
15 | #define SEP_CHAR ';'
16 | #define FD HANDLE
17 | #define FD_ERR INVALID_HANDLE_VALUE
18 | #endif
19 |
20 | #ifndef __WIN32__
21 | #define LOCK_T pthread_mutex_t
22 | #define LOCK_INIT(x) pthread_mutex_init(&(x), NULL)
23 | #define LOCK_DESTROY(x) pthread_mutex_destroy(&(x))
24 | #define LOCK(x) pthread_mutex_lock(&(x))
25 | #define UNLOCK(x) pthread_mutex_unlock(&(x))
26 | #else
27 | #define LOCK_T HANDLE
28 | #define LOCK_INIT(x) do { x = CreateMutex(NULL, FALSE, NULL); } while (0)
29 | #define LOCK_DESTROY(x) CloseHandle(x)
30 | #define LOCK(x) WaitForSingleObject(x, INFINITE)
31 | #define UNLOCK(x) ReleaseMutex(x)
32 | #endif
33 |
34 | #define WDLSUFFIX ".rtbw"
35 | #define DTZSUFFIX ".rtbz"
36 | #define WDLDIR "RTBWDIR"
37 | #define DTZDIR "RTBZDIR"
38 | #define TBPIECES 6
39 |
40 | #define WDL_MAGIC 0x5d23e871
41 | #define DTZ_MAGIC 0xa50c66d7
42 |
43 | #define TBHASHBITS 10
44 |
45 | typedef unsigned long long uint64;
46 | typedef unsigned int uint32;
47 | typedef unsigned char ubyte;
48 | typedef unsigned short ushort;
49 |
50 | struct TBHashEntry;
51 |
52 | #ifdef DECOMP64
53 | typedef uint64 base_t;
54 | #else
55 | typedef uint32 base_t;
56 | #endif
57 |
58 | struct PairsData {
59 | char *indextable;
60 | ushort *sizetable;
61 | ubyte *data;
62 | ushort *offset;
63 | ubyte *symlen;
64 | ubyte *sympat;
65 | int blocksize;
66 | int idxbits;
67 | int min_len;
68 | base_t base[1]; // C++ complains about base[]...
69 | };
70 |
71 | struct TBEntry {
72 | char *data;
73 | uint64 key;
74 | uint64 mapping;
75 | ubyte ready;
76 | ubyte num;
77 | ubyte symmetric;
78 | ubyte has_pawns;
79 | } __attribute__((__may_alias__));
80 |
81 | struct TBEntry_piece {
82 | char *data;
83 | uint64 key;
84 | uint64 mapping;
85 | ubyte ready;
86 | ubyte num;
87 | ubyte symmetric;
88 | ubyte has_pawns;
89 | ubyte enc_type;
90 | struct PairsData *precomp[2];
91 | int factor[2][TBPIECES];
92 | ubyte pieces[2][TBPIECES];
93 | ubyte norm[2][TBPIECES];
94 | };
95 |
96 | struct TBEntry_pawn {
97 | char *data;
98 | uint64 key;
99 | uint64 mapping;
100 | ubyte ready;
101 | ubyte num;
102 | ubyte symmetric;
103 | ubyte has_pawns;
104 | ubyte pawns[2];
105 | struct {
106 | struct PairsData *precomp[2];
107 | int factor[2][TBPIECES];
108 | ubyte pieces[2][TBPIECES];
109 | ubyte norm[2][TBPIECES];
110 | } file[4];
111 | };
112 |
113 | struct DTZEntry_piece {
114 | char *data;
115 | uint64 key;
116 | uint64 mapping;
117 | ubyte ready;
118 | ubyte num;
119 | ubyte symmetric;
120 | ubyte has_pawns;
121 | ubyte enc_type;
122 | struct PairsData *precomp;
123 | int factor[TBPIECES];
124 | ubyte pieces[TBPIECES];
125 | ubyte norm[TBPIECES];
126 | ubyte flags; // accurate, mapped, side
127 | ushort map_idx[4];
128 | ubyte *map;
129 | };
130 |
131 | struct DTZEntry_pawn {
132 | char *data;
133 | uint64 key;
134 | uint64 mapping;
135 | ubyte ready;
136 | ubyte num;
137 | ubyte symmetric;
138 | ubyte has_pawns;
139 | ubyte pawns[2];
140 | struct {
141 | struct PairsData *precomp;
142 | int factor[TBPIECES];
143 | ubyte pieces[TBPIECES];
144 | ubyte norm[TBPIECES];
145 | } file[4];
146 | ubyte flags[4];
147 | ushort map_idx[4][4];
148 | ubyte *map;
149 | };
150 |
151 | struct TBHashEntry {
152 | uint64 key;
153 | struct TBEntry *ptr;
154 | };
155 |
156 | struct DTZTableEntry {
157 | uint64 key1;
158 | uint64 key2;
159 | struct TBEntry *entry;
160 | };
161 |
162 | #endif
163 |
164 |
--------------------------------------------------------------------------------
/interface/tbprobe.h:
--------------------------------------------------------------------------------
1 | #ifndef TBPROBE_H
2 | #define TBPROBE_H
3 |
4 | extern int TBlargest; // 5 if 5-piece tables, 6 if 6-piece tables were found.
5 |
6 | void init_tablebases(char *path);
7 | int probe_wdl(Position& pos, int *success);
8 | int probe_dtz(Position& pos, int *success);
9 | int root_probe(Position& pos, Value& TBScore);
10 | int root_probe_wdl(Position& pos, Value& TBScore);
11 |
12 | #endif
13 |
14 |
--------------------------------------------------------------------------------
/src/Makefile:
--------------------------------------------------------------------------------
1 | # Specify sliding attacks generation method. One of -DMAGIC, -DHYPER, -DBMI2.
2 | # -DBMI2 only works on Haswell processors.
3 | # -DHYPER requires a processor with SSE3 support.
4 | # -DMAGIC and -DHYPER are about equally fast on my system.
5 | FLAGS = -DMAGIC
6 | #FLAGS = -DHYPER
7 | #FLAGS = -DBMI2
8 |
9 | # Specify -DUSE_POPCNT on a machine with popcnt support.
10 | # For pawnful tables this seems slightly faster. For pawnless tables it
11 | # does not seem to matter.
12 | FLAGS += -DUSE_POPCNT
13 |
14 | # Specify maximum number of pieces. More than 7 won't work.
15 | FLAGS += -DTBPIECES=7
16 |
17 | # Use libzstd instead of LZ4 for compression of temporary files.
18 | FLAGS += -DUSE_ZSTD
19 | LDFLAGS += -lzstd
20 |
21 | # Specify number of threads used for compression of temporary files.
22 | FLAGS += -DCOMPRESSION_THREADS=6
23 |
24 | # Specify the compiler
25 | # regular linux
26 | #CC = /usr/bin/gcc -pthread
27 | CC = gcc -pthread
28 | # cross compiling from Linux to Windows
29 | #CC = x86_64-w64-mingw32-gcc
30 |
31 | # Compilation flags
32 | # For Haswell add -mbmi2 and select -DBMI2 above.
33 | #CFLAGS = -g -march=native -pipe -D_GNU_SOURCE -Wall -std=c11 -Wno-array-bounds
34 | CFLAGS = -O3 -march=native -pipe -D_GNU_SOURCE -Wall -std=c11 -Wno-array-bounds -flto=auto
35 | #CFLAGS = -O3 -march=native -pipe -D_GNU_SOURCE -Wall -std=c11 -fsanitize=undefined -Wno-array-bounds
36 |
37 | export FLAGS CC CFLAGS LDFLAGS
38 |
39 | all: rtbgen rtbgenp rtbver rtbverp tbcheck
40 |
41 | rtbgen rtbgenp rtbver rtbverp tbcheck clean:
42 | @$(MAKE) -f Makefile.regular $@
43 |
44 | atbgen atbgenp atbver atbverp aclean:
45 | @$(MAKE) -f Makefile.atomic $@
46 |
47 | stbgen stbgenp sclean:
48 | @$(MAKE) -f Makefile.suicide $@
49 |
50 | gtbgen gtbgenp gclean:
51 | @$(MAKE) -f Makefile.giveaway $@
52 |
53 | jtbgen jtbgenp jclean:
54 | @$(MAKE) -f Makefile.shatranj $@
55 |
56 | #atbgen atbgenp atbver atbverp aclean:
57 | atomic: atbgen atbgenp atbver atbverp tbcheck
58 |
59 | suicide: stbgen stbgenp tbcheck
60 |
61 | giveaway: gtbgen gtbgenp tbcheck
62 |
63 | shatranj: jtbgen jtbgenp tbcheck
64 |
65 | .PHONY: rtbgen rtbgenp rtbver rtbverp tbcheck clean \
66 | atbgen atbgenp atbver atbverp aclean \
67 | stbgen stbgenp sclean \
68 | gtbgen gtbgenp gclean \
69 | jtbgen jtbgenp jclean
70 |
--------------------------------------------------------------------------------
/src/Makefile.atomic:
--------------------------------------------------------------------------------
1 | GENTBNAME = atbgen
2 | GENTBPNAME = atbgenp
3 | VERTBNAME = atbver
4 | VERTBPNAME = atbverp
5 | CLEAN = aclean
6 |
7 | DEPDIR = .depsa
8 | OBJDIR = objsa
9 |
10 | FLAGS += -DATOMIC
11 |
12 | include Makefile.general
13 |
14 |
--------------------------------------------------------------------------------
/src/Makefile.general:
--------------------------------------------------------------------------------
1 | SHELL = /bin/sh
2 |
3 | .SUFFIXES:
4 | .SUFFIXES: .c .o .P
5 |
6 | vpath %.o
7 | vpath %.o $(OBJDIR)
8 |
9 | vpath %.P
10 | vpath %.P $(DEPDIR)
11 |
12 | TBOBJS = tbgen.o tbgenp.o permute.o compress.o huffman.o threads.o lz4.o tbver.o tbverp.o decompress.o checksum.o city-c.o tbcheck.o util.o
13 | GENTBOBJS = tbgen.o permute.o compress.o huffman.o threads.o lz4.o checksum.o city-c.o util.o
14 | GENTBPOBJS = tbgenp.o permute.o compress.o huffman.o threads.o lz4.o checksum.o city-c.o util.o
15 | VERTBOBJS = tbver.o decompress.o threads.o checksum.o city-c.o util.o
16 | VERTBPOBJS = tbverp.o decompress.o threads.o checksum.o city-c.o util.o
17 |
18 | TBCHECKOBJS = tbcheck.o threads.o checksum.o city-c.o util.o
19 |
20 | CFILES = $(filter $(wildcard *.c), $(OBJS:%.o=%.c))
21 |
22 | include $(CFILES:%.c=$(DEPDIR)/%.P)
23 | include $(TBOBJS:%.o=$(DEPDIR)/%.P)
24 |
25 | $(NAME): $(OBJS) # $(OBJS:%=$(OBJDIR)/%)
26 | $(CC) $(CFLAGS) -o $(NAME) $(OBJS:%=$(OBJDIR)/%)
27 |
28 | %.o $(OBJDIR)/%.o: %.c
29 | @mkdir -p $(OBJDIR)
30 | $(CC) $(CFLAGS) -c $*.c $(FLAGS) -o $(OBJDIR)/$*.o
31 |
32 | $(DEPDIR)/%.P: %.c
33 | @mkdir -p $(DEPDIR)
34 | $(SHELL) -ec '$(CC) -M $(FLAGS) -msse4.2 -march=corei7 $*.c \
35 | | sed s/$*\.o/$*\.o\ $*\.P/ >$@'
36 |
37 | $(CLEAN):
38 | rm -f $(TBOBJS:%=$(OBJDIR)/%)
39 |
40 | $(GENTBNAME): $(GENTBOBJS)
41 | $(CC) $(CFLAGS) -o $(GENTBNAME) $(GENTBOBJS:%=$(OBJDIR)/%) $(LDFLAGS)
42 |
43 | $(GENTBPNAME): $(GENTBPOBJS)
44 | $(CC) $(CFLAGS) -o $(GENTBPNAME) $(GENTBPOBJS:%=$(OBJDIR)/%) $(LDFLAGS)
45 |
46 | $(VERTBNAME): $(VERTBOBJS)
47 | $(CC) $(CFLAGS) -o $(VERTBNAME) $(VERTBOBJS:%=$(OBJDIR)/%) $(LDFLAGS)
48 |
49 | $(VERTBPNAME): $(VERTBPOBJS)
50 | $(CC) $(CFLAGS) -o $(VERTBPNAME) $(VERTBPOBJS:%=$(OBJDIR)/%) $(LDFLAGS)
51 |
52 | tbcheck: $(TBCHECKOBJS)
53 | $(CC) $(CFLAGS) -o tbcheck $(TBCHECKOBJS:%=$(OBJDIR)/%)
54 |
55 |
--------------------------------------------------------------------------------
/src/Makefile.giveaway:
--------------------------------------------------------------------------------
1 | GENTBNAME = gtbgen
2 | GENTBPNAME = gtbgenp
3 | VERTBNAME = gtbver
4 | VERTBPNAME = gtbverp
5 | CLEAN = gclean
6 |
7 | DEPDIR = .depsg
8 | OBJDIR = objsg
9 |
10 | FLAGS += -DGIVEAWAY
11 |
12 | include Makefile.general
13 |
14 |
--------------------------------------------------------------------------------
/src/Makefile.regular:
--------------------------------------------------------------------------------
1 | GENTBNAME = rtbgen
2 | GENTBPNAME = rtbgenp
3 | VERTBNAME = rtbver
4 | VERTBPNAME = rtbverp
5 | CLEAN = clean
6 |
7 | DEPDIR = .depsr
8 | OBJDIR = objsr
9 |
10 | FLAGS += -DREGULAR
11 |
12 | include Makefile.general
13 |
14 |
--------------------------------------------------------------------------------
/src/Makefile.shatranj:
--------------------------------------------------------------------------------
1 | GENTBNAME = jtbgen
2 | GENTBPNAME = jtbgenp
3 | VERTBNAME = jtbver
4 | VERTBPNAME = jtbverp
5 | CLEAN = jclean
6 |
7 | DEPDIR = .depsj
8 | OBJDIR = objsj
9 |
10 | FLAGS += -DSHATRANJ
11 |
12 | include Makefile.general
13 |
14 |
--------------------------------------------------------------------------------
/src/Makefile.suicide:
--------------------------------------------------------------------------------
1 | GENTBNAME = stbgen
2 | GENTBPNAME = stbgenp
3 | VERTBNAME = stbver
4 | VERTBPNAME = stbverp
5 | CLEAN = sclean
6 |
7 | DEPDIR = .depss
8 | OBJDIR = objss
9 |
10 | FLAGS += -DSUICIDE
11 |
12 | include Makefile.general
13 |
14 |
--------------------------------------------------------------------------------
/src/bmi2.c:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2013 Ronald de Man
3 |
4 | This file is distributed under the terms of the GNU GPL, version 2.
5 | */
6 |
7 | /* to be included in board.c */
8 |
9 | #ifdef BMI2
10 |
11 | static uint16_t attacks_table[107648];
12 | struct BMI2Info bishop_bmi2[64];
13 | struct BMI2Info rook_bmi2[64];
14 |
15 | static signed char m_bishop_dir[4][2] = {
16 | { -9, -17 }, { -7, -15 }, { 7, 15 }, { 9, 17 }
17 | };
18 |
19 | static signed char m_rook_dir[4][2] = {
20 | { -8, -16 }, { -1, -1 }, { 1, 1}, { 8, 16 }
21 | };
22 |
23 | static int init_bmi2(struct BMI2Info *info, signed char dir[][2], int idx)
24 | {
25 | int sq, sq88;
26 | int i, j, d, num;
27 | bitboard bb, bb2;
28 | int squares[12];
29 |
30 | for (sq = 0; sq < 64; sq++) {
31 | info[sq].data = &attacks_table[idx];
32 |
33 | // calculate mask
34 | sq88 = sq + (sq & ~7);
35 | bb = 0;
36 | for (i = 0; i < 4; i++) {
37 | if ((sq88 + dir[i][1]) & 0x88) continue;
38 | for (d = 2; !((sq88 + d * dir[i][1]) & 0x88); d++)
39 | bb |= bit[sq + (d - 1) * dir[i][0]];
40 | }
41 | info[sq].mask1 = bb;
42 |
43 | num = 0;
44 | while (bb) {
45 | squares[num++] = FirstOne(bb);
46 | ClearFirst(bb);
47 | }
48 |
49 | // loop through all possible occupations within the mask
50 | // and calculate the corresponding attack sets
51 | for (i = 0; i < (1 << num); i++) {
52 | bb = 0;
53 | for (j = 0; j < num; j++)
54 | if (i & (1 << j))
55 | bb |= bit[squares[j]];
56 | bb2 = 0;
57 | for (j = 0; j < 4; j++) {
58 | for (d = 1; !((sq88 + d * dir[j][1]) & 0x88); d++) {
59 | bb2 |= bit[sq + d * dir[j][0]];
60 | if (bb & bit[sq + d * dir[j][0]]) break;
61 | }
62 | }
63 | if (i == 0)
64 | info[sq].mask2 = bb2;
65 | attacks_table[idx++] = _pext_u64(bb2, info[sq].mask2);
66 | }
67 | }
68 |
69 | return idx;
70 | }
71 |
72 | void set_up_move_gen(void)
73 | {
74 | int i;
75 |
76 | for (i = 0; i < 97264; i++)
77 | attacks_table[i] = 0ULL;
78 | i = init_bmi2(bishop_bmi2, m_bishop_dir, 0);
79 | init_bmi2(rook_bmi2, m_rook_dir, i);
80 | }
81 |
82 | #endif
83 |
84 |
--------------------------------------------------------------------------------
/src/bmi2.h:
--------------------------------------------------------------------------------
1 | #ifndef BMI2_H
2 | #define BMI2_H
3 |
4 | #ifdef BMI2
5 |
6 | #include
7 |
8 | // implementations of _pext_u64 and _pdep_u64 for testing
9 | #if 0
10 | static uint64_t _pext_u64(uint64_t val, uint64_t mask)
11 | {
12 | uint64_t res = 0;
13 | int i = 0;
14 |
15 | while (mask) {
16 | if (val & mask & -mask)
17 | res |= bit[i];
18 | mask &= mask - 1;
19 | i++;
20 | }
21 |
22 | return res;
23 | }
24 |
25 | static uint64_t _pdep_u64(uint64_t val, uint64_t mask)
26 | {
27 | uint64_t res = 0;
28 | int i = 0;
29 |
30 | while (mask) {
31 | if (val & bit[i++])
32 | res |= mask & -mask;
33 | mask &= mask - 1;
34 | }
35 |
36 | return res;
37 | }
38 | #endif
39 |
40 | struct BMI2Info {
41 | uint16_t *data;
42 | bitboard mask1;
43 | bitboard mask2;
44 | };
45 |
46 | extern uint16_t attack_table[107648];
47 | extern struct BMI2Info bishop_bmi2[64];
48 | extern struct BMI2Info rook_bmi2[64];
49 |
50 | static __inline__ bitboard BishopRange(int sq, bitboard occ)
51 | {
52 | struct BMI2Info *info = &bishop_bmi2[sq];
53 | return _pdep_u64(info->data[_pext_u64(occ, info->mask1)], info->mask2);
54 | }
55 |
56 | static __inline__ bitboard RookRange(int sq, bitboard occ)
57 | {
58 | struct BMI2Info *info = &rook_bmi2[sq];
59 | return _pdep_u64(info->data[_pext_u64(occ, info->mask1)], info->mask2);
60 | }
61 |
62 | #define QueenRange(sq,occ) (BishopRange(sq,occ)|RookRange(sq,occ))
63 |
64 | #endif
65 |
66 | #endif
67 |
--------------------------------------------------------------------------------
/src/board.c:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2011-2013 Ronald de Man
3 |
4 | This file is distributed under the terms of the GNU GPL, version 2.
5 | */
6 |
7 | #include "board.h"
8 | #include "magic.c"
9 | #include "hyper.c"
10 | #include "bmi2.c"
11 |
12 | #define MAX_PIECES 8
13 |
14 | bitboard bit[64];
15 | bitboard knight_range[64], king_range[64];
16 | #ifdef SHATRANJ
17 | bitboard bishop_range[64], queen_range[64];
18 | #endif
19 | #ifdef HAS_PAWNS
20 | bitboard pawn_range[2][64];
21 | bitboard sides_mask[64];
22 | #endif
23 |
24 | #ifdef ATOMIC
25 | bitboard atom_mask[64];
26 | #endif
27 |
28 | void set_up_tables(void)
29 | {
30 | int i, sq;
31 | int x, y;
32 |
33 | bitboard bits;
34 |
35 | static int Nx[] = {1, 2, 2, 1, -1, -2, -2, -1},
36 | Ny[] = {2, 1, -1, -2, -2, -1, 1, 2},
37 | Kx[] = {-1, 0, 1, 1, 1, 0, -1, -1},
38 | Ky[] = {1, 1, 1, 0, -1, -1, -1, 0};
39 |
40 | #ifdef SHATRANJ
41 | static int Bx[] = {2, 2, -2, -2},
42 | By[] = {2, -2, 2, -2},
43 | Qx[] = {1, 1, -1, -1},
44 | Qy[] = {1, -1, 1, -1};
45 | #endif
46 |
47 | for (sq = 0; sq < 64; sq++)
48 | bit[sq] = 1ULL << sq;
49 |
50 | for (sq = 0; sq < 64; sq++) {
51 | x = sq & 7;
52 | y = sq >> 3;
53 |
54 | #ifdef HAS_PAWNS
55 | bits = 0;
56 | if (y < 7) {
57 | if (x > 0) bits |= bit[sq + 7];
58 | if (x < 7) bits |= bit[sq + 9];
59 | }
60 | white_pawn_range[sq] = bits;
61 |
62 | bits = 0;
63 | if (y > 0) {
64 | if (x > 0) bits |= bit[sq - 9];
65 | if (x < 7) bits |= bit[sq - 7];
66 | }
67 | black_pawn_range[sq] = bits;
68 |
69 | bits = 0;
70 | if (x > 0) bits |= bit[sq - 1];
71 | if (x < 7) bits |= bit[sq + 1];
72 | sides_mask[sq] = bits;
73 | #endif
74 |
75 | bits = 0;
76 | for (i = 0; i < 8; i++)
77 | if (x + Nx[i] >= 0 && x + Nx[i] < 8 && y + Ny[i] >= 0 && y + Ny[i] < 8)
78 | bits |= bit[x + Nx[i] + 8 * (y + Ny[i])];
79 | knight_range[sq] = bits;
80 |
81 | bits = 0;
82 | for (i = 0; i < 8; i++)
83 | if (x + Kx[i] >= 0 && x + Kx[i] < 8 && y + Ky[i] >= 0 && y + Ky[i] < 8)
84 | bits |= bit[x + Kx[i] + 8 * (y + Ky[i])];
85 | king_range[sq] = bits;
86 |
87 | #ifdef SHATRANJ
88 | bits = 0;
89 | for (i = 0; i < 4; i++)
90 | if (x + Bx[i] >= 0 && x + Bx[i] < 8 && y + By[i] >= 0 && y + By[i] < 8)
91 | bits |= bit[x + Bx[i] + 8 * (y + By[i])];
92 | bishop_range[sq] = bits;
93 |
94 | bits = 0;
95 | for (i = 0; i < 4; i++)
96 | if (x + Qx[i] >= 0 && x + Qx[i] < 8 && y + Qy[i] >= 0 && y + Qy[i] < 8)
97 | bits |= bit[x + Qx[i] + 8 * (y + Qy[i])];
98 | queen_range[sq] = bits;
99 | #endif
100 |
101 | #ifdef ATOMIC
102 | atom_mask[sq] = bits | bit[sq];
103 | #endif
104 | }
105 |
106 | set_up_move_gen();
107 | }
108 |
--------------------------------------------------------------------------------
/src/board.h:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2011-2013 Ronald de Man
3 |
4 | This file is distributed under the terms of the GNU GPL, version 2.
5 | */
6 |
7 | #ifndef BOARD_BB_H
8 | #define BOARD_BB_H
9 |
10 | #include "defs.h"
11 | #include "types.h"
12 |
13 | extern bitboard bit[64];
14 |
15 | static __inline__ int FirstOne(bitboard x)
16 | {
17 | bitboard res;
18 | __asm__("bsfq %1, %0" : "=r" (res) : "g" (x));
19 | return (int)res;
20 | }
21 |
22 | #ifdef USE_POPCNT
23 | static __inline__ int PopCount(bitboard x)
24 | {
25 | bitboard res;
26 | __asm__("popcnt %1, %0" : "=r" (res) : "g" (x));
27 | return (int)res;
28 | }
29 | #endif
30 |
31 | #define ClearFirst(x) ((x)&=(x)-1)
32 |
33 | #include "magic.h"
34 | #include "hyper.h"
35 | #include "bmi2.h"
36 |
37 | extern bitboard knight_range[64], king_range[64];
38 | #ifdef SHATRANJ
39 | extern bitboard queen_range[64], bishop_range[64];
40 | #endif
41 | #ifdef HAS_PAWNS
42 | extern bitboard pawn_range[2][64];
43 | #define white_pawn_range pawn_range[0]
44 | #define black_pawn_range pawn_range[1]
45 | extern bitboard sides_mask[64];
46 | extern bitboard double_push_mask[16];
47 | #endif
48 |
49 | #ifdef ATOMIC
50 | extern bitboard atom_mask[64];
51 | #endif
52 |
53 | #define KnightRange(x) knight_range[x]
54 | #define KingRange(x) king_range[x]
55 | #ifdef SHATRANJ
56 | #undef QueenRange
57 | #define QueenRange(x,occ) queen_range[x]
58 | #undef BishopRange
59 | #define BishopRange(x,occ) bishop_range[x]
60 | #endif
61 |
62 | #define PAWN 1
63 | #define KNIGHT 2
64 | #define BISHOP 3
65 | #define ROOK 4
66 | #define QUEEN 5
67 | #define KING 6
68 |
69 | #define WPAWN 1
70 | #define WKNIGHT 2
71 | #define WBISHOP 3
72 | #define WROOK 4
73 | #define WQUEEN 5
74 | #define WKING 6
75 |
76 | #define BPAWN 9
77 | #define BKNIGHT 10
78 | #define BBISHOP 11
79 | #define BROOK 12
80 | #define BQUEEN 13
81 | #define BKING 14
82 |
83 | static __inline__ bitboard PieceRange(int sq, int type, bitboard occ)
84 | {
85 | switch (type & 0x07) {
86 | #ifdef HAS_PAWNS
87 | case PAWN:
88 | return pawn_range[(type & 0x08) >> 3][sq];
89 | #endif
90 | case KNIGHT:
91 | return KnightRange(sq);
92 | case BISHOP:
93 | return BishopRange(sq, occ);
94 | case ROOK:
95 | return RookRange(sq, occ);
96 | case QUEEN:
97 | return QueenRange(sq, occ);
98 | default:
99 | return KingRange(sq);
100 | }
101 | }
102 |
103 | static __inline__ bitboard PieceMoves(int sq, int type, bitboard occ)
104 | {
105 | return PieceRange(sq, type, occ) & ~occ;
106 | }
107 |
108 | // only used in rtbgenp / rtbverp
109 | static __inline__ bitboard PieceRange1(int sq, int type, bitboard occ)
110 | {
111 | switch (type & 0x07) {
112 | case KING:
113 | return KingRange(sq);
114 | case KNIGHT:
115 | return KnightRange(sq);
116 | case BISHOP:
117 | return BishopRange(sq, occ);
118 | case ROOK:
119 | return RookRange(sq, occ);
120 | case QUEEN:
121 | return QueenRange(sq, occ);
122 | default:
123 | assume(0);
124 | }
125 | }
126 |
127 | static __inline__ bitboard PieceMoves1(int sq, int type, bitboard occ)
128 | {
129 | return PieceRange1(sq, type, occ) & ~occ;
130 | }
131 |
132 | // only used in rtbgen / rtbver
133 | static __inline__ bitboard PieceRange2(int sq, int type, bitboard occ)
134 | {
135 | switch (type & 0x07) {
136 | case KNIGHT:
137 | return KnightRange(sq);
138 | case BISHOP:
139 | return BishopRange(sq, occ);
140 | case ROOK:
141 | return RookRange(sq, occ);
142 | case QUEEN:
143 | return QueenRange(sq, occ);
144 | default:
145 | assume(0);
146 | }
147 | }
148 |
149 | static __inline__ bitboard PieceMoves2(int sq, int type, bitboard occ)
150 | {
151 | return PieceRange2(sq, type, occ) & ~occ;
152 | }
153 |
154 | #endif
155 |
156 |
--------------------------------------------------------------------------------
/src/checksum.c:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2011-2013 Ronald de Man
3 |
4 | This file is distributed under the terms of the GNU GPL, version 2.
5 | */
6 |
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 |
15 | #include "defs.h"
16 | #include "checksum.h"
17 | #include "threads.h"
18 | #include "citycrc.h"
19 | #include "util.h"
20 |
21 | #define CHUNK (1ULL << 24)
22 |
23 | extern int total_work;
24 |
25 | static uint64_t checksum1[2];
26 | static uint64_t checksum2[2];
27 | static uint64_t *results = NULL;
28 | static uint8_t *data;
29 | static uint64_t size;
30 | static int checksum_found;
31 | static int checksum_match;
32 | static uint64_t *work = NULL;
33 |
34 | static void checksum_worker(struct thread_data *thread)
35 | {
36 | uint64_t idx;
37 | uint64_t end = thread->end;
38 |
39 | for (idx = thread->begin; idx < end; idx++) {
40 | uint64_t start = idx * CHUNK;
41 | uint64_t chunk = CHUNK;
42 | if (start + chunk > size)
43 | chunk = size - start;
44 | CityHashCrc256((char *)(data + start), chunk, &results[4 * idx]);
45 | }
46 | }
47 |
48 | static void calc_checksum(char *name)
49 | {
50 | uint64_t orig_size;
51 |
52 | if (!work) work = alloc_work(total_work);
53 |
54 | data = map_file(name, 0, &size);
55 | orig_size = size;
56 | if ((size & 0x3f) == 0x10) {
57 | size &= ~0x3fULL;
58 | memcpy(checksum1, data + size, 16);
59 | checksum_found = 1;
60 | } else {
61 | if (size & 0x3f) {
62 | fprintf(stderr, "Size of %s is not a multiple of 64.\n", name);
63 | exit(1);
64 | }
65 | checksum_found = 0;
66 | }
67 |
68 | int chunks = (size + CHUNK - 1) / CHUNK;
69 | results = (uint64_t *)malloc(32 * chunks);
70 | fill_work(total_work, chunks, 0, work);
71 | run_threaded(checksum_worker, work, 0);
72 | CityHashCrc128((char *)results, 32 * chunks, checksum2);
73 | unmap_file(data, orig_size);
74 | free(results);
75 |
76 | if (checksum_found)
77 | checksum_match = (checksum1[0] == checksum2[0]
78 | && checksum1[1] == checksum2[1]);
79 | }
80 |
81 | void print_checksum(char *name, char *sum)
82 | {
83 | data = map_file(name, 1, &size);
84 | if ((size & 0x3f) == 0x10) {
85 | memcpy(checksum1, data + (size & ~0x3fULL), 16);
86 | } else {
87 | fprintf(stderr, "No checksum found.\n");
88 | exit(1);
89 | }
90 | unmap_file(data, size);
91 |
92 | int i;
93 | static char nibble[16] = "0123456789abcdef";
94 | uint8_t *c = (uint8_t *)checksum1;
95 |
96 | for (i = 0; i < 16; i++) {
97 | uint8_t b = c[i];
98 | sum[2 * i] = nibble[b >> 4];
99 | sum[2 * i + 1] = nibble[b & 0x0f];
100 | }
101 | sum[32] = 0;
102 | }
103 |
104 | void add_checksum(char *name)
105 | {
106 | calc_checksum(name);
107 | if (checksum_found) {
108 | fprintf(stderr, "%s checksum already present.\n", checksum_match ? "Matching" : "Non-matching");
109 | exit(1);
110 | }
111 | FILE *F = fopen(name, "ab");
112 | if (!F) {
113 | fprintf(stderr, "Could not open %s for appending.\n", name);
114 | exit(1);
115 | }
116 | fwrite(checksum2, 16, 1, F);
117 | fclose(F);
118 | }
119 |
120 | void verify_checksum(char *name)
121 | {
122 | printf("%s: ", name);
123 | calc_checksum(name);
124 | if (!checksum_found) {
125 | fprintf(stderr, "No checksum present.\n");
126 | exit(1);
127 | }
128 | if (!checksum_match)
129 | printf("FAIL!\n");
130 | else
131 | printf("OK!\n");
132 | }
133 |
134 |
--------------------------------------------------------------------------------
/src/checksum.h:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2011-2013 Ronald de Man
3 |
4 | This file is distributed under the terms of the GNU GPL, version 2.
5 | */
6 |
7 | #ifndef CHECKSUM_H
8 | #define CHECKSUM_H
9 |
10 | void add_checksum(char *name);
11 | void verify_checksum(char *name);
12 | void print_checksum(char *name, char *sum);
13 |
14 | #endif
15 |
16 |
--------------------------------------------------------------------------------
/src/city-c.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2011 Google, Inc.
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in
11 | // all copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | // THE SOFTWARE.
20 | //
21 | // CityHash, by Geoff Pike and Jyrki Alakuijala
22 | //
23 | // This file provides a few functions for hashing strings. On x86-64
24 | // hardware in 2011, CityHash64() is faster than other high-quality
25 | // hash functions, such as Murmur. This is largely due to higher
26 | // instruction-level parallelism. CityHash64() and CityHash128() also perform
27 | // well on hash-quality tests.
28 | //
29 | // CityHash128() is optimized for relatively long strings and returns
30 | // a 128-bit hash. For strings more than about 2000 bytes it can be
31 | // faster than CityHash64().
32 | //
33 | // Functions in the CityHash family are not suitable for cryptography.
34 | //
35 | // WARNING: This code has not been tested on big-endian platforms!
36 | // It is known to work well on little-endian platforms that have a small penalty
37 | // for unaligned reads, such as current Intel and AMD moderate-to-high-end CPUs.
38 | //
39 | // By the way, for some hash functions, given strings a and b, the hash
40 | // of a+b is easily derived from the hashes of a and b. This property
41 | // doesn't hold for any hash functions in this file.
42 |
43 | #ifndef CITY_HASH_H_
44 | #define CITY_HASH_H_
45 |
46 | #include // for size_t.
47 | #include
48 | #include "citycrc.h"
49 |
50 | /* Define to 1 if the compiler supports __builtin_expect. */
51 | #define HAVE_BUILTIN_EXPECT 1
52 |
53 | struct Pair {
54 | uint64_t first;
55 | uint64_t second;
56 | };
57 | typedef struct Pair uint128;
58 |
59 | static uint64_t __inline__ Uint128Low64(const uint128 x) { return x.first; }
60 | static uint64_t __inline__ Uint128High64(const uint128 x) { return x.second; }
61 |
62 | // Hash function for a byte array.
63 | uint64_t CityHash64(const char *buf, size_t len);
64 |
65 | // Hash function for a byte array. For convenience, a 64-bit seed is also
66 | // hashed into the result.
67 | uint64_t CityHash64WithSeed(const char *buf, size_t len, uint64_t seed);
68 |
69 | // Hash function for a byte array. For convenience, two seeds are also
70 | // hashed into the result.
71 | uint64_t CityHash64WithSeeds(const char *buf, size_t len,
72 | uint64_t seed0, uint64_t seed1);
73 |
74 | // Hash function for a byte array.
75 | uint128 CityHash128(const char *s, size_t len);
76 |
77 | // Hash function for a byte array. For convenience, a 128-bit seed is also
78 | // hashed into the result.
79 | uint128 CityHash128WithSeed(const char *s, size_t len, uint128 seed);
80 |
81 | // Hash 128 input bits down to 64 bits of output.
82 | // This is intended to be a reasonably good hash function.
83 | static uint64_t __inline__ Hash128to64(const uint128 x) {
84 | // Murmur-inspired hashing.
85 | const uint64_t kMul = 0x9ddfea08eb382d69ULL;
86 | uint64_t a = (Uint128Low64(x) ^ Uint128High64(x)) * kMul;
87 | a ^= (a >> 47);
88 | uint64_t b = (Uint128High64(x) ^ a) * kMul;
89 | b ^= (b >> 47);
90 | b *= kMul;
91 | return b;
92 | }
93 |
94 | #endif // CITY_HASH_H_
95 |
--------------------------------------------------------------------------------
/src/citycrc.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2011 Google, Inc.
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in
11 | // all copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | // THE SOFTWARE.
20 | //
21 | // CityHash, by Geoff Pike and Jyrki Alakuijala
22 | //
23 | // This file declares the subset of the CityHash functions that require
24 | // _mm_crc32_u64(). See the CityHash README for details.
25 | //
26 | // Functions in the CityHash family are not suitable for cryptography.
27 |
28 | #ifndef CITY_HASH_CRC_H_
29 | #define CITY_HASH_CRC_H_
30 |
31 | #include
32 |
33 | // Hash function for a byte array.
34 | void CityHashCrc128(const char *s, size_t len, uint64_t *result);
35 |
36 | // Hash function for a byte array. Sets result[0] ... result[3].
37 | void CityHashCrc256(const char *s, size_t len, uint64_t *result);
38 |
39 | #endif // CITY_HASH_CRC_H_
40 |
--------------------------------------------------------------------------------
/src/compress.h:
--------------------------------------------------------------------------------
1 | #ifndef COMPRESS_H
2 | #define COMPRESS_H
3 |
4 | #include "defs.h"
5 | #include "huffman.h"
6 | #include "types.h"
7 |
8 | #ifdef DECOMPRESS_H
9 | #error compress.h conflicts with decompress.h
10 | #endif
11 |
12 | struct tb_handle {
13 | char name[64];
14 | int num_tables;
15 | int wdl;
16 | int split;
17 | uint8_t perm[8][TBPIECES];
18 | int default_blocksize;
19 | int blocksize[8];
20 | int idxbits[8];
21 | uint64_t real_num_blocks[8];
22 | uint64_t num_blocks[8];
23 | int num_indices[8];
24 | int num_syms[8];
25 | int num_values[8];
26 | struct HuffCode *c[8];
27 | struct Symbol *symtable[8];
28 | struct dtz_map *map[4];
29 | int flags[8];
30 | uint8_t single_val[8];
31 | FILE *H[8];
32 | };
33 |
34 | void compress_alloc_wdl(void);
35 | void compress_alloc_dtz_u8(void);
36 | void compress_alloc_dtz_u16(void);
37 | void compress_init_wdl(int *vals, int flags);
38 | void compress_init_dtz_u8(struct dtz_map *map);
39 | void compress_init_dtz_u16(struct dtz_map *map);
40 | void compress_tb_u8(struct tb_handle *F, u8 *data, uint64_t tb_size,
41 | uint8_t *perm, int minfreq);
42 | void compress_tb_u16(struct tb_handle *F, u16 *data, uint64_t tb_size,
43 | uint8_t *perm, int minfreq);
44 | void merge_tb(struct tb_handle *F);
45 | struct tb_handle *create_tb(char *tablename, int wdl, int blocksize);
46 | struct HuffCode *construct_pairs_u8(u8 *data, uint64_t size, int minfreq,
47 | int maxsymbols, int wdl);
48 | struct HuffCode *construct_pairs_u16(u16 *data, uint64_t size, int minfreq,
49 | int maxsymbols, int wdl);
50 |
51 | #endif
52 |
--------------------------------------------------------------------------------
/src/crc32c.c:
--------------------------------------------------------------------------------
1 | // Software implementation of _mm_crc32_u64 in case the CPU does not
2 | // support SSE4.2.
3 |
4 | // Based on:
5 | // https://raw.github.com/torvalds/linux/v2.6.12/net/sctp/crc32c.c
6 |
7 | #define CRC32C(c,d) (c=(c>>8)^crc_c[(c^(d))&0xFF])
8 |
9 | static const uint32_t crc_c[256] = {
10 | 0x00000000, 0xF26B8303, 0xE13B70F7, 0x1350F3F4,
11 | 0xC79A971F, 0x35F1141C, 0x26A1E7E8, 0xD4CA64EB,
12 | 0x8AD958CF, 0x78B2DBCC, 0x6BE22838, 0x9989AB3B,
13 | 0x4D43CFD0, 0xBF284CD3, 0xAC78BF27, 0x5E133C24,
14 | 0x105EC76F, 0xE235446C, 0xF165B798, 0x030E349B,
15 | 0xD7C45070, 0x25AFD373, 0x36FF2087, 0xC494A384,
16 | 0x9A879FA0, 0x68EC1CA3, 0x7BBCEF57, 0x89D76C54,
17 | 0x5D1D08BF, 0xAF768BBC, 0xBC267848, 0x4E4DFB4B,
18 | 0x20BD8EDE, 0xD2D60DDD, 0xC186FE29, 0x33ED7D2A,
19 | 0xE72719C1, 0x154C9AC2, 0x061C6936, 0xF477EA35,
20 | 0xAA64D611, 0x580F5512, 0x4B5FA6E6, 0xB93425E5,
21 | 0x6DFE410E, 0x9F95C20D, 0x8CC531F9, 0x7EAEB2FA,
22 | 0x30E349B1, 0xC288CAB2, 0xD1D83946, 0x23B3BA45,
23 | 0xF779DEAE, 0x05125DAD, 0x1642AE59, 0xE4292D5A,
24 | 0xBA3A117E, 0x4851927D, 0x5B016189, 0xA96AE28A,
25 | 0x7DA08661, 0x8FCB0562, 0x9C9BF696, 0x6EF07595,
26 | 0x417B1DBC, 0xB3109EBF, 0xA0406D4B, 0x522BEE48,
27 | 0x86E18AA3, 0x748A09A0, 0x67DAFA54, 0x95B17957,
28 | 0xCBA24573, 0x39C9C670, 0x2A993584, 0xD8F2B687,
29 | 0x0C38D26C, 0xFE53516F, 0xED03A29B, 0x1F682198,
30 | 0x5125DAD3, 0xA34E59D0, 0xB01EAA24, 0x42752927,
31 | 0x96BF4DCC, 0x64D4CECF, 0x77843D3B, 0x85EFBE38,
32 | 0xDBFC821C, 0x2997011F, 0x3AC7F2EB, 0xC8AC71E8,
33 | 0x1C661503, 0xEE0D9600, 0xFD5D65F4, 0x0F36E6F7,
34 | 0x61C69362, 0x93AD1061, 0x80FDE395, 0x72966096,
35 | 0xA65C047D, 0x5437877E, 0x4767748A, 0xB50CF789,
36 | 0xEB1FCBAD, 0x197448AE, 0x0A24BB5A, 0xF84F3859,
37 | 0x2C855CB2, 0xDEEEDFB1, 0xCDBE2C45, 0x3FD5AF46,
38 | 0x7198540D, 0x83F3D70E, 0x90A324FA, 0x62C8A7F9,
39 | 0xB602C312, 0x44694011, 0x5739B3E5, 0xA55230E6,
40 | 0xFB410CC2, 0x092A8FC1, 0x1A7A7C35, 0xE811FF36,
41 | 0x3CDB9BDD, 0xCEB018DE, 0xDDE0EB2A, 0x2F8B6829,
42 | 0x82F63B78, 0x709DB87B, 0x63CD4B8F, 0x91A6C88C,
43 | 0x456CAC67, 0xB7072F64, 0xA457DC90, 0x563C5F93,
44 | 0x082F63B7, 0xFA44E0B4, 0xE9141340, 0x1B7F9043,
45 | 0xCFB5F4A8, 0x3DDE77AB, 0x2E8E845F, 0xDCE5075C,
46 | 0x92A8FC17, 0x60C37F14, 0x73938CE0, 0x81F80FE3,
47 | 0x55326B08, 0xA759E80B, 0xB4091BFF, 0x466298FC,
48 | 0x1871A4D8, 0xEA1A27DB, 0xF94AD42F, 0x0B21572C,
49 | 0xDFEB33C7, 0x2D80B0C4, 0x3ED04330, 0xCCBBC033,
50 | 0xA24BB5A6, 0x502036A5, 0x4370C551, 0xB11B4652,
51 | 0x65D122B9, 0x97BAA1BA, 0x84EA524E, 0x7681D14D,
52 | 0x2892ED69, 0xDAF96E6A, 0xC9A99D9E, 0x3BC21E9D,
53 | 0xEF087A76, 0x1D63F975, 0x0E330A81, 0xFC588982,
54 | 0xB21572C9, 0x407EF1CA, 0x532E023E, 0xA145813D,
55 | 0x758FE5D6, 0x87E466D5, 0x94B49521, 0x66DF1622,
56 | 0x38CC2A06, 0xCAA7A905, 0xD9F75AF1, 0x2B9CD9F2,
57 | 0xFF56BD19, 0x0D3D3E1A, 0x1E6DCDEE, 0xEC064EED,
58 | 0xC38D26C4, 0x31E6A5C7, 0x22B65633, 0xD0DDD530,
59 | 0x0417B1DB, 0xF67C32D8, 0xE52CC12C, 0x1747422F,
60 | 0x49547E0B, 0xBB3FFD08, 0xA86F0EFC, 0x5A048DFF,
61 | 0x8ECEE914, 0x7CA56A17, 0x6FF599E3, 0x9D9E1AE0,
62 | 0xD3D3E1AB, 0x21B862A8, 0x32E8915C, 0xC083125F,
63 | 0x144976B4, 0xE622F5B7, 0xF5720643, 0x07198540,
64 | 0x590AB964, 0xAB613A67, 0xB831C993, 0x4A5A4A90,
65 | 0x9E902E7B, 0x6CFBAD78, 0x7FAB5E8C, 0x8DC0DD8F,
66 | 0xE330A81A, 0x115B2B19, 0x020BD8ED, 0xF0605BEE,
67 | 0x24AA3F05, 0xD6C1BC06, 0xC5914FF2, 0x37FACCF1,
68 | 0x69E9F0D5, 0x9B8273D6, 0x88D28022, 0x7AB90321,
69 | 0xAE7367CA, 0x5C18E4C9, 0x4F48173D, 0xBD23943E,
70 | 0xF36E6F75, 0x0105EC76, 0x12551F82, 0xE03E9C81,
71 | 0x34F4F86A, 0xC69F7B69, 0xD5CF889D, 0x27A40B9E,
72 | 0x79B737BA, 0x8BDCB4B9, 0x988C474D, 0x6AE7C44E,
73 | 0xBE2DA0A5, 0x4C4623A6, 0x5F16D052, 0xAD7D5351,
74 | };
75 |
76 | uint64_t _mm_crc32_u64(uint64_t crc, uint64_t v)
77 | {
78 | int i;
79 | union {
80 | uint8_t buf[8];
81 | uint64_t v;
82 | } in;
83 | uint32_t crc32 = crc;
84 |
85 | in.v = v;
86 | for (i = 0; i < 8; i++)
87 | CRC32C(crc32, in.buf[i]);
88 |
89 | return (uint64_t)crc32;
90 | }
91 |
92 |
--------------------------------------------------------------------------------
/src/decompress.h:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2011-2016, 2018 Ronald de Man
3 |
4 | This file is distributed under the terms of the GNU GPL, version 2.
5 | */
6 |
7 | #ifndef DECOMPRESS_H
8 | #define DECOMPRESS_H
9 |
10 | #include "probe.h"
11 |
12 | #ifdef COMPRESS_H
13 | #error decompress.h conflicts with compress.h
14 | #endif
15 |
16 | struct tb_handle {
17 | FILE *F;
18 | uint8_t *data;
19 | uint64_t data_size;
20 | int wdl;
21 | int num_files;
22 | int split;
23 | int has_pawns;
24 | struct {
25 | uint64_t idx[2];
26 | uint64_t size[2];
27 | } file[4];
28 | union {
29 | struct TBEntry entry;
30 | struct TBEntry_piece entry_piece;
31 | struct TBEntry_pawn entry_pawn;
32 | };
33 | uint8_t dtz_flags[4];
34 | uint8_t (*map[4])[256];
35 | uint16_t (*map16[4])[MAX_VALS];
36 | };
37 |
38 | void decomp_init_piece(int *pcs);
39 | void decomp_init_pawn(int *pcs, int *pt);
40 | struct tb_handle *open_tb(char *tablename, int wdl);
41 | void decomp_init_table(struct tb_handle *H);
42 | uint8_t *decompress_table(struct tb_handle *H, int bside, int f);
43 | void close_tb(struct tb_handle *H);
44 | void set_perm(struct tb_handle *H, int bside, int f, int *perm, int *pt);
45 | struct TBEntry *get_entry(struct tb_handle *H);
46 | int get_ply_accurate_win(struct tb_handle *H, int f);
47 | int get_ply_accurate_loss(struct tb_handle *H, int f);
48 | int get_dtz_side(struct tb_handle *H, int f);
49 | uint8_t (*get_dtz_map(struct tb_handle *H, int f))[256];
50 | uint16_t (*get_dtz_map16(struct tb_handle *H, int f))[4096];
51 |
52 | #endif
53 |
--------------------------------------------------------------------------------
/src/defs.h:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2011-2018 Ronald de Man
3 |
4 | This file is distributed under the terms of the GNU GPL, version 2.
5 | */
6 |
7 | #ifndef DEFS_H
8 | #define DEFS_H
9 |
10 | #include
11 |
12 | #if defined(REGULAR) || defined (SHATRANJ)
13 | #define SMALL
14 | #endif
15 |
16 | #define DRAW_RULE (2 * 50)
17 |
18 | #if TBPIECES < 7
19 | #define MAX_STATS 1536
20 | #else
21 | #define MAX_STATS 2560
22 | #endif
23 |
24 | #ifndef COMPRESSION_THREADS
25 | #define COMPRESSION_THREADS 1
26 | #endif
27 |
28 | #define MAX_VALS (((MAX_STATS / 2) - DRAW_RULE) / 2)
29 |
30 | enum { MAXSYMB = 4095 + 8 };
31 |
32 | #define LOOKUP
33 | #define LUBITS 12
34 |
35 | // GIVEAWAY is a variation on SUICIDE
36 | #ifdef GIVEAWAY
37 | #define SUICIDE
38 | #endif
39 |
40 | #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)
41 | #define assume(x) do { if (!(x)) __builtin_unreachable(); } while (0)
42 | #else
43 | #define assume(x) do { } while (0)
44 | #endif
45 |
46 | #if 0
47 | #define likely(x) (x)
48 | #define unlikely(x) (x)
49 | #else
50 | #define likely(x) __builtin_expect(!!(x),1)
51 | #define unlikely(x) __builtin_expect(!!(x),0)
52 | #endif
53 |
54 | #define PASTER(x,y) x##_##y
55 | #define EVALUATOR(x,y) PASTER(x,y)
56 |
57 | #endif
58 |
--------------------------------------------------------------------------------
/src/generic.c:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2011-2013, 2018 Ronald de Man
3 |
4 | This file is distributed under the terms of the GNU GPL, version 2.
5 | */
6 |
7 | //static uint64_t mask_a1h1, mask_a1a8, mask_a1h8;
8 | static uint64_t mask_a1h8;
9 | static uint64_t idx_mask1[8], idx_mask2[8];
10 |
11 | static const char mirror[] = {
12 | 0, 1, 1, 1, 1, 1, 1, 0,
13 | -1, 0, 1, 1, 1, 1, 0,-1,
14 | -1,-1, 0, 1, 1, 0,-1,-1,
15 | -1,-1,-1, 0, 0,-1,-1,-1,
16 | -1,-1,-1, 0, 0,-1,-1,-1,
17 | -1,-1, 0, 1, 1, 0,-1,-1,
18 | -1, 0, 1, 1, 1, 1, 0,-1,
19 | 0, 1, 1, 1, 1, 1, 1, 0
20 | };
21 |
22 | static const int inv_tri0x40[] = {
23 | 1, 2, 3, 10, 11, 19, 0, 9, 18, 27
24 | };
25 |
26 | static uint64_t mask[MAX_PIECES];
27 | static int shift[MAX_PIECES];
28 |
29 | uint64_t tri0x40[64];
30 | uint64_t sq_mask[64];
31 |
32 | static const uint8_t tri0x40_init[32] = {
33 | 6, 0, 1, 2, 0, 0, 0, 0,
34 | 0, 7, 3, 4, 0, 0, 0, 0,
35 | 0, 0, 8, 5, 0, 0, 0, 0,
36 | 0, 0, 0, 9, 0, 0, 0, 0
37 | };
38 |
39 | #define diagonal (tri0x40[0])
40 |
41 | void init_tables(void)
42 | {
43 | int i, sq;
44 |
45 | uint64_t mask_a1h1, mask_a1a8;
46 | mask_a1h1 = mask_a1a8 = mask_a1h8 = 0;
47 | for (i = 1; i < numpcs; i++) {
48 | mask_a1h1 = (mask_a1h1 << 6) | 0x07;
49 | mask_a1a8 = (mask_a1a8 << 6) | 0x38;
50 | mask_a1h8 = (mask_a1h8 << 6) | 0x07;
51 | }
52 |
53 | for (i = 0; i < 64; i++) {
54 | sq = i;
55 | if (sq & 0x04)
56 | sq ^= 0x07;
57 | if (sq & 0x20)
58 | sq ^= 0x38;
59 | if ((sq >> 3) > (sq & 7))
60 | sq = ((sq & 7) << 3) | (sq >> 3);
61 | tri0x40[i] = (uint64_t)tri0x40_init[sq] << shift[0];
62 | }
63 |
64 | for (sq = 0; sq < 64; sq++) {
65 | uint64_t mask = 0;
66 | if (sq & 0x04) mask ^= mask_a1h1;
67 | if (sq & 0x20) mask ^= mask_a1a8;
68 | sq_mask[sq] = mask;
69 | }
70 |
71 | set_up_tables();
72 | }
73 |
74 | //#define MIRROR_A1H1(x) ((x) ^ mask_a1h1)
75 | //#define MIRROR_A1A8(x) ((x) ^ mask_a1a8)
76 | #define MIRROR_A1H8(x) ((((x) & mask_a1h8) << 3) | (((x) >> 3) & mask_a1h8))
77 |
78 | static uint64_t __inline__ MakeMove0(uint64_t idx, int sq)
79 | {
80 | idx ^= sq_mask[sq];
81 | if (mirror[sq] < 0) idx = MIRROR_A1H8(idx);
82 | return idx | tri0x40[sq];
83 | }
84 |
85 | static uint64_t __inline__ MakeMove1(uint64_t idx, int k, int sq)
86 | {
87 | return idx | ((uint64_t)sq << shift[k]);
88 | }
89 |
90 | static uint64_t __inline__ MakeMove(uint64_t idx, int k, int sq)
91 | {
92 | if (k) return idx | ((uint64_t)sq << shift[k]);
93 | idx ^= sq_mask[sq];
94 | if (mirror[sq] < 0) idx = MIRROR_A1H8(idx);
95 | return idx | tri0x40[sq];
96 | }
97 |
98 | #define CHECK_DIAG int flag = mirror[p[0]]
99 | #define PIVOT_ON_DIAG(idx) (flag && idx >= diagonal)
100 | #define PIVOT_MIRROR(idx) (MIRROR_A1H8(idx) | (idx & mask[0]))
101 |
102 | // use bit_set
103 | #if 1
104 |
105 | #define bit_set(x,y) { uint64_t dummy = y; __asm__("bts %1,%0" : "+r" (x) : "r" (dummy));}
106 | #define bit_set(x,y) { uint64_t dummy = y; __asm__("bts %1,%0" : "+r" (x) : "r" (dummy));}
107 |
108 | #define jump_bit_set(x,y,lab) \
109 | __asm__ goto ("bt %1, %0; jc %l[lab]" : : "r" (x), "r" ((uint64_t)(y)) : : lab);
110 |
111 | #define jump_bit_clear(x,y,lab) \
112 | __asm__ goto ("bt %1, %0; jnc %l[lab]" : : "r" (x), "r" ((uint64_t)(y)) : : lab);
113 |
114 | #define bit_set_jump_set(x,y,lab) \
115 | __asm__ goto ("bts %1, %0; jc %l[lab]" : "+r" (x) : "r" ((uint64_t)(y)) : : lab);
116 |
117 | #define FILL_OCC64_cheap \
118 | occ = 0; \
119 | for (i = n - 2, idx2 = idx >> 6; i > 0; i--, idx2 >>= 6) \
120 | bit_set(occ, idx2 & 0x3f); \
121 | bit_set(occ, inv_tri0x40[idx2]); \
122 | if (PopCount(occ) == n - 1)
123 |
124 | #define FILL_OCC64 \
125 | occ = 0; \
126 | for (i = n - 2, idx2 = idx >> 6; i > 0; i--, idx2 >>= 6) \
127 | bit_set(occ, p[i] = idx2 & 0x3f); \
128 | bit_set(occ, p[0] = inv_tri0x40[idx2]); \
129 | if (PopCount(occ) == n - 1)
130 |
131 | #define FILL_OCC64_asmgoto \
132 | occ = 0; \
133 | i = n - 2; \
134 | idx2 = idx >> 6; \
135 | do { \
136 | bit_set_jump_set(occ, p[i] = idx2 & 0x3f, lab); \
137 | idx2 >>= 6; \
138 | i--; \
139 | } while (i > 0); \
140 | bit_set_jump_set(occ, p[0] = inv_tri0x40[idx2], lab)
141 |
142 | #define FILL_OCC \
143 | occ = 0; \
144 | for (i = n - 1, idx2 = idx; i > 0; i--, idx2 >>= 6) \
145 | bit_set(occ, p[i] = idx2 & 0x3f); \
146 | bit_set(occ, p[0] = inv_tri0x40[idx2])
147 |
148 | #define FILL_OCC_CAPTS \
149 | uint64_t idx2 = idx; \
150 | occ = 0; \
151 | for (k = n - 1; k > 0; k--) \
152 | if (k != i) { \
153 | bit_set(occ, p[k] = idx2 & 0x3f); \
154 | idx2 >>= 6; \
155 | } \
156 | bit_set(occ, p[0] = inv_tri0x40[idx2]); \
157 | if (PopCount(occ) == n - 1)
158 |
159 | #define FILL_OCC_CAPTS_PIVOT \
160 | uint64_t idx2 = idx; \
161 | occ = 0; \
162 | for (k = n - 1; k > 0; k--, idx2 >>= 6) \
163 | bit_set(occ, p[k] = idx2 & 0x3f); \
164 | if (PopCount(occ) == n - 1)
165 |
166 | #else
167 |
168 | #define FILL_OCC64 \
169 | occ = 0; \
170 | for (i = n - 2, idx2 = idx >> 6; i > 0; i--, idx2 >>= 6) \
171 | occ |= bit[p[i] = idx2 & 0x3f]; \
172 | occ |= bit[p[0] = inv_tri0x40[idx2]]; \
173 | if (PopCount(occ) == n - 1)
174 |
175 | #define FILL_OCC \
176 | occ = 0; \
177 | for (i = n - 1, idx2 = idx; i > 0; i--, idx2 >>= 6) \
178 | occ |= bit[p[i] = idx2 & 0x3f]; \
179 | occ |= bit[p[0] = inv_tri0x40[idx2]]
180 |
181 | #define FILL_OCC_CAPTS \
182 | uint64_t idx2 = idx; \
183 | occ = 0; \
184 | for (k = n - 1; k > 0; k--) \
185 | if (k != i) { \
186 | occ |= bit[p[k] = idx2 & 0x3f]; \
187 | idx2 >>= 6; \
188 | } \
189 | occ |= bit[p[k] = inv_tri0x40[idx2]]; \
190 | if (PopCount(occ) == n - 1)
191 |
192 | #define FILL_OCC_CAPTS_PIVOT \
193 | uint64_t idx2 = idx; \
194 | occ = 0; \
195 | for (k = n - 1; k > 0; k--, idx2 >>= 6) \
196 | occ |= bit[p[k] = idx2 & 0x3f]; \
197 | if (PopCount(occ) == n - 1)
198 |
199 | #endif
200 |
201 | #define MAKE_IDX2 \
202 | idx2 = ((idx << 6) & idx_mask1[i]) | (idx & idx_mask2[i])
203 |
204 | #define MAKE_IDX2_PIVOT \
205 | idx2 = idx
206 |
207 | #define MARK(func, ...) \
208 | static void func(int k, uint8_t *table, uint64_t idx, bitboard occ, int *p, ##__VA_ARGS__)
209 |
210 | #define MARK_PIVOT(func, ...) \
211 | static void func##_pivot(uint8_t *table, uint64_t idx, bitboard occ, int *p, ##__VA_ARGS__)
212 |
213 | #define MARK_BEGIN_PIVOT \
214 | int sq; \
215 | uint64_t idx2; \
216 | bitboard bb; \
217 | CHECK_DIAG; \
218 | bb = PieceMoves(p[0], pt[0], occ); \
219 | while (bb) { \
220 | sq = FirstOne(bb); \
221 | idx2 = MakeMove0(idx, sq)
222 |
223 | #define MARK_BEGIN \
224 | int sq; \
225 | uint64_t idx2; \
226 | bitboard bb; \
227 | bb = PieceMoves(p[k], pt[k], occ); \
228 | while (bb) { \
229 | sq = FirstOne(bb); \
230 | idx2 = MakeMove1(idx, k, sq)
231 |
232 | #define MARK_END \
233 | ClearFirst(bb); \
234 | }
235 |
236 | #ifndef ATOMIC
237 | #define BEGIN_CAPTS \
238 | uint64_t idx; \
239 | bitboard occ; \
240 | int i = captured_piece; \
241 | int j, k; \
242 | int p[MAX_PIECES]; \
243 | int pt2[MAX_PIECES]; \
244 | int n = numpcs; \
245 | uint64_t end = thread->end >> 6; \
246 | for (k = 0; k < n; k++) \
247 | pt2[k] = pt[k]; \
248 | pt2[i] = 0
249 | #else
250 | #define BEGIN_CAPTS \
251 | uint64_t idx; \
252 | bitboard occ; \
253 | int i = captured_piece; \
254 | int j, k; \
255 | int p[MAX_PIECES]; \
256 | int pt2[MAX_PIECES]; \
257 | int n = numpcs; \
258 | uint64_t end = thread->end >> 6
259 | #endif
260 |
261 | #define BEGIN_CAPTS_NOPROBE \
262 | uint64_t idx; \
263 | bitboard occ; \
264 | int i = captured_piece; \
265 | int j, k; \
266 | int p[MAX_PIECES]; \
267 | int n = numpcs; \
268 | uint64_t end = thread->end >> 6
269 |
270 | #define BEGIN_CAPTS_PIVOT \
271 | uint64_t idx; \
272 | bitboard occ; \
273 | int j, k; \
274 | int p[MAX_PIECES]; \
275 | int pt2[MAX_PIECES]; \
276 | int n = numpcs; \
277 | uint64_t end = thread->end; \
278 | for (k = 1; k < n; k++) \
279 | pt2[k] = pt[k]; \
280 | pt2[0] = 0
281 |
282 | #define BEGIN_CAPTS_PIVOT_NOPROBE \
283 | uint64_t idx; \
284 | bitboard occ; \
285 | int j, k; \
286 | int p[MAX_PIECES]; \
287 | int n = numpcs; \
288 | uint64_t end = thread->end
289 |
290 | #define LOOP_CAPTS \
291 | for (idx = thread->begin >> 6; idx < end; idx++)
292 |
293 | #define LOOP_CAPTS_PIVOT \
294 | for (idx = thread->begin; idx < end; idx++)
295 |
296 | #ifndef ATOMIC
297 | #define LOOP_WHITE_PIECES(func, ...) \
298 | do { \
299 | uint64_t idx3 = idx2 | ((uint64_t)p[0] << shift[i]); \
300 | func##_pivot(table_w, idx3 & ~mask[0], occ, p, ##__VA_ARGS__); \
301 | for (j = 1; white_pcs[j] >= 0; j++) { \
302 | k = white_pcs[j]; \
303 | uint64_t idx3 = idx2 | ((uint64_t)p[k] << shift[i]); \
304 | func(k, table_w, idx3 & ~mask[k], occ, p, ##__VA_ARGS__); \
305 | } \
306 | } while (0)
307 | #else
308 | #define LOOP_WHITE_PIECES(func, ...) \
309 | do { \
310 | bitboard bits = king_range[p[0]]; \
311 | for (j = 1; white_pcs[j] >= 0; j++) { \
312 | k = white_pcs[j]; \
313 | if (bit[p[k]] & bits) continue; \
314 | uint64_t idx3 = idx2 | ((uint64_t)p[k] << shift[i]); \
315 | func(k, table_w, idx3 & ~mask[k], occ, p, ##__VA_ARGS__); \
316 | } \
317 | } while (0)
318 | #endif
319 |
320 | #if 0
321 | #define LOOP_WHITE_PIECES(func, ...) \
322 | do { for (j = 0; white_pcs[j] >= 0; j++) { \
323 | k = white_pcs[j]; \
324 | uint64_t idx3 = idx2 | ((uint64_t)p[k] << shift[i]); \
325 | func(k, table_w, idx3 & ~mask[k], occ, p, ##__VA_ARGS__); \
326 | } } while (0)
327 | #endif
328 |
329 | #ifndef ATOMIC
330 | #define LOOP_BLACK_PIECES(func, ...) \
331 | do { for (j = 0; black_pcs[j] >= 0; j++) { \
332 | k = black_pcs[j]; \
333 | uint64_t idx3 = idx2 | ((uint64_t)p[k] << shift[i]); \
334 | func(k, table_b, idx3 & ~mask[k], occ, p, ##__VA_ARGS__); \
335 | } } while (0)
336 | #else
337 | #define LOOP_BLACK_PIECES(func, ...) \
338 | do { \
339 | bitboard bits = king_range[p[black_king]]; \
340 | for (j = 1; black_pcs[j] >= 0; j++) { \
341 | k = black_pcs[j]; \
342 | if (bit[p[k]] & bits) continue; \
343 | uint64_t idx3 = idx2 | ((uint64_t)p[k] << shift[i]); \
344 | func(k, table_b, idx3 & ~mask[k], occ, p, ##__VA_ARGS__); \
345 | } } while (0)
346 | #endif
347 |
348 | #define CHECK_BLACK_PIECES_PIVOT \
349 | for (j = 0; black_pcs[j] >= 0; j++) { \
350 | k = black_pcs[j]; \
351 | if (!(p[k] & 0x24) && mirror[p[k]] >= 0) break; \
352 | } \
353 | if (black_pcs[j] < 0) continue
354 |
355 | #ifndef ATOMIC
356 | #define LOOP_BLACK_PIECES_PIVOT(func, ...) \
357 | do { for (j = 0; black_pcs[j] >= 0; j++) { \
358 | k = black_pcs[j]; \
359 | if ((p[k] & 0x24) || mirror[p[k]] < 0) continue; \
360 | uint64_t idx3 = idx2 | tri0x40[p[k]]; \
361 | func(k, table_b, idx3 & ~mask[k], occ, p, ##__VA_ARGS__); \
362 | } } while (0)
363 | #else
364 | #define LOOP_BLACK_PIECES_PIVOT(func, ...) \
365 | do { \
366 | bitboard bits = king_range[p[black_king]]; \
367 | for (j = 1; black_pcs[j] >= 0; j++) { \
368 | k = black_pcs[j]; \
369 | if (bit[p[k]] & bits) continue; \
370 | if ((p[k] & 0x24) || mirror[p[k]] < 0) continue; \
371 | uint64_t idx3 = idx2 | tri0x40[p[k]]; \
372 | func(k, table_b, idx3 & ~mask[k], occ, p, ##__VA_ARGS__); \
373 | } } while (0)
374 | #endif
375 |
376 | #define BEGIN_ITER \
377 | uint64_t idx, idx2; \
378 | bitboard occ; \
379 | int i; \
380 | int n = numpcs; \
381 | int p[MAX_PIECES]; \
382 | uint64_t end = thread->end;
383 |
384 | #define LOOP_ITER \
385 | for (idx = thread->begin; idx < end; idx++)
386 |
387 | #define RETRO(func, ...) \
388 | do { int j; \
389 | j = 0; \
390 | if (pcs_opp[0] == 0) { \
391 | func##_pivot(table_opp, idx & ~mask[0], occ, p, ##__VA_ARGS__); \
392 | j = 1; \
393 | } \
394 | for (; pcs_opp[j] >= 0; j++) { \
395 | int k = pcs_opp[j]; \
396 | func(k, table_opp, idx & ~mask[k], occ, p , ##__VA_ARGS__); \
397 | } \
398 | } while (0)
399 |
400 | #if 0
401 | #define RETRO_BLACK(func, ...) \
402 | do { int j; \
403 | for (j = 0; black_pcs[j] >= 0; j++) { \
404 | int k = black_pcs[j]; \
405 | func(k, table_b, idx & ~mask[k], occ, p , ##__VA_ARGS__); \
406 | } \
407 | } while (0)
408 |
409 | #define RETRO_WHITE(func, ...) \
410 | do { int j; \
411 | for (j = 0; white_pcs[j] >= 0; j++) { \
412 | int k = white_pcs[j]; \
413 | func(k, table_w, idx & ~mask[k], occ, p , ##__VA_ARGS__); \
414 | } \
415 | } while (0)
416 | #endif
417 |
--------------------------------------------------------------------------------
/src/huffman.c:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | #include "defs.h"
4 | #include "huffman.h"
5 |
6 | struct List {
7 | uint64_t w[8192];
8 | int p[8192];
9 | int len;
10 | };
11 |
12 | #define L 32
13 |
14 | static void package_merge(struct HuffCode *c, int num, int *a)
15 | {
16 | struct List *lists = malloc(L * sizeof(struct List));
17 |
18 | for (int m = 0; m < L; m++) {
19 | int prev_len = m == 0 ? 0 : lists[m - 1].len;
20 | int i = 0, j = 0, k = 1;
21 | while (i < 2 * num - 2 && j < num && k < prev_len) {
22 | if (c->freq[c->map[j]] < lists[m - 1].w[k - 1] + lists[m - 1].w[k]) {
23 | lists[m].w[i] = c->freq[c->map[j]];
24 | lists[m].p[i] = 0;
25 | j++;
26 | } else {
27 | lists[m].w[i] = lists[m - 1].w[k - 1] + lists[m - 1].w[k];
28 | lists[m].p[i] = k;
29 | k += 2;
30 | }
31 | i++;
32 | }
33 | while (i < 2 * num - 2 && j < num) {
34 | lists[m].w[i] = c->freq[c->map[j]];
35 | lists[m].p[i] = 0;
36 | j++;
37 | i++;
38 | }
39 | while (i < 2 * num - 2 && k < prev_len) {
40 | lists[m].w[i] = lists[m - 1].w[k - 1] + lists[m - 1].w[k];
41 | lists[m].p[i] = k;
42 | k += 2;
43 | i++;
44 | }
45 | lists[m].len = i;
46 | }
47 |
48 | int k = lists[L - 1].len;
49 | for (int m = L - 1; m >= 0; m--) {
50 | int l = 0;
51 | int n = 0;
52 | for (int i = 0; i < k; i++) {
53 | if (lists[m].p[i])
54 | n = lists[m].p[i] + 1;
55 | else
56 | l++;
57 | }
58 | a[L - 1 - m] = l;
59 | k = n;
60 | }
61 |
62 | for (int l = 0; l < L - 1; l++)
63 | a[l] -= a[l + 1];
64 |
65 | free(lists);
66 | }
67 |
68 | static void create_code_old(struct HuffCode *c, int num_syms);
69 | static int sort_code(struct HuffCode *c);
70 |
71 | void create_code(struct HuffCode *c, int num_syms)
72 | {
73 | create_code_old(c, num_syms);
74 | if (sort_code(c)) return;
75 |
76 | int a[L];
77 |
78 | c->num_syms = num_syms;
79 |
80 | int num = 0;
81 | for (int i = 0; i < num_syms; i++)
82 | if (c->freq[i])
83 | c->map[num++] = i;
84 |
85 | for (int i = 0; i < num; i++)
86 | for (int j = i + 1; j < num; j++)
87 | if (c->freq[c->map[i]] > c->freq[c->map[j]]) {
88 | int tmp = c->map[i];
89 | c->map[i] = c->map[j];
90 | c->map[j] = tmp;
91 | }
92 |
93 | package_merge(c, num, a);
94 |
95 | int k = 0;
96 | for (int l = L - 1; l >= 0; l--)
97 | for (int i = 0; i < a[l]; i++)
98 | c->length[c->map[k++]] = l + 1;
99 |
100 | sort_code(c);
101 | }
102 |
103 | void create_code_old(struct HuffCode *c, int num_syms)
104 | {
105 | int i, num;
106 | int idx1, idx2;
107 | uint64_t min1, min2;
108 |
109 | c->num_syms = num_syms;
110 | num = 0;
111 | for (i = 0; i < num_syms; i++)
112 | if (c->freq[i]) {
113 | c->nfreq[num] = c->freq[i];
114 | c->map[i] = num;
115 | num++;
116 | }
117 |
118 | for (i = 0; i < num_syms; i++)
119 | c->length[i] = 0;
120 |
121 | if (num == 1) {
122 | for (i = 0; i < num_syms; i++)
123 | if (c->freq[i]) break;
124 | c->length[i] = 1;
125 | } else while (num > 1) {
126 | min1 = min2 = INT64_MAX;
127 | idx1 = idx2 = 0;
128 | for (i = 0; i < num; i++)
129 | if (c->nfreq[i] < min2) {
130 | if (c->nfreq[i] < min1) {
131 | min2 = min1;
132 | idx2 = idx1;
133 | min1 = c->nfreq[i];
134 | idx1 = i;
135 | } else {
136 | min2 = c->nfreq[i];
137 | idx2 = i;
138 | }
139 | }
140 | if (idx1 > idx2) {
141 | int tmp = idx1;
142 | idx1 = idx2;
143 | idx2 = tmp;
144 | }
145 | c->nfreq[idx1] = min1 + min2;
146 | num--;
147 | for (i = idx2; i < num; i++)
148 | c->nfreq[i] = c->nfreq[i+1];
149 | for (i = 0; i < num_syms; i++)
150 | if (c->map[i] == idx1) {
151 | c->length[i]++;
152 | } else if (c->map[i] == idx2) {
153 | c->map[i] = idx1;
154 | c->length[i]++;
155 | } else if (c->map[i] > idx2) {
156 | c->map[i]--;
157 | }
158 | }
159 | }
160 |
161 | int sort_code(struct HuffCode *c)
162 | {
163 | int num = c->num_syms;
164 |
165 | for (int i = 0; i < num; i++) {
166 | c->map[i] = i;
167 | if (c->freq[i] == 0)
168 | c->length[i] = 0;
169 | }
170 |
171 | for (int i = 0; i < num; i++)
172 | for (int j = i + 1; j < num; j++)
173 | if ( c->length[c->map[i]] < c->length[c->map[j]]
174 | || ( c->length[c->map[i]] == c->length[c->map[j]]
175 | && c->freq[c->map[i]] > c->freq[c->map[j]]))
176 | {
177 | int tmp = c->map[i];
178 | c->map[i] = c->map[j];
179 | c->map[j] = tmp;
180 | }
181 |
182 | for (int i = 0; i < num; i++)
183 | c->inv[c->map[i]] = i;
184 |
185 | int max_len = c->length[c->map[0]];
186 | if (max_len > L) return 0;
187 |
188 | c->num = num;
189 | c->max_len = max_len;
190 | c->offset[max_len] = 0;
191 | c->base[max_len] = 0;
192 | int k = max_len - 1;
193 | for (int i = 0; i < num && c->length[c->map[i]]; i++)
194 | while (k >= c->length[c->map[i]]) {
195 | c->offset[k] = i;
196 | c->base[k] = (c->base[k + 1] + (i - c->offset[k + 1])) / 2;
197 | k--;
198 | }
199 | c->min_len = k + 1;
200 |
201 | return 1;
202 | }
203 |
204 | uint64_t calc_size(struct HuffCode *c)
205 | {
206 | uint64_t bits = 0;
207 |
208 | for (int i = 0; i < c->num_syms; i++)
209 | bits += c->length[i] * c->freq[i];
210 |
211 | return (bits + 7) >> 3;
212 | }
213 |
--------------------------------------------------------------------------------
/src/huffman.h:
--------------------------------------------------------------------------------
1 | #ifndef HUFFMAN_H
2 | #define HUFFMAN_H
3 |
4 | #include
5 |
6 | #include "defs.h"
7 |
8 | struct HuffCode {
9 | int64_t freq[MAXSYMB];
10 | int64_t nfreq[MAXSYMB];
11 | int map[MAXSYMB];
12 | int inv[MAXSYMB];
13 | int length[MAXSYMB];
14 | int num_syms, num, max_len, min_len;
15 | int base[33];
16 | int offset[33];
17 | };
18 |
19 | void create_code(struct HuffCode *c, int num_syms);
20 | uint64_t calc_size(struct HuffCode *c);
21 |
22 | #endif
23 |
--------------------------------------------------------------------------------
/src/hyper.c:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2011-2013 Ronald de Man
3 |
4 | This file is distributed under the terms of the GNU GPL, version 2.
5 | */
6 |
7 | /* to be included in board.c */
8 |
9 | #ifdef HYPER
10 |
11 | #ifndef HYPER_SSE3
12 | struct Hyper hyper_table[64];
13 | #else
14 | bitboard hyper_rook_mask[64];
15 | #endif
16 | uint8_t hyper_rank[512];
17 |
18 | #ifdef HYPER_SSE3
19 | #include
20 | __m128i hyper_diagmask_xmm[64];
21 | __m128i hyper_bitmask_xmm[64];
22 | __m128i hyper_swapmask_xmm;
23 | #endif
24 |
25 | #ifndef HYPER_INLINE
26 | #ifdef HYPER_SSE3
27 | bitboard BishopRange(int sq, bitboard occ) {
28 | __m128i o, r, m, b, s;
29 |
30 | m = hyper_diagmask_xmm[sq];
31 | b = hyper_bitmask_xmm[sq];
32 | s = hyper_swapmask_xmm;
33 | o = _mm_cvtsi64x_si128(occ);
34 | o = _mm_unpacklo_epi64(o, o);
35 | o = _mm_and_si128(o, m);
36 | r = _mm_shuffle_epi8(o, s);
37 | o = _mm_sub_epi64(o, b);
38 | b = _mm_shuffle_epi8(b, s);
39 | r = _mm_sub_epi64(r, b);
40 | r = _mm_shuffle_epi8(r, s);
41 | o = _mm_xor_si128(o, r);
42 | o = _mm_and_si128(o, m);
43 | r = _mm_unpackhi_epi64(o, o);
44 | o = _mm_add_epi64(o, r);
45 | return _mm_cvtsi128_si64(o);
46 | }
47 | #else
48 | bitboard BishopRange(int sq, bitboard occ)
49 | {
50 | struct Hyper *hyper = &hyper_table[sq];
51 | bitboard diag135, diag45, reverse;
52 |
53 | diag135 = occ & hyper->diagmask135;
54 | reverse = __builtin_bswap64(diag135);
55 | diag135 -= hyper->bitmask;
56 | // reverse -= __builtin_bswap64(hyper->bitmask);
57 | reverse -= bit[sq ^ 0x38];
58 | diag135 ^= __builtin_bswap64(reverse);
59 | diag135 &= hyper->diagmask135;
60 |
61 | diag45 = occ & hyper->diagmask45;
62 | reverse = __builtin_bswap64(diag45);
63 | diag45 -= hyper->bitmask;
64 | // reverse -= __builtin_bswap64(hyper->bitmask);
65 | reverse -= bit[sq ^ 0x38];
66 | diag45 ^= __builtin_bswap64(reverse);
67 | diag45 &= hyper->diagmask45;
68 |
69 | return diag135 | diag45;
70 | }
71 | #endif
72 |
73 | #ifndef HYPER_SSE3
74 | bitboard RookAttacks(int sq, bitboard occ)
75 | {
76 | struct Hyper *hyper = &hyper_table[sq];
77 | bitboard file, reverse;
78 | bitboard rank;
79 |
80 | file = occ & hyper->filemask;
81 | reverse = __builtin_bswap64(file);
82 | file -= hyper->bitmask;
83 | // reverse -= __builtin_bswap64(hyper->bitmask);
84 | reverse -= bit[sq ^ 0x38];
85 | file ^= __builtin_bswap64(reverse);
86 | file &= hyper->filemask;
87 |
88 | uint32 shift = sq & 0x38;
89 | rank = ((bitboard)hyper_rank[4 * ((occ >> shift) & 0x7e) + (sq & 0x07)]) << shift;
90 |
91 | return file | rank;
92 | }
93 | #else
94 | bitboard RookAttacks(int sq, bitboard occ)
95 | {
96 | bitboard file, reverse, rank;
97 |
98 | file = occ & hyper_rook_mask[sq];
99 | reverse = __builtin_bswap64(file);
100 | file -= bit[sq];
101 | reverse -= bit[sq ^ 0x38];
102 | file ^= __builtin_bswap64(reverse);
103 | file &= hyper_rook_mask[sq];
104 |
105 | uint32 shift = sq & 0x38;
106 | rank = ((bitboard)hyper_rank[4 * ((occ >> shift) & 0x7e) + (sq & 0x07)]) << shift;
107 |
108 | return file | rank;
109 | }
110 | #endif
111 | #endif
112 |
113 | static void set_up_move_gen(void)
114 | {
115 | int sq, sq88, d;
116 | int i, j;
117 | uint8_t b;
118 | bitboard bb, bb2;
119 | #ifdef HYPER_SSE3
120 | __m128i xmm1, xmm2;
121 | #endif
122 |
123 | for (sq = 0; sq < 64; sq++) {
124 | sq88 = sq + (sq & ~7);
125 |
126 | bb = 0;
127 | for (d = 1; !((sq88 + 17 * d) & 0x88); d++)
128 | bb |= bit[sq + 9 * d];
129 | for (d = 1; !((sq88 - 17 * d) & 0x88); d++)
130 | bb |= bit[sq - 9 * d];
131 |
132 | bb2 = 0;
133 | for (d = 1; !((sq88 + 15 * d) & 0x88); d++)
134 | bb2 |= bit[sq + 7 * d];
135 | for (d = 1; !((sq88 - 15 * d) & 0x88); d++)
136 | bb2 |= bit[sq - 7 * d];
137 |
138 | #ifdef HYPER_SSE3
139 | xmm1 = _mm_cvtsi64x_si128(bb);
140 | xmm2 = _mm_cvtsi64x_si128(bb2);
141 | hyper_diagmask_xmm[sq] = _mm_unpacklo_epi64(xmm1, xmm2);
142 | xmm1 = _mm_cvtsi64x_si128(bit[sq]);
143 | hyper_bitmask_xmm[sq] = _mm_unpacklo_epi64(xmm1, xmm1);
144 | #else
145 | hyper_table[sq].diagmask135 = bb;
146 | hyper_table[sq].diagmask45 = bb2;
147 | hyper_table[sq].bitmask = bit[sq];
148 | #endif
149 |
150 | bb = 0;
151 | for (d = 1; !((sq88 + 16 * d) & 0x88); d++)
152 | bb |= bit[sq + 8 * d];
153 | for (d = 1; !((sq88 - 16 * d) & 0x88); d++)
154 | bb |= bit[sq - 8 * d];
155 | #ifdef HYPER_SSE3
156 | hyper_rook_mask[sq] = bb;
157 | #else
158 | hyper_table[sq].filemask = bb;
159 | #endif
160 | }
161 |
162 | #ifdef HYPER_SSE3
163 | xmm1 = _mm_cvtsi64x_si128(0x0001020304050607);
164 | xmm2 = _mm_cvtsi64x_si128(0x08090a0b0c0d0e0f);
165 | hyper_swapmask_xmm = _mm_unpacklo_epi64(xmm1, xmm2);
166 | #endif
167 |
168 | for (i = 0; i < 128; i += 2) {
169 | for (j = 0; j < 8; j++) {
170 | b = 0;
171 | for (d = j + 1; d < 8; d++) {
172 | b |= 1 << d;
173 | if (i & (1 << d)) break;
174 | }
175 | for (d = j - 1; d >= 0; d--) {
176 | b |= 1 << d;
177 | if (i & (1 << d)) break;
178 | }
179 | hyper_rank[4 * i + j] = b;
180 | }
181 | }
182 | }
183 |
184 | #endif
185 |
--------------------------------------------------------------------------------
/src/hyper.h:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2011-2013 Ronald de Man
3 |
4 | This file is distributed under the terms of the GNU GPL, version 2.
5 | */
6 |
7 | #ifndef HYPER_H
8 | #define HYPER_H
9 |
10 | #ifdef HYPER
11 |
12 | #define HYPER_INLINE
13 | #define HYPER_SSE3
14 |
15 | #ifndef HYPER_SSE3
16 | struct Hyper {
17 | bitboard diagmask135;
18 | bitboard diagmask45;
19 | bitboard bitmask;
20 | bitboard filemask;
21 | };
22 |
23 | extern struct Hyper hyper_table[64];
24 | #else
25 | extern bitboard hyper_rook_mask[64];
26 | #endif
27 |
28 | extern ubyte hyper_rank[512];
29 |
30 | #ifdef HYPER_INLINE
31 |
32 | #ifdef HYPER_SSE3
33 | #include
34 |
35 | // from http://chessprogramming.wikispaces.com/SSSE3#SSSE3Version
36 |
37 | __m128i hyper_diagmask_xmm[64];
38 | __m128i hyper_bitmask_xmm[64];
39 | __m128i hyper_swapmask_xmm;
40 |
41 | static __inline__ bitboard BishopRange(int sq, bitboard occ) {
42 | __m128i o, r, m, b, s;
43 |
44 | m = hyper_diagmask_xmm[sq];
45 | b = hyper_bitmask_xmm[sq];
46 | s = hyper_swapmask_xmm;
47 | o = _mm_cvtsi64x_si128(occ);
48 | o = _mm_unpacklo_epi64(o, o);
49 | o = _mm_and_si128(o, m);
50 | r = _mm_shuffle_epi8(o, s);
51 | o = _mm_sub_epi64(o, b);
52 | b = _mm_shuffle_epi8(b, s);
53 | r = _mm_sub_epi64(r, b);
54 | r = _mm_shuffle_epi8(r, s);
55 | o = _mm_xor_si128(o, r);
56 | o = _mm_and_si128(o, m);
57 | r = _mm_unpackhi_epi64(o, o);
58 | o = _mm_add_epi64(o, r);
59 | return _mm_cvtsi128_si64(o);
60 | }
61 | #else
62 | static __inline__ bitboard BishopRange(int sq, bitboard occ)
63 | {
64 | struct Hyper *hyper = &hyper_table[sq];
65 | bitboard diag135, diag45, reverse;
66 |
67 | diag135 = occ & hyper->diagmask135;
68 | reverse = __builtin_bswap64(diag135);
69 | diag135 -= hyper->bitmask;
70 | // reverse -= __builtin_bswap64(hyper->bitmask);
71 | reverse -= bit[sq ^ 0x38];
72 | diag135 ^= __builtin_bswap64(reverse);
73 | diag135 &= hyper->diagmask135;
74 |
75 | diag45 = occ & hyper->diagmask45;
76 | reverse = __builtin_bswap64(diag45);
77 | diag45 -= hyper->bitmask;
78 | // reverse -= __builtin_bswap64(hyper->bitmask);
79 | reverse -= bit[sq ^ 0x38];
80 | diag45 ^= __builtin_bswap64(reverse);
81 | diag45 &= hyper->diagmask45;
82 |
83 | return diag135 | diag45;
84 | }
85 | #endif
86 |
87 | #ifndef HYPER_SSE3
88 | static __inline__ bitboard RookRange(int sq, bitboard occ)
89 | {
90 | struct Hyper *hyper = &hyper_table[sq];
91 | bitboard file, reverse;
92 | bitboard rank;
93 |
94 | file = occ & hyper->filemask;
95 | reverse = __builtin_bswap64(file);
96 | file -= hyper->bitmask;
97 | reverse -= __builtin_bswap64(hyper->bitmask);
98 | file ^= __builtin_bswap64(reverse);
99 | file &= hyper->filemask;
100 |
101 | uint32_t shift = sq & 0x38;
102 | rank = ((bitboard)hyper_rank[4 * ((occ >> shift) & 0x7e) + (sq & 0x07)]) << shift;
103 |
104 | return file | rank;
105 | }
106 | #else
107 | static __inline__ bitboard RookRange(int sq, bitboard occ)
108 | {
109 | bitboard file, reverse, rank;
110 |
111 | file = occ & hyper_rook_mask[sq];
112 | reverse = __builtin_bswap64(file);
113 | file -= bit[sq];
114 | reverse -= bit[sq ^ 0x38];
115 | file ^= __builtin_bswap64(reverse);
116 | file &= hyper_rook_mask[sq];
117 |
118 | uint32_t shift = sq & 0x38;
119 | rank = ((bitboard)hyper_rank[4 * ((occ >> shift) & 0x7e) + (sq & 0x07)]) << shift;
120 |
121 | return file | rank;
122 | }
123 | #endif
124 |
125 | #else
126 | bitboard BishopRange(int sq, bitboard occ) __attribute__ ((pure));
127 | bitboard RookRange(int sq, bitboard occ) __attribute__ ((pure));
128 | #endif
129 |
130 | #define QueenRange(sq,occ) (BishopRange(sq,occ)|RookRange(sq,occ))
131 |
132 | #endif
133 |
134 | #endif
135 |
--------------------------------------------------------------------------------
/src/lz4.h:
--------------------------------------------------------------------------------
1 | /*
2 | LZ4 - Fast LZ compression algorithm
3 | Header File
4 | Copyright (C) 2011-2013, Yann Collet.
5 | BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
6 |
7 | Redistribution and use in source and binary forms, with or without
8 | modification, are permitted provided that the following conditions are
9 | met:
10 |
11 | * Redistributions of source code must retain the above copyright
12 | notice, this list of conditions and the following disclaimer.
13 | * Redistributions in binary form must reproduce the above
14 | copyright notice, this list of conditions and the following disclaimer
15 | in the documentation and/or other materials provided with the
16 | distribution.
17 |
18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 |
30 | You can contact the author at :
31 | - LZ4 homepage : http://fastcompression.blogspot.com/p/lz4.html
32 | - LZ4 source repository : http://code.google.com/p/lz4/
33 | */
34 | #pragma once
35 |
36 | #if defined (__cplusplus)
37 | extern "C" {
38 | #endif
39 |
40 |
41 | //**************************************
42 | // Compiler Options
43 | //**************************************
44 | #if defined(_MSC_VER) && !defined(__cplusplus) // Visual Studio
45 | # define inline __inline // Visual is not C99, but supports some kind of inline
46 | #endif
47 |
48 |
49 | //****************************
50 | // Simple Functions
51 | //****************************
52 |
53 | int LZ4_compress (const char* source, char* dest, int inputSize);
54 | int LZ4_decompress_safe (const char* source, char* dest, int inputSize, int maxOutputSize);
55 |
56 | /*
57 | LZ4_compress() :
58 | Compresses 'inputSize' bytes from 'source' into 'dest'.
59 | Destination buffer must be already allocated,
60 | and must be sized to handle worst cases situations (input data not compressible)
61 | Worst case size evaluation is provided by function LZ4_compressBound()
62 | inputSize : Max supported value is ~1.9GB
63 | return : the number of bytes written in buffer dest
64 | or 0 if the compression fails
65 |
66 | LZ4_decompress_safe() :
67 | maxOutputSize : is the size of the destination buffer (which must be already allocated)
68 | return : the number of bytes decoded in the destination buffer (necessarily <= maxOutputSize)
69 | If the source stream is malformed, the function will stop decoding and return a negative result.
70 | This function never writes outside of output buffer, and never reads outside of input buffer. It is therefore protected against malicious data packets
71 | */
72 |
73 |
74 | //****************************
75 | // Advanced Functions
76 | //****************************
77 |
78 | static inline int LZ4_compressBound(int isize) { return ((isize) + ((isize)/255) + 16); }
79 | #define LZ4_COMPRESSBOUND( isize) ((isize) + ((isize)/255) + 16)
80 |
81 | /*
82 | LZ4_compressBound() :
83 | Provides the maximum size that LZ4 may output in a "worst case" scenario (input data not compressible)
84 | primarily useful for memory allocation of output buffer.
85 | inline function is recommended for the general case,
86 | macro is also provided when result needs to be evaluated at compile time (such as table size allocation).
87 |
88 | isize : is the input size. Max supported value is ~1.9GB
89 | return : maximum output size in a "worst case" scenario
90 | note : this function is limited by "int" range (2^31-1)
91 | */
92 |
93 |
94 | int LZ4_compress_limitedOutput (const char* source, char* dest, int inputSize, int maxOutputSize);
95 |
96 | /*
97 | LZ4_compress_limitedOutput() :
98 | Compress 'inputSize' bytes from 'source' into an output buffer 'dest' of maximum size 'maxOutputSize'.
99 | If it cannot achieve it, compression will stop, and result of the function will be zero.
100 | This function never writes outside of provided output buffer.
101 |
102 | inputSize : Max supported value is ~1.9GB
103 | maxOutputSize : is the size of the destination buffer (which must be already allocated)
104 | return : the number of bytes written in buffer 'dest'
105 | or 0 if the compression fails
106 | */
107 |
108 |
109 | int LZ4_decompress_fast (const char* source, char* dest, int outputSize);
110 |
111 | /*
112 | LZ4_decompress_fast() :
113 | outputSize : is the original (uncompressed) size
114 | return : the number of bytes read from the source buffer (in other words, the compressed size)
115 | If the source stream is malformed, the function will stop decoding and return a negative result.
116 | note : This function is a bit faster than LZ4_decompress_safe()
117 | This function never writes outside of output buffers, and never read before input buffer, but may read beyond input buffer (since it doesn't know its size) in case of malicious data packet.
118 | Use this function preferably into a trusted environment (data to decode comes from a trusted source).
119 | Destination buffer must be already allocated. Its size must be a minimum of 'outputSize' bytes.
120 | */
121 |
122 | int LZ4_decompress_safe_partial (const char* source, char* dest, int inputSize, int targetOutputSize, int maxOutputSize);
123 |
124 | /*
125 | LZ4_decompress_safe_partial() :
126 | This function decompress a compressed block of size 'inputSize' at position 'source'
127 | into output buffer 'dest' of size 'maxOutputSize'.
128 | The function stops decompressing operation as soon as 'targetOutputSize' has been reached,
129 | reducing decompression time.
130 | return : the number of bytes decoded in the destination buffer (necessarily <= maxOutputSize)
131 | Note : this number might be < 'targetOutputSize' if the number of bytes to decode into the compressed block is not enough.
132 | Always control how many bytes were decoded.
133 | If the source stream is malformed, the function will stop decoding and return a negative result.
134 | This function never writes outside of output buffer, and never reads outside of input buffer. It is therefore protected against malicious data packets
135 | */
136 |
137 |
138 | //****************************
139 | // Obsolete Functions
140 | //****************************
141 |
142 | static inline int LZ4_uncompress (const char* source, char* dest, int outputSize) { return LZ4_decompress_fast(source, dest, outputSize); }
143 | static inline int LZ4_uncompress_unknownOutputSize (const char* source, char* dest, int isize, int maxOutputSize) { return LZ4_decompress_safe(source, dest, isize, maxOutputSize); }
144 |
145 | /*
146 | These functions are deprecated and should no longer be used.
147 | They are provided here for compatibility with existing user programs.
148 | */
149 |
150 |
151 |
152 | #if defined (__cplusplus)
153 | }
154 | #endif
155 |
--------------------------------------------------------------------------------
/src/lz4_decoder.h:
--------------------------------------------------------------------------------
1 | /*
2 | LZ4 Decoder - Part of LZ4 compression algorithm
3 | Copyright (C) 2011-2013, Yann Collet.
4 | BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
5 |
6 | Redistribution and use in source and binary forms, with or without
7 | modification, are permitted provided that the following conditions are
8 | met:
9 |
10 | * Redistributions of source code must retain the above copyright
11 | notice, this list of conditions and the following disclaimer.
12 | * Redistributions in binary form must reproduce the above
13 | copyright notice, this list of conditions and the following disclaimer
14 | in the documentation and/or other materials provided with the
15 | distribution.
16 |
17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 |
29 | You can contact the author at :
30 | - LZ4 homepage : http://fastcompression.blogspot.com/p/lz4.html
31 | - LZ4 source repository : http://code.google.com/p/lz4/
32 | */
33 |
34 | /* lz4_decoder.h must be included into lz4.c
35 | The objective of this file is to create a single LZ4 decoder function source
36 | which will be instanciated multiple times with minor variations
37 | depending on a set of #define.
38 | */
39 |
40 |
41 |
42 | //****************************
43 | // Check required defines
44 | //****************************
45 |
46 | #ifndef FUNCTION_NAME
47 | # error "FUNTION_NAME is not defined"
48 | #endif
49 |
50 |
51 | //****************************
52 | // Control tests
53 | //****************************
54 |
55 | #ifdef EXITCONDITION_INPUTSIZE
56 | # define INPUTBUFFER_CONTROL(ip,iend) likely(ip= oexit)
63 | #else
64 | # define OUTPUTTARGET(cpy,oexit) (0)
65 | #endif
66 |
67 |
68 |
69 |
70 | //****************************
71 | // Function code
72 | //****************************
73 |
74 | int FUNCTION_NAME(const char* source,
75 | char* dest,
76 | #ifdef EXITCONDITION_INPUTSIZE
77 | int inputSize,
78 | #endif
79 | #ifdef PARTIAL_DECODING
80 | int targetOutputSize,
81 | #endif
82 | int outputSize
83 | )
84 | {
85 | // Local Variables
86 | const BYTE* restrict ip = (const BYTE*) source;
87 | const BYTE* ref;
88 | #ifdef EXITCONDITION_INPUTSIZE
89 | const BYTE* const iend = ip + inputSize;
90 | #endif
91 |
92 | BYTE* op = (BYTE*) dest;
93 | BYTE* const oend = op + outputSize;
94 | BYTE* cpy;
95 | #ifdef PARTIAL_DECODING
96 | BYTE* const oexit = op + targetOutputSize;
97 | #endif
98 |
99 | size_t dec32table[] = {0, 3, 2, 3, 0, 0, 0, 0};
100 | #if LZ4_ARCH64
101 | size_t dec64table[] = {0, 0, 0, (size_t)-1, 0, 1, 2, 3};
102 | #endif
103 |
104 |
105 | #ifdef EXITCONDITION_INPUTSIZE
106 | // Special case
107 | if unlikely(!inputSize) goto _output_error; // A correctly formed null-compressed LZ4 must have at least one byte (token=0)
108 | #endif
109 |
110 | // Main Loop
111 | while (1)
112 | {
113 | unsigned token;
114 | size_t length;
115 |
116 | // get runlength
117 | token = *ip++;
118 | if ((length=(token>>ML_BITS)) == RUN_MASK)
119 | {
120 | unsigned s=255;
121 | while (INPUTBUFFER_CONTROL(ip,iend) && (s==255))
122 | {
123 | s=*ip++;
124 | length += s;
125 | }
126 | }
127 |
128 | // copy literals
129 | cpy = op+length;
130 | #ifdef EXITCONDITION_INPUTSIZE
131 | if ((cpy>oend-MFLIMIT) || (ip+length>iend-(2+1+LASTLITERALS)) || OUTPUTTARGET(cpy,oexit))
132 | {
133 | if (cpy > oend) goto _output_error; // Error : write attempt beyond end of output buffer
134 | if ((!OUTPUTTARGET(cpy,oexit)) && (ip+length != iend)) goto _output_error; // Error : Must consume all input at this stage, except if reaching TargetOutputSize
135 | #else
136 | if (cpy>oend-COPYLENGTH)
137 | {
138 | if (cpy != oend) goto _output_error; // Error : not enough place for another match (min 4) + 5 literals
139 | #endif
140 | memcpy(op, ip, length);
141 | ip += length;
142 | op += length;
143 | break; // Necessarily EOF, due to parsing restrictions
144 | }
145 | LZ4_WILDCOPY(ip, op, cpy); ip -= (op-cpy); op = cpy;
146 |
147 | // get offset
148 | LZ4_READ_LITTLEENDIAN_16(ref,cpy,ip); ip+=2;
149 | #ifndef PREFIX_64K
150 | if unlikely(ref < (BYTE* const)dest) goto _output_error; // Error : offset outside destination buffer
151 | #endif
152 |
153 | // get matchlength
154 | if ((length=(token&ML_MASK)) == ML_MASK)
155 | {
156 | while INPUTBUFFER_CONTROL(ip,iend-(LASTLITERALS+1)) // A minimum nb of input bytes must remain for LASTLITERALS + token
157 | {
158 | unsigned s = *ip++;
159 | length += s;
160 | if (s==255) continue;
161 | break;
162 | }
163 | }
164 |
165 | // copy repeated sequence
166 | if unlikely((op-ref)oend-(COPYLENGTH)-(STEPSIZE-4))
184 | {
185 | if (cpy > oend-LASTLITERALS) goto _output_error; // Error : last 5 bytes must be literals
186 | LZ4_SECURECOPY(ref, op, (oend-COPYLENGTH));
187 | while(op> ((MINMATCH*8)-HASHLOG))
67 | #define LZ4_HASHVALUE(p) LZ4_HASH(A32(p))
68 |
69 |
70 |
71 | //****************************
72 | // Function code
73 | //****************************
74 |
75 | int FUNCTION_NAME(
76 | #ifdef USE_HEAPMEMORY
77 | void* ctx,
78 | #endif
79 | const char* source,
80 | char* dest,
81 | int inputSize
82 | #ifdef LIMITED_OUTPUT
83 | ,int maxOutputSize
84 | #endif
85 | )
86 | {
87 | #ifdef USE_HEAPMEMORY
88 | CURRENT_H_TYPE* HashTable = (CURRENT_H_TYPE*)ctx;
89 | #else
90 | CURRENT_H_TYPE HashTable[HASHTABLE_NBCELLS] = {0};
91 | #endif
92 |
93 | const BYTE* ip = (BYTE*) source;
94 | CURRENTBASE(base);
95 | const BYTE* anchor = ip;
96 | const BYTE* const iend = ip + inputSize;
97 | const BYTE* const mflimit = iend - MFLIMIT;
98 | #define matchlimit (iend - LASTLITERALS)
99 |
100 | BYTE* op = (BYTE*) dest;
101 | #ifdef LIMITED_OUTPUT
102 | BYTE* const oend = op + maxOutputSize;
103 | #endif
104 |
105 | int length;
106 | const int skipStrength = SKIPSTRENGTH;
107 | U32 forwardH;
108 |
109 |
110 | // Init
111 | if (inputSizeLZ4_64KLIMIT) return 0; // Size too large (not within 64K limit)
114 | #endif
115 | #ifdef USE_HEAPMEMORY
116 | memset((void*)HashTable, 0, HASHTABLESIZE);
117 | #endif
118 |
119 | // First Byte
120 | HashTable[LZ4_HASHVALUE(ip)] = (CURRENT_H_TYPE)(ip - base);
121 | ip++; forwardH = LZ4_HASHVALUE(ip);
122 |
123 | // Main Loop
124 | for ( ; ; )
125 | {
126 | int findMatchAttempts = (1U << skipStrength) + 3;
127 | const BYTE* forwardIp = ip;
128 | const BYTE* ref;
129 | BYTE* token;
130 |
131 | // Find a match
132 | do {
133 | U32 h = forwardH;
134 | int step = findMatchAttempts++ >> skipStrength;
135 | ip = forwardIp;
136 | forwardIp = ip + step;
137 |
138 | if unlikely(forwardIp > mflimit) { goto _last_literals; }
139 |
140 | forwardH = LZ4_HASHVALUE(forwardIp);
141 | ref = base + HashTable[h];
142 | HashTable[h] = (CURRENT_H_TYPE)(ip - base);
143 |
144 | } while ((ref < ip - MAX_DISTANCE) || (A32(ref) != A32(ip)));
145 |
146 | // Catch up
147 | while ((ip>anchor) && (ref>(BYTE*)source) && unlikely(ip[-1]==ref[-1])) { ip--; ref--; }
148 |
149 | // Encode Literal length
150 | length = (int)(ip - anchor);
151 | token = op++;
152 | #ifdef LIMITED_OUTPUT
153 | if unlikely(op + length + (2 + 1 + LASTLITERALS) + (length>>8) > oend) return 0; // Check output limit
154 | #endif
155 | #ifdef _MSC_VER
156 | if (length>=(int)RUN_MASK)
157 | {
158 | int len = length-RUN_MASK;
159 | *token=(RUN_MASK<254)
161 | {
162 | do { *op++ = 255; len -= 255; } while (len>254);
163 | *op++ = (BYTE)len;
164 | memcpy(op, anchor, length);
165 | op += length;
166 | goto _next_match;
167 | }
168 | else
169 | *op++ = (BYTE)len;
170 | }
171 | else *token = (BYTE)(length<=(int)RUN_MASK)
174 | {
175 | int len;
176 | *token=(RUN_MASK< 254 ; len-=255) *op++ = 255;
179 | *op++ = (BYTE)len;
180 | }
181 | else *token = (length<>8) > oend) return 0; // Check output limit
210 | #endif
211 | if (length>=(int)ML_MASK)
212 | {
213 | *token += ML_MASK;
214 | length -= ML_MASK;
215 | for (; length > 509 ; length-=510) { *op++ = 255; *op++ = 255; }
216 | if (length > 254) { length-=255; *op++ = 255; }
217 | *op++ = (BYTE)length;
218 | }
219 | else *token += (BYTE)length;
220 |
221 | // Test end of chunk
222 | if (ip > mflimit) { anchor = ip; break; }
223 |
224 | // Fill table
225 | HashTable[LZ4_HASHVALUE(ip-2)] = (CURRENT_H_TYPE)(ip - 2 - base);
226 |
227 | // Test next position
228 | ref = base + HashTable[LZ4_HASHVALUE(ip)];
229 | HashTable[LZ4_HASHVALUE(ip)] = (CURRENT_H_TYPE)(ip - base);
230 | if ((ref >= ip - MAX_DISTANCE) && (A32(ref) == A32(ip))) { token = op++; *token=0; goto _next_match; }
231 |
232 | // Prepare next loop
233 | anchor = ip++;
234 | forwardH = LZ4_HASHVALUE(ip);
235 | }
236 |
237 | _last_literals:
238 | // Encode Last Literals
239 | {
240 | int lastRun = (int)(iend - anchor);
241 | #ifdef LIMITED_OUTPUT
242 | if (((char*)op - dest) + lastRun + 1 + ((lastRun+255-RUN_MASK)/255) > (U32)maxOutputSize) return 0; // Check output limit
243 | #endif
244 | if (lastRun>=(int)RUN_MASK) { *op++=(RUN_MASK< 254 ; lastRun-=255) *op++ = 255; *op++ = (BYTE) lastRun; }
245 | else *op++ = (BYTE)(lastRun<> shift;
211 | magic[sq].data[j] = bb2;
212 | }
213 | }
214 | }
215 |
216 | void set_up_move_gen(void)
217 | {
218 | init_magics(bishop_init, bishop_magic, m_bishop_dir, 64 - 9);
219 | init_magics(rook_init, rook_magic, m_rook_dir, 64 - 12);
220 | }
221 |
222 | #endif
223 |
--------------------------------------------------------------------------------
/src/magic.h:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2011-2013 Ronald de Man
3 |
4 | This file is distributed under the terms of the GNU GPL, version 2.
5 | */
6 |
7 | #ifndef MAGIC_H
8 | #define MAGIC_H
9 |
10 | #ifdef MAGIC
11 |
12 | extern bitboard attack_table[97264];
13 |
14 | struct Magic {
15 | bitboard *data;
16 | bitboard mask;
17 | uint64_t magic;
18 | };
19 |
20 | extern struct Magic bishop_magic[64];
21 | extern struct Magic rook_magic[64];
22 |
23 | static __inline__ bitboard BishopRange(int sq, bitboard occ)
24 | {
25 | struct Magic *mag = &bishop_magic[sq];
26 | return mag->data[((occ & mag->mask) * mag->magic) >> (64-9)];
27 | }
28 |
29 | static __inline__ bitboard RookRange(int sq, bitboard occ)
30 | {
31 | struct Magic *mag = &rook_magic[sq];
32 | return mag->data[((occ & mag->mask) * mag->magic) >> (64-12)];
33 | }
34 |
35 | #define QueenRange(sq,occ) (BishopRange(sq,occ)|RookRange(sq,occ))
36 |
37 | #endif
38 |
39 | #endif
40 |
--------------------------------------------------------------------------------
/src/permute.h:
--------------------------------------------------------------------------------
1 | #ifndef PERMUTE_H
2 | #define PERMUTE_H
3 |
4 | #include "types.h"
5 |
6 | #define MAX_STEP (1ULL << 30)
7 |
8 | uint64_t init_permute_piece(int *pcs, int *pt);
9 | void init_permute_pawn(int *pcs, int *pt);
10 | uint64_t init_permute_file(int *pcs, int file);
11 | void permute_piece_wdl(u8 *tb_table, int *pcs, int *pt, u8 *table,
12 | uint8_t *best, u8 *v);
13 | uint64_t estimate_piece_dtz_u8(int *pcs, int *pt, u8 *table, uint8_t *best,
14 | int *bestp, u8 *v);
15 | uint64_t estimate_piece_dtz_u16(int *pcs, int *pt, u16 *table, uint8_t *best,
16 | int *bestp, u16 *v);
17 | void permute_piece_dtz_u8(u8 *tb_table, int *pcs, u8 *table, int bestp, u8 *v);
18 | void permute_piece_dtz_u16(u16 *tb_table, int *pcs, u16 *table, int bestp,
19 | u16 *v);
20 | void permute_piece_dtz_u16_full(u16 *tb_table, int *pcs, u16 *table, int bestp,
21 | u16 *v, uint64_t tb_step);
22 | void permute_pawn_wdl(u8 *tb_table, int *pcs, int *pt, u8 *table, uint8_t *best,
23 | int file, u8 *v);
24 | uint64_t estimate_pawn_dtz_u8(int *pcs, int *pt, u8 *table, uint8_t *best,
25 | int *bestp, int file, u8 *v);
26 | uint64_t estimate_pawn_dtz_u16(int *pcs, int *pt, u16 *table, uint8_t *best,
27 | int *bestp, int file, u16 *v);
28 | void permute_pawn_dtz_u8(u8 *tb_table, int *pcs, u8 *table, int bestp, int file,
29 | u8 *v);
30 | void permute_pawn_dtz_u16(u16 *tb_table, int *pcs, u16 *table, int bestp,
31 | int file, u16 *v);
32 | void permute_pawn_dtz_u16_full(u16 *tb_table, int *pcs, u16 *table, int bestp,
33 | int file, u16 *v, uint64_t tb_step);
34 |
35 | #endif
36 |
--------------------------------------------------------------------------------
/src/probe.h:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2011-2016, 2018 Ronald de Man
3 |
4 | This file is distributed under the terms of the GNU GPL, version 2.
5 | */
6 |
7 | #ifndef PROBE_H
8 | #define PROBE_H
9 |
10 | #include "defs.h"
11 | #include "types.h"
12 |
13 | #define TBPIECES 7
14 |
15 | #if defined(SUICIDE)
16 | #if !defined(GIVEAWAY)
17 | #define WDLSUFFIX ".stbw"
18 | #define DTZSUFFIX ".stbz"
19 | #define WDLDIR "STBWDIR"
20 | #define DTZDIR "STBZDIR"
21 | #define STATSDIR "STBSTATSDIR"
22 | #define LOGFILE "stblog.txt"
23 | #else
24 | #define WDLSUFFIX ".gtbw"
25 | #define DTZSUFFIX ".gtbz"
26 | #define WDLDIR "GTBWDIR"
27 | #define DTZDIR "GTBZDIR"
28 | #define STATSDIR "GTBSTATSDIR"
29 | #define LOGFILE "gtblog.txt"
30 | #endif
31 | #elif defined(LOSER)
32 | #define WDLSUFFIX ".ltbw"
33 | #define DTZSUFFIX ".ltbz"
34 | #define WDLDIR "LTBWDIR"
35 | #define DTZDIR "LTBZDIR"
36 | #define STATSDIR "LTBSTATSDIR"
37 | #define LOGFILE "ltblog.txt"
38 | #elif defined(GIVEAWAY)
39 | #define WDLSUFFIX ".gtbw"
40 | #define DTZSUFFIX ".gtbz"
41 | #define WDLDIR "GTBWDIR"
42 | #define DTZDIR "GTBZDIR"
43 | #define STATSDIR "GTBSTATSDIR"
44 | #define LOGFILE "gtblog.txt"
45 | #elif defined(ATOMIC)
46 | #define WDLSUFFIX ".atbw"
47 | #define DTZSUFFIX ".atbz"
48 | #define WDLDIR "ATBWDIR"
49 | #define DTZDIR "ATBZDIR"
50 | #define STATSDIR "ATBSTATSDIR"
51 | #define LOGFILE "atblog.txt"
52 | #elif defined(SHATRANJ)
53 | #define WDLSUFFIX ".jtbw"
54 | #define DTZSUFFIX ".jtbz"
55 | #define WDLDIR "JTBWDIR"
56 | #define DTZDIR "JTBZDIR"
57 | #define STATSDIR "JTBSTATSDIR"
58 | #define LOGFILE "jtblog.txt"
59 | #else
60 | #define WDLSUFFIX ".rtbw"
61 | #define DTZSUFFIX ".rtbz"
62 | #define WDLDIR "RTBWDIR"
63 | #define DTZDIR "RTBZDIR"
64 | #define STATSDIR "RTBSTATSDIR"
65 | #define LOGFILE "rtblog.txt"
66 | #endif
67 |
68 | #define MAX_TBPIECES 8
69 |
70 | #if defined(REGULAR)
71 | #define WDL_MAGIC 0x5d23e871
72 | #define DTZ_MAGIC 0xa50c66d7
73 | #elif defined(ATOMIC)
74 | #define WDL_MAGIC 0x49a48d55
75 | #define DTZ_MAGIC 0xeb5ea991
76 | #elif defined(SHATRANJ)
77 | #define WDL_MAGIC 0xb4e9b3b7
78 | #define DTZ_MAGIC 0x87c126fc
79 | #elif defined(SUICIDE) && !defined(GIVEAWAY)
80 | #define WDL_MAGIC 0x1593f67b
81 | #define DTZ_MAGIC 0x23e7cfe4
82 | #define OTHER_MAGIC 0x21bc55bc
83 | #elif defined(GIVEAWAY)
84 | #define WDL_MAGIC 0x21bc55bc
85 | #define DTZ_MAGIC 0x501bf5d6
86 | #define OTHER_MAGIC 0x1593f67b
87 | #endif
88 |
89 | #ifdef SUICIDE
90 | #define TBHASHBITS 12
91 | #else
92 | #define TBHASHBITS 10
93 | #endif
94 |
95 | struct TBHashEntry;
96 |
97 | struct PairsData {
98 | char *indextable;
99 | uint16_t *sizetable;
100 | uint8_t *data;
101 | uint16_t *offset;
102 | uint8_t *symlen;
103 | uint8_t *sympat;
104 | #ifdef LOOKUP
105 | uint16_t *lookup_len;
106 | uint8_t *lookup_bits;
107 | #endif
108 | int blocksize;
109 | int idxbits;
110 | int min_len;
111 | int max_len; // to allow checking max_len with rtbver/rtbverp
112 | uint64_t base[];
113 | };
114 |
115 | struct TBEntry {
116 | uint8_t *data;
117 | uint32_t key;
118 | uint8_t ready;
119 | uint8_t num;
120 | uint8_t symmetric;
121 | uint8_t has_pawns;
122 | } __attribute__((__may_alias__));
123 |
124 | struct TBEntry_piece {
125 | uint8_t *data;
126 | uint32_t key;
127 | uint8_t ready;
128 | uint8_t num;
129 | uint8_t symmetric;
130 | uint8_t has_pawns;
131 | uint8_t enc_type;
132 | struct PairsData *precomp[2];
133 | uint64_t factor[2][TBPIECES];
134 | uint8_t pieces[2][TBPIECES];
135 | uint8_t norm[2][TBPIECES];
136 | uint8_t order[2];
137 | };
138 |
139 | struct TBEntry_pawn {
140 | uint8_t *data;
141 | uint32_t key;
142 | uint8_t ready;
143 | uint8_t num;
144 | uint8_t symmetric;
145 | uint8_t has_pawns;
146 | uint8_t pawns[2];
147 | struct {
148 | struct PairsData *precomp[2];
149 | uint64_t factor[2][TBPIECES];
150 | uint8_t pieces[2][TBPIECES];
151 | uint8_t norm[2][TBPIECES];
152 | uint8_t order[2];
153 | uint8_t order2[2];
154 | } file[4];
155 | };
156 |
157 | struct TBHashEntry {
158 | uint64_t key;
159 | struct TBEntry *ptr;
160 | };
161 |
162 | int probe_tb(int *pieces, int *pos, int wtm, bitboard occ, int alpha, int beta);
163 |
164 | uint64_t encode_piece(struct TBEntry_piece *ptr, uint8_t *norm, int *pos,
165 | uint64_t *factor);
166 | void decode_piece(struct TBEntry_piece *ptr, uint8_t *norm, int *pos,
167 | uint64_t *factor, int *order, uint64_t idx);
168 | uint64_t encode_pawn(struct TBEntry_pawn *ptr, uint8_t *norm, int *pos,
169 | uint64_t *factor);
170 | void decode_pawn(struct TBEntry_pawn *ptr, uint8_t *norm, int *pos,
171 | uint64_t *factor, int *order, uint64_t idx, int file);
172 |
173 | void set_norm_piece(struct TBEntry_piece *ptr, uint8_t *norm, uint8_t *pieces,
174 | int order);
175 | void set_norm_pawn(struct TBEntry_pawn *ptr, uint8_t *norm, uint8_t *pieces,
176 | int order, int order2);
177 | uint64_t calc_factors_piece(uint64_t *factor, int num, int order,
178 | uint8_t *norm, uint8_t enc_type);
179 | uint64_t calc_factors_pawn(uint64_t *factor, int num, int order, int order2,
180 | uint8_t *norm, int file);
181 |
182 | void calc_order_piece(int num, int ord, int *order, uint8_t *norm);
183 | void calc_order_pawn(int num, int ord, int ord2, int *order, uint8_t *norm);
184 |
185 | #endif
186 |
--------------------------------------------------------------------------------
/src/reduce.c:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2011-2018 Ronald de Man
3 |
4 | This file is distributed under the terms of the GNU GPL, version 2.
5 | */
6 |
7 | #include "util.h"
8 |
9 | static int reduce_cnt;
10 |
11 | static void save_table(uint8_t *table, char color)
12 | {
13 | int i;
14 | FILE *F;
15 | char name[64];
16 | uint8_t v[256];
17 |
18 | sprintf(name, "%s.%c.%d", tablename, color, num_saves);
19 |
20 | if (!(F = fopen(name, "wb"))) {
21 | fprintf(stderr, "Could not open %s for writing.\n", name);
22 | exit(EXIT_FAILURE);
23 | }
24 |
25 | for (i = 0; i < 256; i++)
26 | v[i] = 0;
27 |
28 | #ifndef SUICIDE
29 | if (num_saves == 0) {
30 | v[MATE] = 255;
31 | for (i = 0; i < DRAW_RULE; i++) {
32 | v[WIN_IN_ONE + i] = 1 + i;
33 | v[LOSS_IN_ONE - i] = 254 - i;
34 | }
35 | for (; i < REDUCE_PLY - 2; i++) {
36 | v[WIN_IN_ONE + i + 1] = 1 + DRAW_RULE + (i - DRAW_RULE) / 2;
37 | v[LOSS_IN_ONE - i] = 254 - DRAW_RULE - (i - DRAW_RULE) / 2;
38 | }
39 | v[LOSS_IN_ONE - i] = 254 - DRAW_RULE - (i - DRAW_RULE) / 2;
40 | } else {
41 | for (i = 0; i < REDUCE_PLY_RED; i++) {
42 | v[CAPT_CWIN_RED + i + 2] = 1 + ((reduce_cnt & 1) + i) / 2;
43 | v[LOSS_IN_ONE - i - 1] = 255 - ((reduce_cnt & 1) + i + 1) / 2;
44 | }
45 | }
46 | #else
47 | if (num_saves == 0) {
48 | for (i = 3; i <= DRAW_RULE; i++)
49 | v[BASE_WIN + i] = 1 + (i - 3);
50 | v[BASE_WIN + DRAW_RULE + 1] = DRAW_RULE - 1;
51 | // should we save THREAT_CWIN1/2 (separately) ?
52 | for (i = DRAW_RULE + 2; i < REDUCE_PLY - 1; i++)
53 | v[BASE_WIN + i + 2] = DRAW_RULE - 1 + (i - DRAW_RULE - 1) / 2;
54 | for (i = 2; i <= DRAW_RULE; i++)
55 | v[BASE_LOSS - i] = 255 - (i - 2);
56 | for (; i < REDUCE_PLY; i++)
57 | v[BASE_LOSS - i] = 255 - (DRAW_RULE - 2) - 1 - (i - DRAW_RULE - 1) / 2;
58 | } else {
59 | for (i = 0; i < REDUCE_PLY_RED; i++) {
60 | v[BASE_WIN + i + 6] = 1 + ((reduce_cnt & 1) + i) / 2;
61 | v[BASE_LOSS - i - 4] = 255 - ((reduce_cnt & 1) + i + 1) / 2;
62 | }
63 | }
64 | #endif
65 |
66 | write_data(F, table, 0, size, v);
67 |
68 | fclose(F);
69 | }
70 |
71 | static void reduce_tables(void)
72 | {
73 | int i;
74 | uint8_t v[256];
75 |
76 | collect_stats(0);
77 |
78 | if (generate_dtz) {
79 | save_table(table_w, 'w');
80 | if (!symmetric)
81 | save_table(table_b, 'b');
82 | }
83 |
84 | for (i = 0; i < 256; i++)
85 | v[i] = 0;
86 |
87 | #ifndef SUICIDE
88 | v[BROKEN] = BROKEN;
89 | v[UNKNOWN] = UNKNOWN;
90 | v[CHANGED] = CHANGED;
91 | v[CAPT_DRAW] = CAPT_DRAW;
92 | v[MATE] = MATE;
93 | v[ILLEGAL] = ILLEGAL;
94 | v[CAPT_WIN] = CAPT_WIN;
95 | if (num_saves == 0) {
96 | for (i = 0; i < DRAW_RULE; i++) {
97 | v[WIN_IN_ONE + i] = WIN_IN_ONE;
98 | v[LOSS_IN_ONE - i] = MATE;
99 | }
100 | v[CAPT_CWIN] = CAPT_CWIN_RED;
101 | for (; i < REDUCE_PLY - 2; i++) {
102 | v[WIN_IN_ONE + i + 1] = CAPT_CWIN_RED + 1;
103 | v[LOSS_IN_ONE - i] = LOSS_IN_ONE;
104 | }
105 | v[LOSS_IN_ONE - i] = LOSS_IN_ONE;
106 | v[WIN_IN_ONE + REDUCE_PLY - 1] = CAPT_CWIN_RED + 2;
107 | v[WIN_IN_ONE + REDUCE_PLY] = CAPT_CWIN_RED + 3;
108 | v[WIN_IN_ONE + REDUCE_PLY + 1] = CAPT_CWIN_RED + 4;
109 | v[LOSS_IN_ONE - REDUCE_PLY + 1] = LOSS_IN_ONE - 1;
110 | } else {
111 | v[WIN_IN_ONE] = WIN_IN_ONE;
112 | v[LOSS_IN_ONE] = LOSS_IN_ONE;
113 | v[CAPT_CWIN_RED] = CAPT_CWIN_RED;
114 | v[CAPT_CWIN_RED + 1] = CAPT_CWIN_RED + 1;
115 | for (i = 0; i < REDUCE_PLY_RED; i++) {
116 | v[CAPT_CWIN_RED + i + 2] = CAPT_CWIN_RED + 1;
117 | v[LOSS_IN_ONE - i - 1] = LOSS_IN_ONE;
118 | }
119 | v[CAPT_CWIN_RED + REDUCE_PLY_RED + 2] = CAPT_CWIN_RED + 2;
120 | v[CAPT_CWIN_RED + REDUCE_PLY_RED + 3] = CAPT_CWIN_RED + 3;
121 | v[CAPT_CWIN_RED + REDUCE_PLY_RED + 4] = CAPT_CWIN_RED + 4;
122 | v[LOSS_IN_ONE - REDUCE_PLY_RED - 1] = LOSS_IN_ONE - 1;
123 | }
124 | #else
125 | v[BROKEN] = BROKEN;
126 | v[UNKNOWN] = UNKNOWN;
127 | v[CHANGED] = CHANGED;
128 | v[CAPT_WIN] = CAPT_WIN;
129 | v[CAPT_CWIN] = CAPT_CWIN;
130 | v[CAPT_DRAW] = CAPT_DRAW;
131 | v[CAPT_CLOSS] = CAPT_CLOSS;
132 | v[CAPT_LOSS] = CAPT_LOSS;
133 | v[THREAT_WIN] = THREAT_WIN;
134 | if (num_saves == 0) {
135 | for (i = 3; i <= DRAW_RULE; i++)
136 | v[BASE_WIN + i] = BASE_WIN + 3;
137 | v[THREAT_CWIN1] = BASE_WIN + 4;
138 | v[THREAT_CWIN2] = BASE_WIN + 4;
139 | v[BASE_WIN + DRAW_RULE + 1] = BASE_WIN + 5;
140 | for (i = DRAW_RULE + 2; i < REDUCE_PLY - 1; i++)
141 | v[BASE_WIN + i + 2] = BASE_WIN + 5;
142 | for (i = 2; i <= DRAW_RULE; i++)
143 | v[BASE_LOSS - i] = BASE_LOSS - 2;
144 | for (; i < REDUCE_PLY; i++)
145 | v[BASE_LOSS - i] = BASE_LOSS - 3;
146 | v[BASE_WIN + REDUCE_PLY + 1] = BASE_WIN + 6;
147 | v[BASE_WIN + REDUCE_PLY + 2] = BASE_WIN + 7;
148 | v[BASE_WIN + REDUCE_PLY + 3] = BASE_WIN + 8;
149 | v[BASE_LOSS - REDUCE_PLY] = BASE_LOSS - 4;
150 | } else {
151 | v[BASE_WIN + 3] = BASE_WIN + 3;
152 | v[BASE_WIN + 4] = BASE_WIN + 4;
153 | v[BASE_WIN + 5] = BASE_WIN + 5;
154 | v[BASE_LOSS - 2] = BASE_LOSS - 2;
155 | v[BASE_LOSS - 3] = BASE_LOSS - 3;
156 | for (i = 0; i < REDUCE_PLY_RED; i++) {
157 | v[BASE_WIN + i + 6] = BASE_WIN + 5;
158 | v[BASE_LOSS - i - 4] = BASE_LOSS - 3;
159 | }
160 | v[BASE_WIN + REDUCE_PLY_RED + 6] = BASE_WIN + 6;
161 | v[BASE_WIN + REDUCE_PLY_RED + 7] = BASE_WIN + 7;
162 | v[BASE_WIN + REDUCE_PLY_RED + 8] = BASE_WIN + 8;
163 | v[BASE_LOSS - REDUCE_PLY_RED - 4] = BASE_LOSS - 4;
164 | }
165 | #endif
166 |
167 | transform_v_u8 = v;
168 | run_threaded(transform, work_g, 1);
169 |
170 | if (num_saves == 0)
171 | reduce_cnt = REDUCE_PLY - DRAW_RULE - 2;
172 | else
173 | reduce_cnt += REDUCE_PLY_RED;
174 | }
175 |
176 | static void store_table(uint8_t *table, char color)
177 | {
178 | FILE *F;
179 | char name[64];
180 |
181 | sprintf(name, "%s.%c", tablename, color);
182 |
183 | if (!(F = fopen(name, "wb"))) {
184 | fprintf(stderr, "Could not open %s for writing.\n", name);
185 | exit(EXIT_FAILURE);
186 | }
187 |
188 | write_data(F, table, 0, size, NULL);
189 |
190 | fclose(F);
191 | }
192 |
193 | static void unlink_table(char color)
194 | {
195 | char name[64];
196 |
197 | sprintf(name, "%s.%c", tablename, color);
198 | unlink(name);
199 | }
200 |
201 | static void unlink_saves(char color)
202 | {
203 | char name[64];
204 |
205 | for (int k = 0; k < num_saves; k++) {
206 | sprintf(name, "%s.%c.%d", tablename, color, k);
207 | unlink(name);
208 | }
209 | }
210 |
211 | #define MAX_STAT(x) _Generic((x), \
212 | u8: 256, \
213 | u16: MAX_VALS \
214 | )
215 |
216 | #define T u8
217 | #include "reduce_tmpl.c"
218 | #undef T
219 |
220 | #define T u16
221 | #include "reduce_tmpl.c"
222 | #undef T
223 |
--------------------------------------------------------------------------------
/src/reduce_tmpl.c:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2018 Ronald de Man
3 |
4 | This file is distributed under the terms of the GNU GPL, version 2.
5 | */
6 |
7 | #define NAME(f) EVALUATOR(f,T)
8 |
9 | static void NAME(reconstruct_table_pass)(T *table, char color, int k, T *v)
10 | {
11 | FILE *F;
12 | char name[64];
13 |
14 | sprintf(name, "%s.%c.%d", tablename, color, k);
15 |
16 | if (!(F = fopen(name, "rb"))) {
17 | fprintf(stderr, "Could not open %s for reading.\n", name);
18 | exit(EXIT_FAILURE);
19 | }
20 |
21 | NAME(read_data)(F, table, size, v);
22 |
23 | fclose(F);
24 | }
25 |
26 | static void NAME(verify_stats)(T *table, uint64_t *tot_stats,
27 | struct dtz_map *map)
28 | {
29 | uint64_t stats[MAX_STAT(*table)];
30 | uint64_t stats2[MAX_STAT(*table)];
31 | int i, j;
32 | uint16_t (*inv_map)[MAX_VALS] = map->inv_map;
33 |
34 | for (i = 0; i < MAX_STAT(*table); i++)
35 | stats[i] = stats2[i] = 0;
36 |
37 | for (i = 0; i < MAX_VALS * numthreads; i++)
38 | thread_stats[i] = 0;
39 | NAME(count_stats_table) = table;
40 | run_threaded(NAME(count_stats), work_g, 0);
41 | for (i = 0; i < numthreads; i++)
42 | for (j = 0; j < MAX_STAT(*table); j++)
43 | stats[j] += thread_data[i].stats[j];
44 |
45 | stats2[inv_map[0][0]] = tot_stats[0];
46 | stats2[inv_map[1][0]] = tot_stats[STAT_MATE];
47 | #ifndef SUICIDE
48 | if (map->ply_accurate_win)
49 | for (i = 0; i < DRAW_RULE; i++)
50 | stats2[inv_map[0][i]] += tot_stats[i + 1];
51 | else
52 | for (i = 0; i < DRAW_RULE; i++)
53 | stats2[inv_map[0][i / 2]] += tot_stats[i + 1];
54 | if (map->ply_accurate_loss)
55 | for (i = 0; i < DRAW_RULE; i++)
56 | stats2[inv_map[1][i]] += tot_stats[STAT_MATE - 1 - i];
57 | else
58 | for (i = 0; i < DRAW_RULE; i++)
59 | stats2[inv_map[1][i / 2]] += tot_stats[STAT_MATE - 1 - i];
60 | #else
61 | if (map->ply_accurate_win)
62 | for (i = 2; i < DRAW_RULE; i++)
63 | stats2[inv_map[0][i]] += tot_stats[i + 1];
64 | else
65 | for (i = 2; i < DRAW_RULE; i++)
66 | stats2[inv_map[0][i / 2]] += tot_stats[i + 1];
67 | if (map->ply_accurate_loss)
68 | for (i = 1; i < DRAW_RULE; i++)
69 | stats2[inv_map[1][i]] += tot_stats[1022 - i];
70 | else
71 | for (i = 1; i < DRAW_RULE; i++)
72 | stats2[inv_map[1][i / 2]] += tot_stats[1022 - i];
73 | #endif
74 | for (i = DRAW_RULE + 1; i < MAX_PLY; i++) {
75 | stats2[inv_map[2][(i - DRAW_RULE - 1) / 2]] += tot_stats[i];
76 | stats2[inv_map[3][(i - DRAW_RULE - 1) / 2]] += tot_stats[STAT_MATE - i];
77 | }
78 |
79 | int verify_ok = 1;
80 | for (i = 0; i < MAX_STAT(*table); i++)
81 | if (stats[i] != stats2[i] && i != map->max_num) {
82 | fprintf(stderr, "stats[%d] = %"PRIu64"; stats2[%d] = %"PRIu64"\n",
83 | i, stats[i], i, stats2[i]);
84 | int j;
85 | for (j = 0; j < 4; j++)
86 | fprintf(stderr, "map[%d][%d]=%d\n", j, i, map->map[j][i]);
87 | verify_ok = 0;
88 | }
89 |
90 | if (!verify_ok)
91 | exit(EXIT_FAILURE);
92 | }
93 |
94 | static void NAME(reconstruct_table)(T *table, char color, struct dtz_map *map)
95 | {
96 | int i, k;
97 | int num = map->max_num;
98 | uint16_t (*inv_map)[MAX_VALS] = map->inv_map;
99 | T v[256];
100 |
101 | for (i = 0; i < 256; i++)
102 | v[i] = 0;
103 |
104 | #ifndef SUICIDE
105 | v[ILLEGAL] = num;
106 | v[BROKEN] = num;
107 | v[UNKNOWN] = num;
108 | v[CAPT_DRAW] = num;
109 | v[CAPT_CWIN_RED] = num;
110 | v[CAPT_WIN] = num;
111 | for (i = 0; i <= REDUCE_PLY_RED; i++) {
112 | v[CAPT_CWIN_RED + i + 2] = inv_map[2][(reduce_cnt + i) / 2];
113 | v[LOSS_IN_ONE - i - 1] = inv_map[3][(reduce_cnt + i + 1) / 2];
114 | }
115 | v[CAPT_CWIN_RED + i + 2] = inv_map[2][(reduce_cnt + i) / 2];
116 | #else
117 | v[BROKEN] = num;
118 | v[UNKNOWN] = num;
119 | v[CAPT_WIN] = v[CAPT_CWIN] = v[CAPT_DRAW] = num;
120 | v[CAPT_CLOSS] = v[CAPT_LOSS] = num;
121 | v[THREAT_WIN] = v[BASE_WIN + 4] = v[THREAT_DRAW] = num;
122 | for (i = 0; i <= REDUCE_PLY_RED; i++) {
123 | v[BASE_WIN + i + 6] = inv_map[2][(reduce_cnt + i) / 2];
124 | v[BASE_LOSS - i - 4] = inv_map[3][(reduce_cnt + i + 1) / 2];
125 | }
126 | v[BASE_WIN + i + 6] = inv_map[2][(reduce_cnt + i) / 2];
127 | #endif
128 |
129 | NAME(transform_v) = v;
130 | NAME(transform_tbl) = table;
131 | run_threaded(NAME(transform_table), work_g, 0);
132 |
133 | v[0] = 0;
134 | int red_cnt = 0;
135 | #ifndef SUICIDE
136 | for (k = 0; k < num_saves; k++) {
137 | if (k == 0) {
138 | v[255] = inv_map[1][0];
139 | if (map->ply_accurate_win)
140 | for (i = 0; i < DRAW_RULE; i++)
141 | v[i + 1] = inv_map[0][i];
142 | else
143 | for (i = 0; i < DRAW_RULE; i++)
144 | v[i + 1] = inv_map[0][i / 2];
145 | if (map->ply_accurate_loss)
146 | for (i = 0; i < DRAW_RULE; i++)
147 | v[254 - i] = inv_map[1][i];
148 | else
149 | for (i = 0; i < DRAW_RULE; i++)
150 | v[254 - i] = inv_map[1][i / 2];
151 | for (; i <= REDUCE_PLY; i += 2) {
152 | v[1 + DRAW_RULE + (i - DRAW_RULE) / 2] = inv_map[2][(i - DRAW_RULE) / 2];
153 | v[254 - DRAW_RULE - (i - DRAW_RULE) / 2] = inv_map[3][(i - DRAW_RULE) / 2];
154 | }
155 | red_cnt = REDUCE_PLY - DRAW_RULE - 2;
156 | } else {
157 | for (i = 0; i <= REDUCE_PLY_RED + 1; i += 2) {
158 | v[1 + ((red_cnt & 1) + i) / 2] = inv_map[2][(red_cnt + i) / 2];
159 | v[255 - ((red_cnt & 1) + i + 1) / 2] = inv_map[3][(red_cnt + i + 1) / 2];
160 | }
161 | red_cnt += REDUCE_PLY_RED;
162 | }
163 | NAME(reconstruct_table_pass)(table, color, k, v);
164 | }
165 | #else
166 | for (k = 0; k < num_saves; k++) {
167 | if (k == 0) {
168 | if (map->ply_accurate_win)
169 | for (i = 3; i <= DRAW_RULE; i++)
170 | v[1 + (i - 3)] = inv_map[0][i - 1];
171 | else
172 | for (i = 3; i <= DRAW_RULE; i++)
173 | v[1 + (i - 3)] = inv_map[0][(i - 1) / 2];
174 | if (map->ply_accurate_loss)
175 | for (i = 2; i <= DRAW_RULE; i++)
176 | v[255 - (i - 2)] = inv_map[1][i - 1];
177 | else
178 | for (i = 2; i <= DRAW_RULE; i++)
179 | v[255 - (i - 2)] = inv_map[1][(i - 1) / 2];
180 | for (i = DRAW_RULE + 1; i < REDUCE_PLY; i += 2) {
181 | v[DRAW_RULE - 1 + (i - DRAW_RULE - 1) / 2] = inv_map[2][(i - DRAW_RULE - 1) / 2];
182 | v[254 - (DRAW_RULE - 2) - (i - DRAW_RULE - 1) / 2] = inv_map[3][(i - DRAW_RULE - 1) / 2];
183 | }
184 | red_cnt = REDUCE_PLY - 1 - DRAW_RULE;
185 | } else {
186 | for (i = 0; i < REDUCE_PLY_RED; i += 2) {
187 | v[1 + ((red_cnt & 1) + i) / 2] = inv_map[2][(red_cnt + i) / 2];
188 | v[255 - ((red_cnt & 1) + i + 1) / 2] = inv_map[3][(red_cnt + i + 1) / 2];
189 | }
190 | red_cnt += REDUCE_PLY_RED;
191 | }
192 | NAME(reconstruct_table_pass)(table, color, k, v);
193 | }
194 | #endif
195 |
196 | if (color == 'w') {
197 | printf("Verifying reconstructed table_w based on collected statistics.\n");
198 | NAME(verify_stats)(table, total_stats_w, map);
199 | } else {
200 | printf("Verifying reconstructed table_b based on collected statistics.\n");
201 | NAME(verify_stats)(table, total_stats_b, map);
202 | }
203 | }
204 |
205 | static void NAME(load_table)(T *table, char color)
206 | {
207 | FILE *F;
208 | char name[64];
209 |
210 | sprintf(name, "%s.%c", tablename, color);
211 |
212 | if (!(F = fopen(name, "rb"))) {
213 | fprintf(stderr, "Could not open %s for reading.\n", name);
214 | exit(EXIT_FAILURE);
215 | }
216 |
217 | NAME(read_data)(F, table, size, NULL);
218 |
219 | fclose(F);
220 | }
221 |
--------------------------------------------------------------------------------
/src/reducep.c:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2011-2016, 2018 Ronald de Man
3 |
4 | This file is distributed under the terms of the GNU GPL, version 2.
5 | */
6 |
7 | #include "util.h"
8 |
9 | #define MAX_SAVES 32
10 |
11 | void reduce_tables(int local);
12 | void count_stats(struct thread_data *thread);
13 | void collect_stats(uint64_t *work, int phase, int local);
14 |
15 | static FILE *tmp_table[MAX_SAVES][2];
16 | static int reduce_cnt[MAX_SAVES];
17 | static int stats_val[MAX_SAVES];
18 | static int reduce_val[MAX_SAVES];
19 |
20 | void save_table(uint8_t *table, char color, int local, uint64_t begin,
21 | uint64_t size)
22 | {
23 | int i;
24 | FILE *F;
25 | char name[64];
26 | uint8_t v[256];
27 |
28 | if (local == num_saves) {
29 | sprintf(name, "%s.%c.%d", tablename, color, num_saves);
30 | if (!(F = fopen(name, "wb"))) {
31 | fprintf(stderr, "Could not open %s for writing.\n", name);
32 | exit(1);
33 | }
34 | tmp_table[num_saves][color == 'w' ? 0 : 1] = F;
35 | } else {
36 | F = tmp_table[local][color == 'w' ? 0 : 1];
37 | }
38 |
39 | for (i = 0; i < 256; i++)
40 | v[i] = 0;
41 |
42 | #ifndef SUICIDE
43 | if (local == 0) {
44 | v[MATE] = 255;
45 | v[PAWN_WIN] = v[PAWN_CWIN] = 1;
46 | for (i = 0; i < DRAW_RULE; i++) {
47 | v[WIN_IN_ONE + i] = 2 + i;
48 | v[LOSS_IN_ONE - i] = 254 - i;
49 | }
50 | for (; i < REDUCE_PLY - 2; i++) {
51 | v[WIN_IN_ONE + i + 2] = 2 + DRAW_RULE + (i - DRAW_RULE) / 2;
52 | v[LOSS_IN_ONE - i] = 254 - DRAW_RULE - (i - DRAW_RULE) / 2;
53 | }
54 | v[LOSS_IN_ONE - i] = 254 - DRAW_RULE - (i - DRAW_RULE) / 2;
55 | } else {
56 | for (i = 0; i < REDUCE_PLY_RED; i++) {
57 | v[CAPT_CWIN_RED + i + 2] = 1 + ((reduce_cnt[local - 1] & 1) + i) / 2;
58 | v[LOSS_IN_ONE - i - 1] = 255 - ((reduce_cnt[local - 1] & 1) + i + 1) / 2;
59 | }
60 | }
61 | #else
62 | if (local == 0) {
63 | v[STALE_WIN] = 1;
64 | v[STALE_WIN + 1] = 2;
65 | for (i = 2; i <= DRAW_RULE; i++)
66 | v[BASE_WIN + i] = 1 + i;
67 | for (i = 0; i <= DRAW_RULE; i++)
68 | v[BASE_LOSS - i] = 255 - i;
69 | v[BASE_WIN + DRAW_RULE + 1] = 1 + DRAW_RULE + 1;
70 | for (i = DRAW_RULE + 2; i < REDUCE_PLY - 1; i++)
71 | v[BASE_WIN + i + 2] = 2 + DRAW_RULE + (i - DRAW_RULE - 1) / 2;
72 | for (i = DRAW_RULE + 1; i < REDUCE_PLY; i++)
73 | v[BASE_LOSS - i] = 255 - DRAW_RULE - 1 - (i - DRAW_RULE - 1) / 2;
74 | } else {
75 | for (i = 0; i < REDUCE_PLY_RED; i++) {
76 | v[BASE_CWIN_RED + i + 1] = 1 + ((reduce_cnt[local - 1] & 1) + i) / 2;
77 | v[BASE_CLOSS_RED - i - 1] = 255 - ((reduce_cnt[local - 1] & 1) + i + 1) / 2;
78 | }
79 | }
80 | #endif
81 |
82 | write_data(F, table, begin, size, v);
83 | }
84 |
85 | void reduce_tables(int local)
86 | {
87 | int i;
88 | uint8_t v[256];
89 | uint64_t *work;
90 | uint64_t save_begin = begin;
91 |
92 | if (local == num_saves) {
93 | work = work_part;
94 | fill_work(total_work, begin + (1ULL << shift[numpawns - 1]), 0, work);
95 | begin = 0;
96 | reduce_val[local] = ply;
97 | work = work_part;
98 | } else
99 | work = work_p;
100 |
101 | collect_stats(work, 0, local);
102 |
103 | if (generate_dtz) {
104 | save_table(table_w, 'w', local, begin, work[total_work]);
105 | if (!symmetric)
106 | save_table(table_b, 'b', local, begin, work[total_work]);
107 | }
108 |
109 | for (i = 0; i < 256; i++)
110 | v[i] = 0;
111 |
112 | #ifndef SUICIDE
113 | v[BROKEN] = BROKEN;
114 | v[UNKNOWN] = UNKNOWN;
115 | v[CHANGED] = CHANGED;
116 | v[CAPT_DRAW] = CAPT_DRAW;
117 | v[PAWN_DRAW] = PAWN_DRAW;
118 | v[MATE] = MATE;
119 | v[ILLEGAL] = ILLEGAL;
120 | v[CAPT_WIN] = CAPT_WIN;
121 | if (local == 0) {
122 | v[PAWN_WIN] = WIN_RED;
123 | for (i = 0; i < DRAW_RULE; i++) {
124 | v[WIN_IN_ONE + i] = WIN_RED;
125 | v[LOSS_IN_ONE - i] = MATE;
126 | }
127 | v[CAPT_CWIN] = CAPT_CWIN_RED;
128 | v[PAWN_CWIN] = CAPT_CWIN_RED + 1;
129 | for (; i < REDUCE_PLY - 2; i++) {
130 | v[WIN_IN_ONE + i + 2] = CAPT_CWIN_RED + 1;
131 | v[LOSS_IN_ONE - i] = LOSS_IN_ONE;
132 | }
133 | v[LOSS_IN_ONE - i] = LOSS_IN_ONE;
134 | v[WIN_IN_ONE + REDUCE_PLY] = CAPT_CWIN_RED + 2;
135 | v[WIN_IN_ONE + REDUCE_PLY + 1] = CAPT_CWIN_RED + 3;
136 | v[WIN_IN_ONE + REDUCE_PLY + 2] = CAPT_CWIN_RED + 4;
137 | v[LOSS_IN_ONE - REDUCE_PLY + 1] = LOSS_IN_ONE - 1;
138 | } else {
139 | v[WIN_RED] = WIN_RED;
140 | v[LOSS_IN_ONE] = LOSS_IN_ONE;
141 | v[CAPT_CWIN_RED] = CAPT_CWIN_RED;
142 | v[CAPT_CWIN_RED + 1] = CAPT_CWIN_RED + 1;
143 | for (i = 0; i < REDUCE_PLY_RED; i++) {
144 | v[CAPT_CWIN_RED + i + 2] = CAPT_CWIN_RED + 1;
145 | v[LOSS_IN_ONE - i - 1] = LOSS_IN_ONE;
146 | }
147 | v[CAPT_CWIN_RED + REDUCE_PLY_RED + 2] = CAPT_CWIN_RED + 2;
148 | v[CAPT_CWIN_RED + REDUCE_PLY_RED + 3] = CAPT_CWIN_RED + 3;
149 | v[CAPT_CWIN_RED + REDUCE_PLY_RED + 4] = CAPT_CWIN_RED + 4;
150 | v[LOSS_IN_ONE - REDUCE_PLY_RED - 1] = LOSS_IN_ONE - 1;
151 | }
152 | #else
153 | v[BROKEN] = BROKEN;
154 | v[UNKNOWN] = UNKNOWN;
155 | v[CHANGED] = CHANGED;
156 | v[CAPT_WIN] = CAPT_WIN;
157 | v[CAPT_CWIN] = CAPT_CWIN;
158 | v[CAPT_DRAW] = CAPT_DRAW;
159 | v[CAPT_CLOSS] = CAPT_CLOSS;
160 | v[CAPT_LOSS] = CAPT_LOSS;
161 | v[PAWN_DRAW] = PAWN_DRAW;
162 | if (local == 0) {
163 | v[THREAT_WIN1] = THREAT_WIN_RED;
164 | v[THREAT_WIN2] = THREAT_WIN_RED;
165 | v[STALE_WIN] = BASE_WIN_RED;
166 | v[STALE_WIN + 1] = BASE_WIN_RED;
167 | for (i = 2; i <= DRAW_RULE; i++)
168 | v[BASE_WIN + i] = BASE_WIN_RED;
169 | v[THREAT_CWIN1] = THREAT_CWIN_RED;
170 | v[THREAT_CWIN2] = THREAT_CWIN_RED;
171 | v[BASE_WIN + DRAW_RULE + 1] = BASE_CWIN_RED;
172 | for (i = DRAW_RULE + 2; i < REDUCE_PLY - 1; i++)
173 | v[BASE_WIN + i + 2] = BASE_CWIN_RED;
174 | for (i = 0; i <= DRAW_RULE; i++)
175 | v[BASE_LOSS - i] = BASE_LOSS_RED;
176 | for (; i < REDUCE_PLY; i++)
177 | v[BASE_LOSS - i] = BASE_CLOSS_RED;
178 | v[BASE_WIN + REDUCE_PLY + 1] = BASE_CWIN_RED + 1;
179 | v[BASE_WIN + REDUCE_PLY + 2] = BASE_CWIN_RED + 2;
180 | v[BASE_WIN + REDUCE_PLY + 3] = BASE_CWIN_RED + 3;
181 | v[BASE_LOSS - REDUCE_PLY] = BASE_CLOSS_RED - 1;
182 | } else {
183 | v[THREAT_WIN_RED] = THREAT_WIN_RED;
184 | v[BASE_WIN_RED] = BASE_WIN_RED;
185 | v[THREAT_CWIN_RED] = THREAT_CWIN_RED;
186 | v[BASE_CWIN_RED] = BASE_CWIN_RED;
187 | v[BASE_LOSS_RED] = BASE_LOSS_RED;
188 | v[BASE_CLOSS_RED] = BASE_CLOSS_RED;
189 | for (i = 0; i < REDUCE_PLY_RED; i++) {
190 | v[BASE_CWIN_RED + i + 1] = BASE_CWIN_RED;
191 | v[BASE_CLOSS_RED - i - 1] = BASE_CLOSS_RED;
192 | }
193 | v[BASE_CWIN_RED + REDUCE_PLY_RED + 1] = BASE_CWIN_RED + 1;
194 | v[BASE_CWIN_RED + REDUCE_PLY_RED + 2] = BASE_CWIN_RED + 2;
195 | v[BASE_CWIN_RED + REDUCE_PLY_RED + 3] = BASE_CWIN_RED + 3;
196 | v[BASE_CLOSS_RED - REDUCE_PLY_RED - 1] = BASE_CLOSS_RED - 1;
197 | }
198 | #endif
199 |
200 | transform_v_u8 = v;
201 | run_threaded(transform, work, 0);
202 |
203 | if (local == num_saves) {
204 | if (num_saves == 0)
205 | reduce_cnt[0] = ply - DRAW_RULE - 2;
206 | else
207 | reduce_cnt[num_saves] = reduce_cnt[num_saves - 1] + ply;
208 | begin = save_begin;
209 | num_saves++;
210 | }
211 | }
212 |
213 | void store_table(uint8_t *table, char color)
214 | {
215 | FILE *F;
216 | char name[64];
217 |
218 | sprintf(name, "%s.%c", tablename, color);
219 |
220 | if (!(F = fopen(name, "wb"))) {
221 | fprintf(stderr, "Could not open %s for writing.\n", name);
222 | exit(1);
223 | }
224 |
225 | write_data(F, table, 0, size, NULL);
226 |
227 | fclose(F);
228 | }
229 |
230 | void unlink_table(char color)
231 | {
232 | char name[64];
233 |
234 | sprintf(name, "%s.%c", tablename, color);
235 | unlink(name);
236 | }
237 |
238 | void unlink_saves(char color)
239 | {
240 | char name[64];
241 |
242 | for (int k = 0; k < num_saves; k++) {
243 | sprintf(name, "%s.%c.%d", tablename, color, k);
244 | unlink(name);
245 | }
246 | }
247 |
248 | #define MAX_STAT(x) _Generic((x), \
249 | u8: 256, \
250 | u16: MAX_VALS \
251 | )
252 |
253 | #define T u8
254 | #include "reducep_tmpl.c"
255 | #undef T
256 |
257 | #define T u16
258 | #include "reducep_tmpl.c"
259 | #undef T
260 |
--------------------------------------------------------------------------------
/src/reducep_tmpl.c:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2018 Ronald de Man
3 |
4 | This file is distributed under the terms of the GNU GPL, version 2.
5 | */
6 |
7 | #define NAME(f) EVALUATOR(f,T)
8 |
9 | void NAME(reconstruct_table_pass)(T *table, char color, int k, T *v)
10 | {
11 | FILE *F;
12 | char name[64];
13 |
14 | sprintf(name, "%s.%c.%d", tablename, color, k);
15 |
16 | if (!(F = fopen(name, "rb"))) {
17 | fprintf(stderr, "Could not open %s for writing.\n", name);
18 | exit(1);
19 | }
20 |
21 | NAME(read_data)(F, table, size, v);
22 |
23 | fclose(F);
24 | }
25 |
26 | void NAME(verify_stats)(T *table, uint64_t *tot_stats, struct dtz_map *map)
27 | {
28 | uint64_t stats[MAX_STAT(*table)];
29 | uint64_t stats2[MAX_STAT(*table)];
30 | int i, j;
31 | uint16_t (*inv_map)[MAX_VALS] = map->inv_map;
32 |
33 | for (i = 0; i < MAX_STAT(*table); i++)
34 | stats[i] = stats2[i] = 0;
35 |
36 | for (i = 0; i < MAX_VALS * numthreads; i++)
37 | thread_stats[i] = 0;
38 | NAME(count_stats_table) = table;
39 | run_threaded(NAME(count_stats), work_g, 0);
40 | for (i = 0; i < numthreads; i++)
41 | for (j = 0; j < MAX_STAT(*table); j++)
42 | stats[j] += thread_data[i].stats[j];
43 |
44 | stats2[inv_map[0][0]] = tot_stats[0];
45 | stats2[inv_map[1][0]] += tot_stats[STAT_MATE];
46 | if (map->ply_accurate_win)
47 | for (i = 0; i < DRAW_RULE; i++)
48 | stats2[inv_map[0][i]] += tot_stats[i + 1];
49 | else
50 | for (i = 0; i < DRAW_RULE; i++)
51 | stats2[inv_map[0][i / 2]] += tot_stats[i + 1];
52 | if (map->ply_accurate_loss)
53 | for (i = 0; i < DRAW_RULE; i++)
54 | stats2[inv_map[1][i]] += tot_stats[STAT_MATE - 1 - i];
55 | else
56 | for (i = 0; i < DRAW_RULE; i++)
57 | stats2[inv_map[1][i / 2]] += tot_stats[STAT_MATE - 1 - i];
58 | for (i = DRAW_RULE + 1; i < MAX_PLY; i++) {
59 | stats2[inv_map[2][(i - DRAW_RULE - 1) / 2]] += tot_stats[i];
60 | stats2[inv_map[3][(i - DRAW_RULE - 1) / 2]] += tot_stats[STAT_MATE - i];
61 | }
62 |
63 | int verify_ok = 1;
64 | for (i = 0; i < MAX_STAT(*table); i++)
65 | if (stats[i] != stats2[i] && i != map->max_num) {
66 | fprintf(stderr, "stats[%d] = %"PRIu64"; stats2[%d] = %"PRIu64"\n",
67 | i, stats[i], i, stats2[i]);
68 | int j;
69 | for (j = 0; j < 4; j++)
70 | fprintf(stderr, "map[%d][%d]=%d\n", j, i, map->map[j][i]);
71 | verify_ok = 0;
72 | }
73 |
74 | if (!verify_ok)
75 | exit(EXIT_FAILURE);
76 | }
77 |
78 | void NAME(reconstruct_table)(T *table, char color, struct dtz_map *map)
79 | {
80 | int i, k;
81 | int num = map->max_num;
82 | uint16_t (*inv_map)[MAX_VALS] = map->inv_map;
83 | T v[256];
84 |
85 | for (i = 0; i < 256; i++)
86 | v[i] = 0;
87 |
88 | #ifndef SUICIDE
89 | v[ILLEGAL] = num;
90 | v[BROKEN] = num;
91 | v[UNKNOWN] = num;
92 | v[PAWN_DRAW] = num;
93 | v[CAPT_DRAW] = num;
94 | v[CAPT_CWIN_RED] = num;
95 | v[CAPT_WIN] = num;
96 | for (i = 0; i <= REDUCE_PLY_RED; i++) {
97 | v[CAPT_CWIN_RED + i + 2] = inv_map[2][(reduce_cnt[num_saves - 1] + i) / 2];
98 | v[LOSS_IN_ONE - i - 1] = inv_map[3][(reduce_cnt[num_saves - 1] + i + 1) / 2];
99 | }
100 | v[CAPT_CWIN_RED + i + 2] = inv_map[2][(reduce_cnt[num_saves - 1] + i) / 2];
101 | #else
102 | v[BROKEN] = num;
103 | v[UNKNOWN] = v[PAWN_DRAW] = num;
104 | v[CAPT_WIN] = v[CAPT_CWIN] = v[CAPT_DRAW] = num;
105 | v[CAPT_CLOSS] = v[CAPT_LOSS] = num;
106 | v[THREAT_WIN_RED] = v[THREAT_CWIN_RED] = v[THREAT_DRAW] = num;
107 | // FIXME: add THREAT_CLOSS
108 | for (i = 0; i <= REDUCE_PLY_RED; i++) {
109 | v[BASE_CWIN_RED + i + 1] = inv_map[2][(reduce_cnt[num_saves - 1] + i) / 2];
110 | v[BASE_CLOSS_RED - i - 1] = inv_map[3][(reduce_cnt[num_saves - 1] + i + 1) / 2];
111 | }
112 | v[BASE_CWIN_RED + i + 1] = inv_map[2][(reduce_cnt[num_saves -1] + i) / 2];
113 | #endif
114 |
115 | begin = 0;
116 | NAME(transform_v) = v;
117 | NAME(transform_tbl) = table;
118 | run_threaded(NAME(transform_table), work_g, 0);
119 |
120 | v[0] = 0;
121 | int red_cnt = 0;
122 | #ifndef SUICIDE
123 | for (k = 0; k < num_saves; k++) {
124 | if (k == 0) {
125 | v[255] = inv_map[1][0];
126 | v[1] = num;
127 | if (map->ply_accurate_win)
128 | for (i = 0; i < DRAW_RULE; i++)
129 | v[i + 2] = inv_map[0][i];
130 | else
131 | for (i = 0; i < DRAW_RULE; i++)
132 | v[i + 2] = inv_map[0][i / 2];
133 | if (map->ply_accurate_loss)
134 | for (i = 0; i < DRAW_RULE; i++)
135 | v[254 - i] = inv_map[1][i];
136 | else
137 | for (i = 0; i < DRAW_RULE; i++)
138 | v[254 - i] = inv_map[1][i / 2];
139 | for (; i <= REDUCE_PLY; i += 2) {
140 | v[2 + DRAW_RULE + (i - DRAW_RULE) / 2] = inv_map[2][(i - DRAW_RULE) / 2];
141 | v[254 - DRAW_RULE - (i - DRAW_RULE) / 2] = inv_map[3][(i - DRAW_RULE) / 2];
142 | }
143 | red_cnt = REDUCE_PLY - DRAW_RULE - 2;
144 | } else {
145 | for (i = 0; i <= REDUCE_PLY_RED + 1; i += 2) {
146 | v[1 + ((red_cnt & 1) + i) / 2] = inv_map[2][(red_cnt + i) / 2];
147 | v[255 - ((red_cnt & 1) + i + 1) / 2] = inv_map[3][(red_cnt + i + 1) / 2];
148 | }
149 | red_cnt += REDUCE_PLY_RED;
150 | }
151 | NAME(reconstruct_table_pass)(table, color, k, v);
152 | }
153 | #else
154 | for (k = 0; k < num_saves; k++) {
155 | if (k == 0) {
156 | v[1] = inv_map[0][0];
157 | if (map->ply_accurate_win)
158 | for (i = 1; i <= DRAW_RULE; i++)
159 | v[1 + i] = inv_map[0][i - 1];
160 | else
161 | for (i = 1; i <= DRAW_RULE; i++)
162 | v[1 + i] = inv_map[0][(i - 1) / 2];
163 | v[255] = inv_map[1][0];
164 | if (map->ply_accurate_loss)
165 | for (i = 1; i <= DRAW_RULE; i++)
166 | v[255 - i] = inv_map[1][i - 1];
167 | else
168 | for (i = 1; i <= DRAW_RULE; i++)
169 | v[255 - i] = inv_map[1][(i - 1) / 2];
170 | for (i = DRAW_RULE + 1; i < REDUCE_PLY; i += 2) {
171 | v[2 + DRAW_RULE + (i - DRAW_RULE - 1) / 2] = inv_map[2][(i - DRAW_RULE - 1) / 2];
172 | v[254 - DRAW_RULE - (i - DRAW_RULE - 1) / 2] = inv_map[3][(i - DRAW_RULE - 1) / 2];
173 | }
174 | red_cnt = REDUCE_PLY - 1 - DRAW_RULE;
175 | } else {
176 | for (i = 0; i < REDUCE_PLY_RED; i += 2) {
177 | v[1 + ((red_cnt & 1) + i) / 2] = inv_map[2][(red_cnt + i) / 2];
178 | v[255 - ((red_cnt & 1) + i + 1) / 2] = inv_map[3][(red_cnt + i + 1) / 2];
179 | }
180 | red_cnt += REDUCE_PLY_RED;
181 | }
182 | NAME(reconstruct_table_pass)(table, color, k, v);
183 | }
184 | #endif
185 |
186 | if (color == 'w') {
187 | printf("Verifying reconstructed table_w based on collected statistics.\n");
188 | NAME(verify_stats)(table, total_stats_w, map);
189 | } else {
190 | printf("Verifying reconstructed table_b based on collected statistics.\n");
191 | NAME(verify_stats)(table, total_stats_b, map);
192 | }
193 | }
194 |
195 | void NAME(load_table)(T *table, char color)
196 | {
197 | FILE *F;
198 | char name[64];
199 |
200 | sprintf(name, "%s.%c", tablename, color);
201 |
202 | if (!(F = fopen(name, "rb"))) {
203 | fprintf(stderr, "Could not open %s for reading.\n", name);
204 | exit(1);
205 | }
206 |
207 | NAME(read_data)(F, table, size, NULL);
208 |
209 | fclose(F);
210 | }
211 |
212 | #undef NAME
213 |
--------------------------------------------------------------------------------
/src/run.pl:
--------------------------------------------------------------------------------
1 | #!/usr/bin/perl
2 |
3 | $ENV{'RTBWDIR'} = '.';
4 |
5 | use Getopt::Long;
6 |
7 | $threads = 1;
8 | $generate = '';
9 | $verify = '';
10 | $disk = '';
11 | $min = 3;
12 | $max = 4;
13 | GetOptions('threads=i' => \$threads,
14 | 'generate' => \$generate,
15 | 'verify' => \$verify,
16 | 'huffman' => \$huffman,
17 | 'min=i' => \$min,
18 | 'max=i' => \$max,
19 | 'disk' => \$disk);
20 |
21 | sub Process {
22 | my($tb) = @_;
23 | my $len = length($tb) - 1;
24 | if ($len < $min || $len > $max) { return; }
25 | $dopt = "";
26 | if ($disk && $len == $max) {
27 | $dopt = "-d ";
28 | }
29 | if ($generate && !-e $tb.".rtbz") {
30 | print "Generating $tb\n";
31 | if ($tb !~ /.*P.*/) {
32 | system "rtbgen $dopt-t $threads --stats $tb";
33 | } else {
34 | system "rtbgenp $dopt-t $threads --stats $tb";
35 | }
36 | }
37 | if ($verify) {
38 | printf "Verifying $tb\n";
39 | if ($tb !~ /.*P.*/) {
40 | system "rtbver -t $threads --log $tb";
41 | } else {
42 | system "rtbverp -t $threads --log $tb";
43 | }
44 | }
45 | if ($huffman && -e $tb.".rtbw") {
46 | if ($tb !~ /.*P.*/) {
47 | system "rtbver -h $tb";
48 | } else {
49 | system "rtbverp -h $tb";
50 | }
51 | }
52 | }
53 |
54 | @Pieces = ('Q', 'R', 'B', 'N', 'P');
55 |
56 | for ($i = 0; $i < 5; ++$i) {
57 | $a = @Pieces[$i];
58 | $tb = "K".$a."v"."K";
59 | Process($tb);
60 | }
61 |
62 | for ($i = 0; $i < 5; ++$i) {
63 | $a = @Pieces[$i];
64 | for ($j = $i; $j < 5; ++$j) {
65 | $b = @Pieces[$j];
66 | $tb = "K".$a.$b."v"."K";
67 | Process($tb);
68 | }
69 | }
70 |
71 | for ($i = 0; $i < 5; ++$i) {
72 | $a = @Pieces[$i];
73 | for ($j = $i; $j < 5; ++$j) {
74 | $b = @Pieces[$j];
75 | $tb = "K".$a."v"."K".$b;
76 | Process($tb);
77 | }
78 | }
79 |
80 | for ($i = 0; $i < 5; ++$i) {
81 | $a = @Pieces[$i];
82 | for ($j = $i; $j < 5; ++$j) {
83 | $b = @Pieces[$j];
84 | for ($k = $j; $k < 5; ++$k) {
85 | $c = @Pieces[$k];
86 | $tb = "K".$a.$b.$c."v"."K";
87 | Process($tb);
88 | }
89 | }
90 | }
91 |
92 | for ($i = 0; $i < 5; ++$i) {
93 | $a = @Pieces[$i];
94 | for ($j = $i; $j < 5; ++$j) {
95 | $b = @Pieces[$j];
96 | for ($k = 0; $k < 5; ++$k) {
97 | $c = @Pieces[$k];
98 | $tb = "K".$a.$b."v"."K".$c;
99 | Process($tb);
100 | }
101 | }
102 | }
103 |
104 | for ($i = 0; $i < 5; ++$i) {
105 | $a = @Pieces[$i];
106 | for ($j = $i; $j < 5; ++$j) {
107 | $b = @Pieces[$j];
108 | for ($k = $j; $k < 5; ++$k) {
109 | $c = @Pieces[$k];
110 | for ($l = $k; $l < 5; ++$l) {
111 | $d = @Pieces[$l];
112 | $tb = "K".$a.$b.$c.$d."v"."K";
113 | Process($tb);
114 | }
115 | }
116 | }
117 | }
118 |
119 | for ($i = 0; $i < 5; ++$i) {
120 | $a = @Pieces[$i];
121 | for ($j = $i; $j < 5; ++$j) {
122 | $b = @Pieces[$j];
123 | for ($k = $j; $k < 5; ++$k) {
124 | $c = @Pieces[$k];
125 | for ($l = 0; $l < 5; ++$l) {
126 | $d = @Pieces[$l];
127 | $tb = "K".$a.$b.$c."v"."K".$d;
128 | Process($tb);
129 | }
130 | }
131 | }
132 | }
133 |
134 | for ($i = 0; $i < 5; ++$i) {
135 | $a = @Pieces[$i];
136 | for ($j = $i; $j < 5; ++$j) {
137 | $b = @Pieces[$j];
138 | for ($k = $i; $k < 5; ++$k) {
139 | $c = @Pieces[$k];
140 | for ($l = ($i == $k) ? $j : $k; $l < 5; ++$l) {
141 | $d = @Pieces[$l];
142 | $tb = "K".$a.$b."v"."K".$c.$d;
143 | Process($tb);
144 | }
145 | }
146 | }
147 | }
148 |
149 | for ($i = 0; $i < 5; ++$i) {
150 | $a = @Pieces[$i];
151 | for ($j = $i; $j < 5; ++$j) {
152 | $b = @Pieces[$j];
153 | for ($k = $j; $k < 5; ++$k) {
154 | $c = @Pieces[$k];
155 | for ($l = $k; $l < 5; ++$l) {
156 | $d = @Pieces[$l];
157 | for ($m = $l; $m < 5; ++$m) {
158 | $e = @Pieces[$m];
159 | $tb = "K".$a.$b.$c.$d.$e."v"."K";
160 | Process($tb);
161 | }
162 | }
163 | }
164 | }
165 | }
166 |
167 | for ($i = 0; $i < 5; ++$i) {
168 | $a = @Pieces[$i];
169 | for ($j = $i; $j < 5; ++$j) {
170 | $b = @Pieces[$j];
171 | for ($k = $j; $k < 5; ++$k) {
172 | $c = @Pieces[$k];
173 | for ($l = $k; $l < 5; ++$l) {
174 | $d = @Pieces[$l];
175 | for ($m = 0; $m < 5; ++$m) {
176 | $e = @Pieces[$m];
177 | $tb = "K".$a.$b.$c.$d."v"."K".$e;
178 | Process($tb);
179 | }
180 | }
181 | }
182 | }
183 | }
184 |
185 | for ($i = 0; $i < 5; ++$i) {
186 | $a = @Pieces[$i];
187 | for ($j = $i; $j < 5; ++$j) {
188 | $b = @Pieces[$j];
189 | for ($k = $j; $k < 5; ++$k) {
190 | $c = @Pieces[$k];
191 | for ($l = 0; $l < 5; ++$l) {
192 | $d = @Pieces[$l];
193 | for ($m = $l; $m < 5; ++$m) {
194 | $e = @Pieces[$m];
195 | $tb = "K".$a.$b.$c."v"."K".$d.$e;
196 | Process($tb);
197 | }
198 | }
199 | }
200 | }
201 | }
202 |
--------------------------------------------------------------------------------
/src/sprobe.c:
--------------------------------------------------------------------------------
1 | struct Player {
2 | int num;
3 | int type[5];
4 | int pos[5];
5 | };
6 |
7 | static int probe_tb2(struct Player *player, struct Player *opp, bitboard player_occ, bitboard opp_occ, int alpha, int beta);
8 |
9 | static int probe_tb_capts(struct Player *player, struct Player *opp, bitboard player_occ, bitboard opp_occ, int alpha, int beta, int *capts)
10 | {
11 | int i, j;
12 |
13 | *capts = 0;
14 |
15 | if (opp->num > 1) {
16 | for (i = 0; i < player->num; i++) {
17 | int from = player->pos[i];
18 | bitboard bb = PieceRange(from, player->type[i], player_occ | opp_occ) & opp_occ;
19 | if (bb) {
20 | *capts = 1;
21 | opp->num--;
22 | bitboard occ2 = player_occ ^ bit[from];
23 | do {
24 | int to = FirstOne(bb);
25 | player->pos[i] = to;
26 | for (j = 0; opp->pos[j] != to; j++);
27 | int tmp_type = opp->type[j];
28 | opp->type[j] = opp->type[opp->num];
29 | opp->pos[j] = opp->pos[opp->num];
30 | #ifdef HAS_PAWNS
31 | // FIXME: optimise
32 | if ((player->type[i] & 0x07) == PAWN && ((to + 0x08) & 0x30) == 0) {
33 | int t = player->type[i];
34 | int m;
35 | for (m = KING - PAWN; m >= KNIGHT - PAWN; m--) {
36 | player->type[i] = t + m;
37 | int v = -probe_tb2(opp, player, opp_occ ^ bit[to], occ2 ^ bit[to], -beta, -alpha);
38 | if (v > alpha) {
39 | alpha = v;
40 | if (alpha >= beta) break;
41 | }
42 | }
43 | player->type[i] = t;
44 | } else {
45 | #endif
46 | int v = -probe_tb2(opp, player, opp_occ ^ bit[to], occ2 ^ bit[to], -beta, -alpha);
47 | if (v > alpha)
48 | alpha = v;
49 | #ifdef HAS_PAWNS
50 | }
51 | #endif
52 | opp->type[j] = tmp_type;
53 | opp->pos[j] = to;
54 | if (alpha >= beta) {
55 | player->pos[i] = from;
56 | opp->num++;
57 | return alpha;
58 | }
59 | ClearFirst(bb);
60 | } while (bb);
61 | player->pos[i] = from;
62 | opp->num++;
63 | }
64 | }
65 | } else {
66 | for (i = 0; i < player->num; i++) {
67 | bitboard bb = PieceRange(player->pos[i], player->type[i], player_occ) & opp_occ;
68 | if (bb) {
69 | *capts = 1;
70 | return -2;
71 | }
72 | }
73 | }
74 |
75 | return alpha;
76 | }
77 |
78 | static int probe_tb2(struct Player *player, struct Player *opp, bitboard player_occ, bitboard opp_occ, int alpha, int beta)
79 | {
80 | int i, j;
81 | bitboard player_att[5];
82 | bitboard opp_att[5];
83 |
84 | // first try captures
85 | if (opp->num > 1) {
86 | int capts = 0;
87 | for (i = 0; i < player->num; i++) {
88 | int from = player->pos[i];
89 | bitboard bb = PieceRange(from, player->type[i], player_occ | opp_occ);
90 | player_att[i] = bb;
91 | bb &= opp_occ;
92 | if (bb) {
93 | capts = 1;
94 | opp->num--;
95 | bitboard occ2 = player_occ ^ bit[from];
96 | do {
97 | int to = FirstOne(bb);
98 | player->pos[i] = to;
99 | for (j = 0; opp->pos[j] != to; j++);
100 | int tmp_type = opp->type[j];
101 | opp->type[j] = opp->type[opp->num];
102 | opp->pos[j] = opp->pos[opp->num];
103 | #ifdef HAS_PAWNS
104 | if ((player->type[i] & 0x07) == PAWN && ((to + 0x08) & 0x30) == 0) {
105 | int t = player->type[i];
106 | int m;
107 | for (m = KING - PAWN; m >= KNIGHT - PAWN; m--) {
108 | player->type[i] = t + m;
109 | int v = -probe_tb2(opp, player, opp_occ ^ bit[to], occ2 ^ bit[to], -beta, -alpha);
110 | if (v > alpha) {
111 | alpha = v;
112 | if (alpha >= beta) break;
113 | }
114 | }
115 | player->type[i] = t;
116 | } else {
117 | #endif
118 | int v = -probe_tb2(opp, player, opp_occ ^ bit[to], occ2 ^ bit[to], -beta, -alpha);
119 | if (v > alpha)
120 | alpha = v;
121 | #ifdef HAS_PAWNS
122 | }
123 | #endif
124 | opp->type[j] = tmp_type;
125 | opp->pos[j] = to;
126 | if (alpha >= beta) {
127 | player->pos[i] = from;
128 | opp->num++;
129 | return alpha;
130 | }
131 | ClearFirst(bb);
132 | } while (bb);
133 | player->pos[i] = from;
134 | opp->num++;
135 | }
136 | }
137 | if (capts) return alpha;
138 | } else {
139 | for (i = 0; i < player->num; i++) {
140 | bitboard bb = PieceRange(player->pos[i], player->type[i], player_occ);
141 | player_att[i] = bb;
142 | if (bb & opp_occ)
143 | return -2;
144 | }
145 | }
146 |
147 | #if 1
148 | if (player->num + opp->num < 6)
149 | goto skip_threats;
150 | #endif
151 |
152 | // now try threats. there are two cases
153 | bitboard atts = 0ULL;
154 | for (i = 0; i < opp->num; i++) {
155 | opp_att[i] = PieceRange(opp->pos[i], opp->type[i], player_occ | opp_occ);
156 | atts |= opp_att[i];
157 | }
158 | // first case: opponent currently is not attacking any pieces
159 | // we only need to consider moves moving into opponent attacks
160 | if (!(atts & player_occ)) {
161 | if (player->num > 1) {
162 | player->num--;
163 | for (i = 0; i <= player->num; i++) {
164 | #ifdef HAS_PAWNS
165 | if ((player->type[i] & 0x07) == 1) continue;
166 | #endif
167 | bitboard bb = player_att[i] & atts;
168 | if (!bb) continue;
169 | int pos = player->pos[i];
170 | int type = player->type[i];
171 | player->pos[i] = player->pos[player->num];
172 | player->type[i] = player->type[player->num];
173 | do {
174 | int sq = FirstOne(bb);
175 | int beta2 = beta;
176 | for (j = 0; j < opp->num; j++) {
177 | if (!(bit[sq] & opp_att[j])) continue;
178 | int tmp_pos = opp->pos[j];
179 | opp->pos[j] = sq;
180 | #ifdef HAS_PAWNS
181 | if ((opp->type[j] & 0x07) == PAWN && ((sq + 0x08) & 0x30) == 0) {
182 | int t = opp->type[j];
183 | int m;
184 | for (m = KING - PAWN; m >= KNIGHT - PAWN; m--) {
185 | opp->type[j] = t + m;
186 | int v = probe_tb2(player, opp, player_occ ^ bit[pos], opp_occ ^ bit[sq] ^ bit[tmp_pos], alpha, beta2);
187 | if (v < beta2) {
188 | beta2 = v;
189 | if (beta2 <= alpha)
190 | break;
191 | }
192 | }
193 | opp->type[j] = t;
194 | } else {
195 | #endif
196 | int v = probe_tb2(player, opp, player_occ ^ bit[pos], opp_occ ^ bit[sq] ^ bit[tmp_pos], alpha, beta2);
197 | if (v < beta2)
198 | beta2 = v;
199 | #ifdef HAS_PAWNS
200 | }
201 | #endif
202 | opp->pos[j] = tmp_pos;
203 | if (beta2 <= alpha) break;
204 | }
205 | if (beta2 > alpha) {
206 | if (beta2 >= beta) {
207 | player->pos[i] = pos;
208 | player->type[i] = type;
209 | player->num++;
210 | return beta2;
211 | }
212 | alpha = beta2;
213 | }
214 | ClearFirst(bb);
215 | } while (bb);
216 | player->pos[i] = pos;
217 | player->type[i] = type;
218 | }
219 | player->num++;
220 | } else {
221 | for (i = 0; i < player->num; i++) {
222 | #ifdef HAS_PAWNS
223 | if ((player->type[i] & 0x07) == 1) continue;
224 | #endif
225 | if (player_att[i] & atts) return 2;
226 | }
227 | }
228 | } else { // second case: just try all moves
229 | for (i = 0; i < player->num; i++) {
230 | #ifdef HAS_PAWNS
231 | if ((player->type[i] & 0x07) == 1) continue;
232 | #endif
233 | bitboard bb = player_att[i] & ~player_occ;
234 | if (bb) {
235 | int from = player->pos[i];
236 | do {
237 | int capts;
238 | int to = FirstOne(bb);
239 | player->pos[i] = to;
240 | int v = -probe_tb_capts(opp, player, opp_occ, player_occ ^ bit[from] ^ bit[to], -beta, -alpha, &capts);
241 | if (capts && v > alpha) {
242 | if (v >= beta) {
243 | player->pos[i] = from;
244 | return v;
245 | }
246 | alpha = v;
247 | }
248 | ClearFirst(bb);
249 | } while (bb);
250 | player->pos[i] = from;
251 | }
252 | }
253 | }
254 |
255 | int pieces[6];
256 | int pos[6];
257 | skip_threats:
258 | for (i = 0; i < player->num; i++) {
259 | pieces[i] = player->type[i];
260 | pos[i] = player->pos[i];
261 | }
262 | for (j = 0; j < opp->num; j++, i++) {
263 | pieces[i] = opp->type[j];
264 | pos[i] = opp->pos[j];
265 | }
266 | for (; i < numpcs; i++)
267 | pieces[i] = 0;
268 | int v = probe_table(pieces, pos, pieces[0] < 8);
269 | return alpha > v ? alpha : v;
270 | }
271 |
272 | int probe_tb(int *pieces, int *pos, int wtm, bitboard occ, int alpha, int beta)
273 | {
274 | int i, j, k;
275 | struct Player white, black;
276 | bitboard bb;
277 |
278 | bb = 0ULL;
279 | for (i = j = k = 0; i < numpcs; i++) {
280 | if (!pieces[i]) continue;
281 | if (!(pieces[i] & 0x08)) {
282 | white.type[j] = pieces[i];
283 | white.pos[j] = pos[i];
284 | j++;
285 | } else {
286 | black.type[k] = pieces[i];
287 | black.pos[k] = pos[i];
288 | bb |= bit[pos[i]];
289 | k++;
290 | }
291 | }
292 | white.num = j;
293 | black.num = k;
294 |
295 | //if (j == 0 || k == 0) return 2;
296 |
297 | #if 1
298 | if (wtm)
299 | return probe_tb2(&white, &black, occ ^ bb, bb, alpha, beta);
300 | else
301 | return probe_tb2(&black, &white, bb, occ ^ bb, alpha, beta);
302 | #else
303 | #define min(a,b) ((a) < (b) ? a : b)
304 | #define max(a,b) ((a) > (b) ? a : b)
305 | int v, v2;
306 | skip = 0;
307 | if (wtm)
308 | v = probe_tb2(&white, &black, occ ^ bb, bb, alpha, beta);
309 | else
310 | v = probe_tb2(&black, &white, bb, occ ^ bb, alpha, beta);
311 | skip = 1;
312 | if (wtm)
313 | v2 = probe_tb2(&white, &black, occ ^ bb, bb, alpha, beta);
314 | else
315 | v2 = probe_tb2(&black, &white, bb, occ ^ bb, alpha, beta);
316 | //int v2 = old_probe_tb(pieces, pos, wtm, occ, alpha, beta);
317 | if (max(v,alpha) != max(v2,alpha) && min(v,beta) != min(v2,beta)) {
318 | printf("hey! v = %d, v2 = %d\n", v, v2);
319 | for (i = 0; i < numpcs; i++)
320 | printf("pieces[%d] = %d, pos[%d] = %d\n", i, pieces[i], i, pos[i]);
321 | if (wtm)
322 | v = probe_tb2(&white, &black, occ ^ bb, bb, alpha, beta);
323 | else
324 | v = probe_tb2(&black, &white, bb, occ ^ bb, alpha, beta);
325 | }
326 | return v;
327 | #endif
328 | }
329 |
330 |
--------------------------------------------------------------------------------
/src/tbcheck.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 |
6 | #include "defs.h"
7 | #include "threads.h"
8 | #include "checksum.h"
9 |
10 | extern int total_work;
11 | extern int numthreads;
12 |
13 | static void compare_checksums(char *file)
14 | {
15 | char name[128];
16 | char sum[40];
17 | char sum2[40];
18 |
19 | FILE *F = fopen(file, "r");
20 | if (!F) {
21 | fprintf(stderr, "Could not open %s.\n", file);
22 | return;
23 | }
24 | while (!feof(F)) {
25 | int num = fscanf(F, "%100[KQRBNP|v|rtbwz|.]: %32[0-9|a-f]\n", name, sum);
26 | if (num != 2 || strlen(sum) != 32) {
27 | fprintf(stderr, "Could not completely parse %s.\n", file);
28 | break;
29 | }
30 | FILE *G = fopen(name, "rb");
31 | if (!G) {
32 | fprintf(stderr, "Tablebase file %s not found.\n", name);
33 | } else {
34 | fclose(G);
35 | print_checksum(name, sum2);
36 | if (strcmp(sum, sum2) == 0)
37 | printf("%s: OK!\n", name);
38 | else
39 | printf("%s: FAIL!\n", name);
40 | }
41 | }
42 | fclose(F);
43 | }
44 |
45 | static struct option options[] = {
46 | { "threads", 1, NULL, 't' },
47 | { "print", 0, NULL, 'p' },
48 | { "compare", 0, NULL, 'c' },
49 | { 0, 0, NULL, 0 }
50 | };
51 |
52 | int main(int argc, char **argv)
53 | {
54 | int i;
55 | int val, longindex;
56 | int only_print = 0;
57 | int compare = 0;
58 |
59 | numthreads = 1;
60 |
61 | do {
62 | val = getopt_long(argc, argv, "t:pc", options, &longindex);
63 | switch (val) {
64 | case 't':
65 | numthreads = atoi(optarg);
66 | break;
67 | case 'p':
68 | only_print = 1;
69 | break;
70 | case 'c':
71 | compare = 1;
72 | break;
73 | }
74 | } while (val != EOF);
75 |
76 | if (optind >= argc) {
77 | fprintf(stderr, "No tablebase specified.\n");
78 | exit(0);
79 | }
80 |
81 | if (numthreads < 1) numthreads = 1;
82 |
83 | total_work = (numthreads == 1) ? 1 : 100 + 10 * numthreads;
84 |
85 | init_threads(0);
86 |
87 | if (!compare) {
88 | if (!only_print)
89 | for (i = optind; i < argc; i++)
90 | verify_checksum(argv[i]);
91 | else
92 | for (i = optind; i < argc; i++) {
93 | char sum[40];
94 | printf("%s: ", argv[i]);
95 | print_checksum(argv[i], sum);
96 | puts(sum);
97 | }
98 | } else {
99 | for (i = optind; i < argc; i++)
100 | compare_checksums(argv[i]);
101 | }
102 |
103 | return 0;
104 | }
105 |
106 |
--------------------------------------------------------------------------------
/src/tbver.c:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2011-2013, 2018 Ronald de Man
3 |
4 | This file is distributed under the terms of the GNU GPL, version 2.
5 | */
6 |
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 |
14 | #include "board.h"
15 | #include "decompress.h"
16 | #include "defs.h"
17 | #include "threads.h"
18 | #include "util.h"
19 |
20 | #ifndef SUICIDE
21 | static int white_king, black_king;
22 | #endif
23 |
24 | #include "probe.c"
25 | #include "board.c"
26 |
27 | #define MAX_PIECES 8
28 |
29 | void error(char *str, ...);
30 |
31 | extern int use_envdirs;
32 |
33 | extern int total_work;
34 | extern struct thread_data *thread_data;
35 | extern int numthreads;
36 | extern struct timeval start_time, cur_time;
37 |
38 | static uint64_t *work_g;
39 | #ifndef SMALL
40 | static uint64_t *work_piv;
41 | #else
42 | static uint64_t *work_piv0, *work_piv1;
43 | #endif
44 |
45 | uint8_t *table_w, *table_b;
46 | int numpcs;
47 | int numpawns = 0;
48 | int ply_accurate_win, ply_accurate_loss;
49 | //int dtz_side;
50 | uint8_t *load_table;
51 | int load_bside;
52 | struct TBEntry_piece *load_entry;
53 | uint8_t *load_opp_table;
54 | int *load_pieces, *load_opp_pieces;
55 | uint8_t (*load_map)[256];
56 | uint8_t *tb_table;
57 | int tb_perm[MAX_PIECES];
58 |
59 | static uint64_t size;
60 |
61 | static int white_pcs[MAX_PIECES], black_pcs[MAX_PIECES];
62 | static int pt[MAX_PIECES];
63 | #ifndef SUICIDE
64 | static int pcs2[MAX_PIECES];
65 | #endif
66 |
67 | #ifndef SMALL
68 | #include "generic.c"
69 | #else
70 | #include "generics.c"
71 | #endif
72 |
73 | #if defined(REGULAR)
74 | #include "rtbver.c"
75 | #elif defined(SUICIDE)
76 | #include "stbver.c"
77 | #elif defined(ATOMIC)
78 | #include "atbver.c"
79 | #elif defined(LOSER)
80 | #include "ltbver.c"
81 | #endif
82 |
83 | #define HUGEPAGESIZE 2*1024*1024
84 |
85 | extern char *optarg;
86 |
87 | static char *tablename;
88 |
89 | static int log = 0;
90 | static int num_errors = 0;
91 | static FILE *L;
92 |
93 | void error(char *str, ...)
94 | {
95 | va_list ap;
96 |
97 | va_start(ap, str);
98 | vprintf(str, ap);
99 | va_end(ap);
100 | fflush(stdout);
101 | if (log) {
102 | va_start(ap, str);
103 | vfprintf(L, str, ap);
104 | va_end(ap);
105 | fflush(L);
106 | }
107 | num_errors++;
108 | if (num_errors == 10) {
109 | if (log) fclose(L);
110 | exit(EXIT_FAILURE);
111 | }
112 | }
113 |
114 | static void check_huffman_tb(int wdl)
115 | {
116 | struct tb_handle *F = open_tb(tablename, wdl);
117 | decomp_init_table(F);
118 | struct TBEntry_piece *entry = &(F->entry_piece);
119 | printf("%s%s:", tablename, wdl ? WDLSUFFIX : DTZSUFFIX);
120 | int m0 = entry->precomp[0]->max_len;
121 | printf(" %d", m0);
122 | int m1 = 0;
123 | if (F->split) {
124 | m1 = entry->precomp[1]->max_len;
125 | printf(" %d", m1);
126 | }
127 | if (m0 >= 32 || m1 >= 32)
128 | printf(" ----- WARNING!!!!!");
129 | printf("\n");
130 | close_tb(F);
131 | }
132 |
133 | static void check_huffman()
134 | {
135 | check_huffman_tb(1);
136 | check_huffman_tb(0);
137 | }
138 |
139 | static struct option options[] = {
140 | { "threads", 1, NULL, 't' },
141 | { "log", 0, NULL, 'l' },
142 | { "huffman", 0, NULL, 'h' },
143 | // { "wdl", 0, NULL, 'w' },
144 | { 0, 0, NULL, 0 }
145 | };
146 |
147 | int main(int argc, char **argv)
148 | {
149 | int i, j;
150 | int color;
151 | int val, longindex;
152 | int pcs[16];
153 | int wdl_only = 0;
154 | int check_huff = 0;
155 | #ifdef SUICIDE
156 | int switched = 0;
157 | #endif
158 |
159 | numthreads = 1;
160 |
161 | do {
162 | // val = getopt_long(argc, argv, "t:lwc", options, &longindex);
163 | val = getopt_long(argc, argv, "t:ldh", options, &longindex);
164 | switch (val) {
165 | case 't':
166 | numthreads = atoi(optarg);
167 | break;
168 | case 'l':
169 | log = 1;
170 | break;
171 | case 'w':
172 | wdl_only = 1;
173 | break;
174 | case 'd':
175 | use_envdirs = 1;
176 | break;
177 | case 'h':
178 | check_huff = 1;
179 | break;
180 | }
181 | } while (val != EOF);
182 |
183 | if (optind >= argc) {
184 | fprintf(stderr, "No tablebase specified.\n");
185 | exit(EXIT_FAILURE);
186 | }
187 | tablename = argv[optind];
188 |
189 | for (i = 0; i < 16; i++)
190 | pcs[i] = 0;
191 |
192 | numpcs = strlen(tablename) - 1;
193 | color = 0;
194 | j = 0;
195 | for (i = 0; i < strlen(tablename); i++)
196 | switch (tablename[i]) {
197 | case 'P':
198 | pcs[PAWN | color]++;
199 | pt[j++] = PAWN | color;
200 | break;
201 | case 'N':
202 | pcs[KNIGHT | color]++;
203 | pt[j++] = KNIGHT | color;
204 | break;
205 | case 'B':
206 | pcs[BISHOP | color]++;
207 | pt[j++] = BISHOP | color;
208 | break;
209 | case 'R':
210 | pcs[ROOK | color]++;
211 | pt[j++] = ROOK | color;
212 | break;
213 | case 'Q':
214 | pcs[QUEEN | color]++;
215 | pt[j++] = QUEEN | color;
216 | break;
217 | case 'K':
218 | pcs[KING | color]++;
219 | pt[j++] = KING | color;
220 | break;
221 | case 'v':
222 | if (color) exit(EXIT_FAILURE);
223 | color = 0x08;
224 | break;
225 | default:
226 | exit(EXIT_FAILURE);
227 | }
228 | if (!color) exit(EXIT_FAILURE);
229 |
230 | if (pcs[WPAWN] || pcs[BPAWN]) {
231 | fprintf(stderr, "Can't handle pawns.\n");
232 | exit(EXIT_FAILURE);
233 | }
234 |
235 | decomp_init_piece(pcs);
236 |
237 | if (check_huff) {
238 | check_huffman();
239 | return 0;
240 | }
241 |
242 | init_tablebases();
243 |
244 | if (numthreads < 1) numthreads = 1;
245 |
246 | printf("number of threads = %d\n", numthreads);
247 |
248 | if (numthreads == 1)
249 | total_work = 1;
250 | else
251 | total_work = 100 + 10 * numthreads;
252 |
253 | for (i = 0; i < numpcs; i++) {
254 | shift[i] = (numpcs - i - 1) * 6;
255 | mask[i] = 0x3fULL << shift[i];
256 | }
257 |
258 | #ifndef SMALL
259 | size = 10ULL << (6 * (numpcs-1));
260 | #else
261 | size = 462ULL << (6 * (numpcs-2));
262 |
263 | mask[0] = 0x1ffULL << shift[1];
264 | #endif
265 |
266 | work_g = create_work(total_work, size, 0x3f);
267 | #ifndef SMALL
268 | work_piv = create_work(total_work, 1ULL << shift[0], 0);
269 | #else
270 | work_piv0 = create_work(total_work, 1ULL << shift[0], 0);
271 | work_piv1 = create_work(total_work, 10ULL << shift[1], 0);
272 | #endif
273 |
274 | static int piece_order[16] = {
275 | 0, 0, 3, 5, 7, 9, 1, 0,
276 | 0, 0, 4, 6, 8, 10, 2, 0
277 | };
278 |
279 | #ifdef SUICIDE
280 | j = pt[0];
281 | for (i = 1; i < numpcs; i++)
282 | if (piece_order[pt[i]] < piece_order[j])
283 | j = pt[i];
284 | if (j & 0x08) {
285 | for (i = 0; i < numpcs; i++)
286 | pt[i] ^= 0x08;
287 | for (i = 0; i < 8; i++) {
288 | int tmp = pcs[i];
289 | pcs[i] = pcs[i + 8];
290 | pcs[i + 8] = tmp;
291 | }
292 | switched = 1;
293 | }
294 | #endif
295 |
296 | for (i = 0; i < numpcs; i++)
297 | for (j = i + 1; j < numpcs; j++)
298 | if (piece_order[pt[i]] > piece_order[pt[j]]) {
299 | int tmp = pt[i];
300 | pt[i] = pt[j];
301 | pt[j] = tmp;
302 | }
303 |
304 | for (i = 0, j = 0; i < numpcs; i++)
305 | if (!(pt[i] & 0x08))
306 | white_pcs[j++] = i;
307 | white_pcs[j] = -1;
308 |
309 | for (i = 0, j = 0; i < numpcs; i++)
310 | if (pt[i] & 0x08)
311 | black_pcs[j++] = i;
312 | black_pcs[j] = -1;
313 |
314 | idx_mask1[numpcs - 1] = 0xffffffffffffffc0ULL;
315 | idx_mask2[numpcs - 1] = 0;
316 | for (i = numpcs - 2; i >= 0; i--) {
317 | idx_mask1[i] = idx_mask1[i + 1] << 6;
318 | idx_mask2[i] = (idx_mask2[i + 1] << 6) | 0x3f;
319 | }
320 |
321 | #ifndef SUICIDE
322 | for (i = 0; i < numpcs; i++)
323 | if (pt[i] == WKING)
324 | white_king = i;
325 |
326 | for (i = 0; i < numpcs; i++)
327 | if (pt[i] == BKING)
328 | black_king = i;
329 | #endif
330 |
331 | table_w = alloc_huge(2 * size);
332 | table_b = table_w + size;
333 |
334 | printf("Verifying %s.\n", tablename);
335 | if (log) {
336 | L = fopen(LOGFILE, "a");
337 | fprintf(L, "Verifying %s...", tablename);
338 | fflush(L);
339 | }
340 |
341 | init_threads(0);
342 | init_tables();
343 |
344 | gettimeofday(&start_time, NULL);
345 | cur_time = start_time;
346 |
347 | printf("Initialising broken positions.\n");
348 | run_threaded(calc_broken, work_g, 1);
349 | printf("Calculating white captures.\n");
350 | calc_captures_w();
351 | printf("Calculating black captures.\n");
352 | calc_captures_b();
353 | #ifndef SUICIDE
354 | printf("Calculating mate positions.\n");
355 | run_threaded(calc_mates, work_g, 1);
356 | #else
357 | init_capt_threat();
358 | printf("Calculating white threats.\n");
359 | iter_table = table_b;
360 | iter_table_opp = table_w;
361 | iter_pcs_opp = white_pcs;
362 | run_threaded(calc_threats, work_g, 1);
363 | printf("Calculating black threats.\n");
364 | iter_table = table_w;
365 | iter_table_opp = table_b;
366 | iter_pcs_opp = black_pcs;
367 | run_threaded(calc_threats, work_g, 1);
368 | #endif
369 |
370 | // open wdl table
371 | struct tb_handle *H = open_tb(tablename, 1);
372 | decomp_init_table(H);
373 | load_entry = (struct TBEntry_piece *)get_entry(H);
374 |
375 | if (!wdl_only) {
376 | // white, wdl
377 | printf("Loading wdl, white.\n");
378 | tb_table = decompress_table(H, 0, 0);
379 | set_perm(H, 0, 0, tb_perm, pt);
380 | load_table = table_w;
381 | load_bside = 0;
382 | run_threaded(load_wdl, work_g, 1);
383 |
384 | // black, wdl
385 | printf("Loading wdl, black.\n");
386 | tb_table = decompress_table(H, 1, 0);
387 | set_perm(H, 1, 0, tb_perm, pt);
388 | load_table = table_b;
389 | load_bside = 1;
390 | run_threaded(load_wdl, work_g, 1);
391 | close_tb(H);
392 |
393 | // open dtz table
394 | H = open_tb(tablename, 0);
395 | decomp_init_table(H);
396 | load_entry = (struct TBEntry_piece *)get_entry(H);
397 | ply_accurate_win = get_ply_accurate_win(H, 0);
398 | ply_accurate_loss = get_ply_accurate_loss(H, 0);
399 | load_map = get_dtz_map(H, 0);
400 | int dtz_side = get_dtz_side(H, 0);
401 | init_wdl_dtz();
402 |
403 | // dtz
404 | printf("Loading dtz, %s.\n" , dtz_side == 0 ? "white" : "black");
405 | tb_table = decompress_table(H, 0, 0);
406 | set_perm(H, 0, 0, tb_perm, pt);
407 | load_table = dtz_side == 0 ? table_w : table_b;
408 | load_bside = 0;
409 | if (load_map)
410 | run_threaded(load_dtz_mapped, work_g, 1);
411 | else
412 | run_threaded(load_dtz, work_g, 1);
413 | close_tb(H);
414 |
415 | if (dtz_side == 0) {
416 | load_table = table_w;
417 | load_opp_table = table_b;
418 | load_pieces = white_pcs;
419 | load_opp_pieces = black_pcs;
420 | } else {
421 | load_table = table_b;
422 | load_opp_table = table_w;
423 | load_pieces = black_pcs;
424 | load_opp_pieces = white_pcs;
425 | }
426 |
427 | printf("Verifying %s.\n", dtz_side ? "white" : "black");
428 | run_threaded(verify_opp, work_g, 1);
429 | printf("Verifying %s.\n", dtz_side ? "black" : "white");
430 | run_threaded(verify_dtz, work_g, 1);
431 | } else { // currently broken (and disabled)
432 | // white, wdl
433 | printf("Loading wdl, white.\n");
434 | tb_table = decompress_table(H, 0, 0);
435 | set_perm(H, 0, 0, tb_perm, pt);
436 | load_table = table_w;
437 | load_bside = 0;
438 | run_threaded(wdl_load_wdl, work_g, 1);
439 |
440 | // black, wdl
441 | printf("Loading wdl, black.\n");
442 | tb_table = decompress_table(H, 1, 0);
443 | set_perm(H, 1, 0, tb_perm, pt);
444 | load_table = table_b;
445 | load_bside = 1;
446 | run_threaded(wdl_load_wdl, work_g, 1);
447 | close_tb(H);
448 |
449 | ply_accurate_win = get_ply_accurate_win(H, 0);
450 | ply_accurate_loss = get_ply_accurate_loss(H, 0);
451 | init_wdl();
452 | load_table = table_w;
453 | load_opp_table = table_b;
454 | load_pieces = white_pcs;
455 | printf("Verifying white.\n");
456 | run_threaded(verify_wdl, work_g, 1);
457 |
458 | ply_accurate_win = get_ply_accurate_loss(H, 0);
459 | ply_accurate_loss = get_ply_accurate_win(H, 0);
460 | init_wdl();
461 | load_table = table_b;
462 | load_opp_table = table_w;
463 | load_pieces = black_pcs;
464 | printf("Verifying black.\n");
465 | run_threaded(verify_wdl, work_g, 1);
466 | }
467 |
468 | if (num_errors == 0) {
469 | printf("No errors.\n");
470 | if (log) fprintf(L, " No errors.\n");
471 | }
472 | if (log) fclose(L);
473 |
474 | return 0;
475 | }
476 |
--------------------------------------------------------------------------------
/src/threads.c:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2011-2013, 2018 Ronald de Man
3 |
4 | This file is distributed under the terms of the GNU GPL, version 2.
5 | */
6 |
7 | #include
8 | #include
9 | #ifndef __WIN32__
10 | #include
11 | #else
12 | #include
13 | #endif
14 | #include
15 |
16 | #include "threads.h"
17 | #include "util.h"
18 |
19 | struct thread_data *thread_data;
20 |
21 | #ifndef __WIN32__ /* pthread */
22 |
23 | // implementation of pthread_barrier in case it is missing
24 | #if !defined(_POSIX_BARRIERS)
25 | #define pthread_barrier_t barrier_t
26 | #define pthread_barrier_attr_t barrier_attr_t
27 | #define pthread_barrier_init(b,a,n) barrier_init(b,n)
28 | #define pthread_barrier_destroy(b) barrier_destroy(b)
29 | #define pthread_barrier_wait(b) barrier_wait(b)
30 |
31 | typedef struct {
32 | int needed;
33 | int called;
34 | pthread_mutex_t mutex;
35 | pthread_cond_t cond;
36 | } barrier_t;
37 |
38 | int barrier_init(barrier_t *barrier, int needed)
39 | {
40 | barrier->needed = needed;
41 | barrier->called = 0;
42 | pthread_mutex_init(&barrier->mutex, NULL);
43 | pthread_cond_init(&barrier->cond, NULL);
44 | return 0;
45 | }
46 |
47 | int barrier_destroy(barrier_t *barrier)
48 | {
49 | pthread_mutex_destroy(&barrier->mutex);
50 | pthread_cond_destroy(&barrier->cond);
51 | return 0;
52 | }
53 |
54 | int barrier_wait(barrier_t *barrier)
55 | {
56 | pthread_mutex_lock(&barrier->mutex);
57 | barrier->called++;
58 | if (barrier->called == barrier->needed) {
59 | barrier->called = 0;
60 | pthread_cond_broadcast(&barrier->cond);
61 | } else {
62 | pthread_cond_wait(&barrier->cond,&barrier->mutex);
63 | }
64 | pthread_mutex_unlock(&barrier->mutex);
65 | return 0;
66 | }
67 | #endif
68 |
69 | pthread_t *threads;
70 | static pthread_barrier_t barrier;
71 | #define THREAD_FUNC void*
72 |
73 | #else /* WIN32 */
74 |
75 | HANDLE *threads;
76 | HANDLE *start_event;
77 | HANDLE *stop_event;
78 | #define THREAD_FUNC DWORD
79 |
80 | #endif
81 |
82 | static struct {
83 | void (*func)(struct thread_data *);
84 | uint64_t *work;
85 | int counter;
86 | int total;
87 | } queue;
88 |
89 | int total_work;
90 | int numthreads;
91 | int thread_affinity;
92 |
93 | struct timeval start_time, cur_time;
94 |
95 | void fill_work(int n, uint64_t size, uint64_t mask, uint64_t *w)
96 | {
97 | int i;
98 |
99 | w[0] = 0;
100 | w[n] = size;
101 |
102 | for (i = 1; i < n; i++)
103 | w[i] = ((((uint64_t)i) * size) / ((uint64_t)n)) & ~mask;
104 | }
105 |
106 | void fill_work_offset(int n, uint64_t size, uint64_t mask, uint64_t *w,
107 | uint64_t offset)
108 | {
109 | fill_work(n, size, mask, w);
110 | for (int i = 0; i <= n; i++)
111 | w[i] += offset;
112 | }
113 |
114 | uint64_t *alloc_work(int n)
115 | {
116 | return (uint64_t *)malloc((n + 1) * sizeof(uint64_t));
117 | }
118 |
119 | uint64_t *create_work(int n, uint64_t size, uint64_t mask)
120 | {
121 | uint64_t *w;
122 |
123 | w = alloc_work(n);
124 | fill_work(n, size, mask, w);
125 |
126 | return w;
127 | }
128 |
129 | THREAD_FUNC worker(void *arg);
130 |
131 | void init_threads(int pawns)
132 | {
133 | int i;
134 |
135 | thread_data = alloc_aligned(numthreads * sizeof(*thread_data), 64);
136 |
137 | for (i = 0; i < numthreads; i++)
138 | thread_data[i].thread = i;
139 |
140 | if (pawns) {
141 | uint8_t *p = alloc_aligned(64 * numthreads, 64);
142 | for (i = 0; i < numthreads; i++)
143 | thread_data[i].p = (int *)(p + 64 * i);
144 | }
145 |
146 | #ifndef __WIN32__
147 | threads = malloc(numthreads * sizeof(*threads));
148 | pthread_barrier_init(&barrier, NULL, numthreads);
149 |
150 | for (i = 0; i < numthreads - 1; i++) {
151 | int rc = pthread_create(&threads[i], NULL, worker,
152 | (void *)&(thread_data[i]));
153 | if (rc) {
154 | fprintf(stderr, "ERROR: pthread_create() returned %d\n", rc);
155 | exit(EXIT_FAILURE);
156 | }
157 | }
158 | threads[numthreads - 1] = pthread_self();
159 |
160 | if (thread_affinity) {
161 | cpu_set_t cpuset;
162 | CPU_ZERO(&cpuset);
163 | for (i = 0; i < numthreads; i++) {
164 | CPU_SET(i, &cpuset);
165 | int rc = pthread_setaffinity_np(threads[i], sizeof(cpuset), &cpuset);
166 | CPU_CLR(i, &cpuset);
167 | if (rc)
168 | fprintf(stderr, "pthread_setaffinity_np() returned %d.\n", rc);
169 | }
170 | }
171 | #else
172 | threads = malloc((numthreads - 1) * sizeof(*threads));
173 | start_event = malloc((numthreads - 1) * sizeof(*start_event));
174 | stop_event = malloc((numthreads - 1) * sizeof(*stop_event));
175 | for (i = 0; i < numthreads - 1; i++) {
176 | start_event[i] = CreateEvent(NULL, FALSE, FALSE, NULL);
177 | stop_event[i] = CreateEvent(NULL, FALSE, FALSE, NULL);
178 | if (!start_event[i] || !stop_event[i]) {
179 | fprintf(stderr, "CreateEvent() failed.\n");
180 | exit(EXIT_FAILURE);
181 | }
182 | }
183 | for (i = 0; i < numthreads - 1; i++) {
184 | threads[i] = CreateThread(NULL, 0, worker, (void *)&(thread_data[i]),
185 | 0, NULL);
186 | if (threads[i] == NULL) {
187 | fprintf(stderr, "CreateThread() failed.\n");
188 | exit(EXIT_FAILURE);
189 | }
190 | }
191 |
192 | if (thread_affinity)
193 | fprintf(stderr, "Thread affinities not yet implemented on Windows.\n");
194 | #endif
195 | }
196 |
197 | THREAD_FUNC worker(void *arg)
198 | {
199 | struct thread_data *thread = (struct thread_data *)arg;
200 | int t = thread->thread;
201 | int w;
202 |
203 | do {
204 | #ifndef __WIN32__
205 | pthread_barrier_wait(&barrier);
206 | #else
207 | if (t != numthreads - 1)
208 | WaitForSingleObject(start_event[t], INFINITE);
209 | else {
210 | int i;
211 | for (i = 0; i < numthreads - 1; i++)
212 | SetEvent(start_event[i]);
213 | }
214 | #endif
215 |
216 | int total = queue.total;
217 |
218 | while (1) {
219 | w = __sync_fetch_and_add(&queue.counter, 1);
220 | if (w >= total) break;
221 | thread->begin = queue.work[w];
222 | thread->end = queue.work[w + 1];
223 | queue.func(thread);
224 | }
225 |
226 | #ifndef __WIN32__
227 | pthread_barrier_wait(&barrier);
228 | #else
229 | if (t != numthreads - 1)
230 | SetEvent(stop_event[t]);
231 | else
232 | WaitForMultipleObjects(numthreads - 1, stop_event, TRUE, INFINITE);
233 | #endif
234 | } while (t != numthreads - 1);
235 |
236 | return 0;
237 | }
238 |
239 | void run_threaded(void (*func)(struct thread_data *), uint64_t *work, int report_time)
240 | {
241 | int secs, usecs;
242 | struct timeval stop_time;
243 |
244 | queue.func = func;
245 | queue.work = work;
246 | queue.total = total_work;
247 | queue.counter = 0;
248 |
249 | worker((void *)&(thread_data[numthreads - 1]));
250 |
251 | gettimeofday(&stop_time, NULL);
252 | secs = stop_time.tv_sec - cur_time.tv_sec;
253 | usecs = stop_time.tv_usec - cur_time.tv_usec;
254 | if (usecs < 0) {
255 | usecs += 1000000;
256 | secs--;
257 | }
258 | if (report_time)
259 | printf("time taken = %3d:%02d.%03d\n", secs / 60, secs % 60, usecs/1000);
260 | cur_time = stop_time;
261 | }
262 |
263 | void run_single(void (*func)(struct thread_data *), uint64_t *work, int report_time)
264 | {
265 | int secs, usecs;
266 | struct timeval stop_time;
267 | struct thread_data *thread = &(thread_data[0]);
268 |
269 | thread->begin = work[0];
270 | thread->end = work[total_work];
271 | func(thread);
272 |
273 | gettimeofday(&stop_time, NULL);
274 | secs = stop_time.tv_sec - cur_time.tv_sec;
275 | usecs = stop_time.tv_usec - cur_time.tv_usec;
276 | if (usecs < 0) {
277 | usecs += 1000000;
278 | secs--;
279 | }
280 | if (report_time)
281 | printf("time taken = %3d:%02d.%03d\n", secs / 60, secs % 60, usecs/1000);
282 | cur_time = stop_time;
283 | }
284 |
285 | static pthread_t cmprs_threads[COMPRESSION_THREADS];
286 | static struct thread_data cmprs_data[COMPRESSION_THREADS];
287 | static pthread_barrier_t cmprs_barrier;
288 | static void (*cmprs_func)(int t);
289 |
290 | static void *cmprs_worker(void *arg)
291 | {
292 | struct thread_data *thread = arg;
293 | do {
294 | pthread_barrier_wait(&cmprs_barrier);
295 |
296 | cmprs_func(thread->thread);
297 |
298 | pthread_barrier_wait(&cmprs_barrier);
299 | } while (thread->thread != 0);
300 |
301 | return 0;
302 | }
303 |
304 | void create_compression_threads(void)
305 | {
306 | for (int i = 0; i < COMPRESSION_THREADS; i++) {
307 | cmprs_data[i].thread = i;
308 | }
309 |
310 | pthread_barrier_init(&cmprs_barrier, NULL, COMPRESSION_THREADS);
311 |
312 | for (int i = 1; i < COMPRESSION_THREADS; i++) {
313 | int rc = pthread_create(&cmprs_threads[i], NULL, cmprs_worker, &cmprs_data[i]);
314 | if (rc) {
315 | fprintf(stderr, "ERROR: phtread_create() return %d\n", rc);
316 | exit(EXIT_FAILURE);
317 | }
318 | }
319 | }
320 |
321 | void run_compression(void (*func)(int t))
322 | {
323 | cmprs_func = func;
324 | cmprs_worker(&cmprs_data[0]);
325 | }
326 |
--------------------------------------------------------------------------------
/src/threads.h:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2011-2013, 2018 Ronald de Man
3 |
4 | This file is distributed under the terms of the GNU GPL, version 2.
5 | */
6 |
7 | #include
8 |
9 | #ifndef THREADS_H
10 | #define THREADS_H
11 | #include "defs.h"
12 | #include "types.h"
13 |
14 | #ifndef __WIN32__
15 | #include
16 | #else
17 | #include
18 | #endif
19 |
20 | #ifndef __WIN32__
21 | #define LOCK_T pthread_mutex_t
22 | #define LOCK_INIT(x) pthread_mutex_init(&(x), NULL)
23 | #define LOCK(x) pthread_mutex_lock(&(x))
24 | #define UNLOCK(x) pthread_mutex_unlock(&(x))
25 | #else
26 | #define LOCK_T HANDLE
27 | #define LOCK_INIT(x) do { x = CreateMutex(NULL, FALSE, NULL); } while (0)
28 | #define LOCK(x) WaitForSingleObject(x, INFINITE)
29 | #define UNLOCK(x) ReleaseMutex(x)
30 | #endif
31 |
32 | struct thread_data {
33 | alignas(64) uint64_t begin;
34 | uint64_t end;
35 | bitboard occ;
36 | uint64_t *stats;
37 | int *p;
38 | int thread;
39 | };
40 |
41 | void init_threads(int pawns);
42 | void run_threaded(void (*func)(struct thread_data *), uint64_t *work,
43 | int report_time);
44 | void run_single(void (*func)(struct thread_data *), uint64_t *work,
45 | int report_time);
46 | void fill_work(int n, uint64_t size, uint64_t mask, uint64_t *w);
47 | void fill_work_offset(int n, uint64_t size, uint64_t mask, uint64_t *w,
48 | uint64_t offset);
49 | uint64_t *alloc_work(int n);
50 | uint64_t *create_work(int n, uint64_t size, uint64_t mask);
51 |
52 | void create_compression_threads(void);
53 | void run_compression(void (*func)(int t));
54 |
55 | extern int numthreads;
56 | extern int thread_affinity;
57 | extern int total_work;
58 | extern struct thread_data *thread_data;
59 | extern struct timeval start_time, cur_time;
60 |
61 | #endif
62 |
--------------------------------------------------------------------------------
/src/types.h:
--------------------------------------------------------------------------------
1 | #ifndef TYPES_H
2 | #define TYPES_H
3 |
4 | #include
5 | #include "defs.h"
6 |
7 | typedef uint64_t bitboard;
8 | typedef uint16_t Move;
9 |
10 | typedef uint8_t u8;
11 | typedef uint16_t u16;
12 |
13 | enum { PAWN = 1, KNIGHT, BISHOP, ROOK, QUEEN, KING };
14 |
15 | enum {
16 | WPAWN = 1, WKNIGHT, WBISHOP, WROOK, WQUEEN, WKING,
17 | BPAWN = 9, BKNIGHT, BBISHOP, BROOK, BQUEEN, BKING,
18 | };
19 |
20 | struct dtz_map {
21 | uint16_t map[4][MAX_VALS];
22 | uint16_t inv_map[4][MAX_VALS];
23 | uint16_t num[4];
24 | uint16_t max_num;
25 | uint8_t side;
26 | uint8_t ply_accurate_win;
27 | uint8_t ply_accurate_loss;
28 | uint8_t wide;
29 | uint8_t high_freq_max;
30 | };
31 |
32 | #endif
33 |
--------------------------------------------------------------------------------
/src/util.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #ifndef __WIN32__
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #else
13 | #include
14 | #endif
15 |
16 | #ifdef USE_ZSTD
17 | #include
18 | #else
19 | #include "lz4.h"
20 | #endif
21 |
22 | #include "defs.h"
23 | #include "threads.h"
24 | #include "util.h"
25 |
26 | void *map_file(char *name, int shared, uint64_t *size)
27 | {
28 | #ifndef __WIN32__
29 |
30 | struct stat statbuf;
31 | int fd = open(name, O_RDONLY);
32 | if (fd < 0) {
33 | fprintf(stderr, "Could not open %s for reading.\n", name);
34 | exit(EXIT_FAILURE);
35 | }
36 | fstat(fd, &statbuf);
37 | *size = statbuf.st_size;
38 | #ifdef __linux__
39 | void *data = mmap(NULL, statbuf.st_size, PROT_READ,
40 | shared ? MAP_SHARED : MAP_PRIVATE | MAP_POPULATE, fd, 0);
41 | #else
42 | void *data = mmap(NULL, statbuf.st_size, PROT_READ, MAP_SHARED, fd, 0);
43 | #endif
44 | if (data == MAP_FAILED) {
45 | fprintf(stderr, "Could not mmap() %s.\n", name);
46 | exit(EXIT_FAILURE);
47 | }
48 | close(fd);
49 | return data;
50 |
51 | #else
52 |
53 | HANDLE h = CreateFile(name, GENERIC_READ, FILE_SHARE_READ, NULL,
54 | OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
55 | if (h == INVALID_HANDLE_VALUE) {
56 | fprintf(stderr, "Could not open %s for reading.\n", name);
57 | exit(EXIT_FAILURE);
58 | }
59 | DWORD size_low, size_high;
60 | size_low = GetFileSize(h, &size_high);
61 | *size = ((uint64_t)size_high << 32) | (uint64_t)size_low;
62 | HANDLE map = CreateFileMapping(h, NULL, PAGE_READONLY, size_high, size_low,
63 | NULL);
64 | if (map == NULL) {
65 | fprintf(stderr, "CreateFileMapping() failed.\n");
66 | exit(EXIT_FAILURE);
67 | }
68 | void *data = MapViewOfFile(map, FILE_MAP_READ, 0, 0, 0);
69 | if (data == NULL) {
70 | fprintf(stderr, "MapViewOfFile() failed.\n");
71 | exit(EXIT_FAILURE);
72 | }
73 | CloseHandle(h);
74 | return data;
75 |
76 | #endif
77 | }
78 |
79 | void unmap_file(void *data, uint64_t size)
80 | {
81 | #ifndef __WIN32__
82 |
83 | munmap(data, size);
84 |
85 | #else
86 |
87 | UnmapViewOfFile(data);
88 |
89 | #endif
90 | }
91 |
92 | void *alloc_aligned(uint64_t size, uintptr_t alignment)
93 | {
94 | #ifndef __WIN32__
95 |
96 | void *ptr;
97 |
98 | posix_memalign(&ptr, alignment, size);
99 | if (ptr == NULL) {
100 | fprintf(stderr, "Could not allocate sufficient memory.\n");
101 | exit(EXIT_FAILURE);
102 | }
103 |
104 | return ptr;
105 |
106 | #else
107 |
108 | void *ptr;
109 |
110 | ptr = malloc(size + alignment - 1);
111 | if (ptr == NULL) {
112 | fprintf(stderr, "Could not allocate sufficient memory.\n");
113 | exit(EXIT_FAILURE);
114 | }
115 | ptr = (void *)((uintptr_t)(ptr + alignment - 1) & ~(alignment - 1));
116 |
117 | return ptr;
118 |
119 | #endif
120 | }
121 |
122 | void *alloc_huge(uint64_t size)
123 | {
124 | void *ptr;
125 |
126 | #ifndef __WIN32__
127 |
128 | posix_memalign(&ptr, 2 * 1024 * 1024, size);
129 | if (ptr == NULL) {
130 | fprintf(stderr, "Could not allocate sufficient memory.\n");
131 | exit(EXIT_FAILURE);
132 | }
133 | #ifdef MADV_HUGEPAGE
134 | madvise(ptr, size, MADV_HUGEPAGE);
135 | #endif
136 |
137 | #else
138 |
139 | ptr = malloc(size);
140 | if (ptr == NULL) {
141 | fprintf(stderr, "Could not allocate sufficient memory.\n");
142 | exit(EXIT_FAILURE);
143 | }
144 |
145 | #endif
146 |
147 | return ptr;
148 | }
149 |
150 | void write_u32(FILE *F, uint32_t v)
151 | {
152 | fputc(v & 0xff, F);
153 | fputc((v >> 8) & 0xff, F);
154 | fputc((v >> 16) & 0xff, F);
155 | fputc((v >> 24) & 0xff, F);
156 | }
157 |
158 | void write_u16(FILE *F, uint16_t v)
159 | {
160 | fputc(v & 0xff, F);
161 | fputc((v >> 8) & 0xff, F);
162 | }
163 |
164 | void write_u8(FILE *F, uint8_t v)
165 | {
166 | fputc(v, F);
167 | }
168 |
169 | static uint8_t buf[8192];
170 |
171 | void write_bits(FILE *F, uint32_t bits, int n)
172 | {
173 | static int numBytes, numBits;
174 |
175 | if (n > 0) {
176 | if (numBits) {
177 | if (numBits >= n) {
178 | buf[numBytes - 1] |= (bits << (numBits - n));
179 | numBits -= n;
180 | n = 0;
181 | } else {
182 | buf[numBytes - 1] |= (bits >> (n - numBits));
183 | n -= numBits;
184 | numBits = 0;
185 | }
186 | }
187 | while (n >= 8) {
188 | buf[numBytes++] = bits >> (n - 8);
189 | n -= 8;
190 | }
191 | if (n > 0) {
192 | buf[numBytes++] = bits << (8 - n);
193 | numBits = 8 - n;
194 | }
195 | } else if (n == 0) {
196 | numBytes = 0;
197 | numBits = 0;
198 | } else if (n < 0) {
199 | n = -n;
200 | while (numBytes < n)
201 | buf[numBytes++] = 0;
202 | fwrite(buf, 1, n, F);
203 | numBytes = 0;
204 | numBits = 0;
205 | }
206 | }
207 |
208 | #define COPYSIZE (10*1024*1024)
209 |
210 | static size_t compress_bound;
211 |
212 | static LOCK_T cmprs_mutex;
213 |
214 | static FILE *cmprs_F;
215 | static void *cmprs_ptr;
216 | static size_t cmprs_size;
217 | static void *cmprs_v;
218 | static size_t cmprs_idx;
219 |
220 | struct CompressFrame {
221 | uint32_t cmprs_chunk;
222 | uint32_t chunk;
223 | size_t idx;
224 | uint8_t data[];
225 | };
226 |
227 | #define HEADER_SIZE offsetof(struct CompressFrame, data)
228 |
229 | struct CompressState {
230 | uint8_t *buffer;
231 | struct CompressFrame *frame;
232 | #ifdef USE_ZSTD
233 | ZSTD_CCtx *c_ctx;
234 | ZSTD_DCtx *d_ctx;
235 | #endif
236 | };
237 |
238 | static struct CompressState cmprs_state[COMPRESSION_THREADS];
239 |
240 | static void init(void)
241 | {
242 | static int initialised = 0;
243 |
244 | if (!initialised) {
245 | initialised = 1;
246 | LOCK_INIT(cmprs_mutex);
247 | #ifdef USE_ZSTD
248 | compress_bound = ZSTD_compressBound(COPYSIZE);
249 | #else
250 | compress_bound = LZ4_compressBound(COPYSIZE);
251 | #endif
252 | for (int i = 0; i < COMPRESSION_THREADS; i++) {
253 | cmprs_state[i].buffer = malloc(COPYSIZE);
254 | cmprs_state[i].frame = malloc(HEADER_SIZE + compress_bound);
255 | #ifdef USE_ZSTD
256 | cmprs_state[i].c_ctx = ZSTD_createCCtx();
257 | cmprs_state[i].d_ctx = ZSTD_createDCtx();
258 | #endif
259 | }
260 | create_compression_threads();
261 | }
262 | }
263 |
264 | static void file_read(void *ptr, size_t size, FILE *F)
265 | {
266 | if (fread(ptr, 1, size, F) != size) {
267 | fprintf(stderr, "Error reading data from disk.\n");
268 | exit(EXIT_FAILURE);
269 | }
270 | }
271 |
272 | static void file_write(void *ptr, size_t size, FILE *F)
273 | {
274 | if (fwrite(ptr, 1, size, F) != size) {
275 | fprintf(stderr, "Error writing data to disk.\n");
276 | exit(EXIT_FAILURE);
277 | }
278 | }
279 |
280 | #ifdef USE_ZSTD
281 |
282 | static size_t compress(struct CompressState *state, void *dst, void *src,
283 | size_t chunk)
284 | {
285 | return ZSTD_compressCCtx(state->c_ctx, dst, compress_bound, src, chunk, 1);
286 | }
287 |
288 | static void decompress(struct CompressState *state, void *dst, size_t chunk,
289 | void *src, size_t compressed)
290 | {
291 | ZSTD_decompressDCtx(state->d_ctx, dst, chunk, src, compressed);
292 | }
293 |
294 | #else
295 |
296 | static size_t compress(struct CompressState *state, void *dst, void *src,
297 | size_t chunk)
298 | {
299 | (void)state;
300 | return LZ4_compress(src, dst, chunk);
301 | }
302 |
303 | static void decompress(struct CompressState *state, void *dst, size_t chunk,
304 | void *src, size_t compressed)
305 | {
306 | (void)state;
307 | (void)compressed;
308 | LZ4_uncompress(src, dst, chunk);
309 | }
310 |
311 | #endif
312 |
313 | void copy_data(FILE *F, FILE *G, uint64_t size)
314 | {
315 | init();
316 |
317 | uint8_t *buffer = cmprs_state[0].buffer;
318 |
319 | while (size) {
320 | uint32_t chunk = min(COPYSIZE, size);
321 | file_read(buffer, chunk, G);
322 | file_write(buffer, chunk, F);
323 | size -= chunk;
324 | }
325 | }
326 |
327 | static void write_data_worker(int t)
328 | {
329 | struct CompressState *state = &cmprs_state[t];
330 |
331 | FILE *F = cmprs_F;
332 | uint8_t *src = cmprs_ptr;
333 | uint8_t *v = cmprs_v;
334 | while (1) {
335 | LOCK(cmprs_mutex);
336 | size_t idx = cmprs_idx;
337 | uint32_t chunk = min(COPYSIZE, cmprs_size - idx);
338 | cmprs_idx += chunk;
339 | UNLOCK(cmprs_mutex);
340 | if (chunk == 0)
341 | break;
342 | uint8_t *buf;
343 | if (v) {
344 | for (size_t i = 0; i < chunk; i++)
345 | state->buffer[i] = v[src[idx + i]];
346 | buf = state->buffer;
347 | } else
348 | buf = src + idx;
349 | uint32_t cmprs_chunk = compress(state, state->frame->data, buf, chunk);
350 | state->frame->cmprs_chunk = cmprs_chunk;
351 | state->frame->chunk = chunk;
352 | state->frame->idx = idx;
353 | file_write(state->frame, cmprs_chunk + HEADER_SIZE, F);
354 | }
355 | }
356 |
357 | void write_data(FILE *F, uint8_t *src, uint64_t offset, uint64_t size,
358 | uint8_t *v)
359 | {
360 | init();
361 |
362 | cmprs_F = F;
363 | cmprs_ptr = src;
364 | cmprs_size = offset + size;
365 | cmprs_v = v;
366 | cmprs_idx = offset;
367 | run_compression(write_data_worker);
368 | }
369 |
370 | static void read_data_worker_u8(int t)
371 | {
372 | struct CompressState *state = &cmprs_state[t];
373 |
374 | FILE *F = cmprs_F;
375 | uint8_t *dst = cmprs_ptr;
376 | uint8_t *v = cmprs_v;
377 | while (1) {
378 | uint32_t cmprs_chunk;
379 | flockfile(F);
380 | if (cmprs_size == 0) {
381 | funlockfile(F);
382 | break;
383 | }
384 | file_read(&cmprs_chunk, 4, F);
385 | file_read(&state->frame->chunk, cmprs_chunk + HEADER_SIZE - 4, F);
386 | uint32_t chunk = state->frame->chunk;
387 | if (chunk > cmprs_size) {
388 | fprintf(stderr, "Error in read_data_worker.\n");
389 | exit(EXIT_FAILURE);
390 | }
391 | cmprs_size -= chunk;
392 | funlockfile(F);
393 | size_t idx = state->frame->idx;
394 | if (!v)
395 | decompress(state, dst + idx, chunk, state->frame->data, cmprs_chunk);
396 | else {
397 | decompress(state, state->buffer, chunk, state->frame->data, cmprs_chunk);
398 | for (size_t i = 0; i < chunk; i++)
399 | dst[idx + i] |= v[state->buffer[i]];
400 | }
401 | }
402 | }
403 |
404 | void read_data_u8(FILE *F, uint8_t *dst, uint64_t size, uint8_t *v)
405 | {
406 | init();
407 |
408 | cmprs_F = F;
409 | cmprs_ptr = dst;
410 | cmprs_size = size;
411 | cmprs_v = v;
412 | run_compression(read_data_worker_u8);
413 | }
414 |
415 | static void read_data_worker_u16(int t)
416 | {
417 | struct CompressState *state = &cmprs_state[t];
418 |
419 | FILE *F = cmprs_F;
420 | uint16_t *dst = cmprs_ptr;
421 | uint16_t *v = cmprs_v;
422 | while (1) {
423 | uint32_t cmprs_chunk;
424 | flockfile(F);
425 | if (cmprs_size == 0) {
426 | funlockfile(F);
427 | break;
428 | }
429 | file_read(&cmprs_chunk, 4, F);
430 | file_read(&state->frame->chunk, cmprs_chunk + HEADER_SIZE - 4, F);
431 | uint32_t chunk = state->frame->chunk;
432 | if (chunk > cmprs_size) {
433 | fprintf(stderr, "Error in read_data_worker.\n");
434 | exit(EXIT_FAILURE);
435 | }
436 | cmprs_size -= chunk;
437 | funlockfile(F);
438 | size_t idx = state->frame->idx;
439 | decompress(state, state->buffer, chunk, state->frame->data, cmprs_chunk);
440 | if (!v)
441 | for (size_t i = 0; i < chunk; i++)
442 | dst[idx + i] = state->buffer[i];
443 | else
444 | for (size_t i = 0; i < chunk; i++)
445 | dst[idx + i] |= v[state->buffer[i]];
446 | }
447 | }
448 |
449 | // Read 8-bit data into 16-bit array.
450 | void read_data_u16(FILE *F, uint16_t *dst, uint64_t size, uint16_t *v)
451 | {
452 | init();
453 |
454 | cmprs_F = F;
455 | cmprs_ptr = dst;
456 | cmprs_size = size;
457 | cmprs_v = v;
458 | run_compression(read_data_worker_u16);
459 | }
460 |
--------------------------------------------------------------------------------
/src/util.h:
--------------------------------------------------------------------------------
1 | #ifndef UTIL_H
2 | #define UTIL_H
3 |
4 | #include
5 | #include
6 |
7 | #define min(a,b) ((a) < (b) ? (a) : (b))
8 |
9 | void *map_file(char *name, int shared, uint64_t *size);
10 | void unmap_file(void *data, uint64_t size);
11 |
12 | void *alloc_aligned(uint64_t size, uintptr_t alignment);
13 | void *alloc_huge(uint64_t size);
14 |
15 | void write_u32(FILE *F, uint32_t v);
16 | void write_u16(FILE *F, uint16_t v);
17 | void write_u8(FILE *F, uint8_t v);
18 |
19 | void write_bits(FILE *F, uint32_t bits, int n);
20 |
21 | void copy_data(FILE *F, FILE *G, uint64_t num);
22 | void write_data(FILE *F, uint8_t *src, uint64_t offset, uint64_t size,
23 | uint8_t *v);
24 | void read_data_u8(FILE *F, uint8_t *dst, uint64_t size, uint8_t *v);
25 | void read_data_u16(FILE *F, uint16_t *dst, uint64_t size, uint16_t *v);
26 |
27 | #endif
28 |
--------------------------------------------------------------------------------