├── .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 | --------------------------------------------------------------------------------