Install engines as ./exefile in XBoard
[xboard.git] / book.c
1 /*
2  * book.c -- code for probing Polyglot opening books
3  *
4  * This code was first released in the public domain by Michel Van den Bergh.
5  * The array Random64 is taken from the Polyglot source code. 
6  * I am pretty sure that a table of random numbers is never protected
7  * by copyright.
8  *
9  * It s adapted by H.G. Muller for working with xboard / Winboard
10  *
11  * The following terms apply to the enhanced version of XBoard distributed
12  * by the Free Software Foundation:
13  * ------------------------------------------------------------------------
14  *
15  * GNU XBoard is free software: you can redistribute it and/or modify
16  * it under the terms of the GNU General Public License as published by
17  * the Free Software Foundation, either version 3 of the License, or (at
18  * your option) any later version.
19  *
20  * GNU XBoard is distributed in the hope that it will be useful, but
21  * WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23  * General Public License for more details.
24  *
25  * You should have received a copy of the GNU General Public License
26  * along with this program. If not, see http://www.gnu.org/licenses/.  *
27  *
28  * ------------------------------------------------------------------------
29  */
30
31 #include <stdio.h>
32 #include <string.h>
33 #include <time.h>
34 #include <stdlib.h>
35 #include <math.h>
36
37 #include "common.h"
38 #include "backend.h"
39 #include "moves.h"
40 #include "gettext.h"
41
42 #ifdef ENABLE_NLS
43 # define  _(s) gettext (s)
44 # define N_(s) gettext_noop (s)
45 #else
46 # define  _(s) (s)
47 # define N_(s)  s
48 #endif
49
50 #ifdef _MSC_VER
51   typedef unsigned __int64 uint64;
52 #else
53   typedef unsigned long long int uint64;
54 #endif
55
56 #ifdef _MSC_VER
57 #  define U64(u) (u##ui64)
58 #else
59 #  define U64(u) (u##ULL)
60 #endif
61
62 typedef unsigned char uint8;
63 typedef unsigned short uint16;
64 typedef unsigned int uint32;
65
66 typedef struct {
67     uint64 key; 
68     uint16 move;
69     uint16 weight;
70     uint16 learnPoints;
71     uint16 learnCount;
72 } entry_t;
73
74 entry_t entry_none = {
75     0, 0, 0, 0
76 };
77
78 char *promote_pieces=" nbrqac=";
79
80 uint64 Random64[781] = {
81    U64(0x9D39247E33776D41), U64(0x2AF7398005AAA5C7), U64(0x44DB015024623547), U64(0x9C15F73E62A76AE2),
82    U64(0x75834465489C0C89), U64(0x3290AC3A203001BF), U64(0x0FBBAD1F61042279), U64(0xE83A908FF2FB60CA),
83    U64(0x0D7E765D58755C10), U64(0x1A083822CEAFE02D), U64(0x9605D5F0E25EC3B0), U64(0xD021FF5CD13A2ED5),
84    U64(0x40BDF15D4A672E32), U64(0x011355146FD56395), U64(0x5DB4832046F3D9E5), U64(0x239F8B2D7FF719CC),
85    U64(0x05D1A1AE85B49AA1), U64(0x679F848F6E8FC971), U64(0x7449BBFF801FED0B), U64(0x7D11CDB1C3B7ADF0),
86    U64(0x82C7709E781EB7CC), U64(0xF3218F1C9510786C), U64(0x331478F3AF51BBE6), U64(0x4BB38DE5E7219443),
87    U64(0xAA649C6EBCFD50FC), U64(0x8DBD98A352AFD40B), U64(0x87D2074B81D79217), U64(0x19F3C751D3E92AE1),
88    U64(0xB4AB30F062B19ABF), U64(0x7B0500AC42047AC4), U64(0xC9452CA81A09D85D), U64(0x24AA6C514DA27500),
89    U64(0x4C9F34427501B447), U64(0x14A68FD73C910841), U64(0xA71B9B83461CBD93), U64(0x03488B95B0F1850F),
90    U64(0x637B2B34FF93C040), U64(0x09D1BC9A3DD90A94), U64(0x3575668334A1DD3B), U64(0x735E2B97A4C45A23),
91    U64(0x18727070F1BD400B), U64(0x1FCBACD259BF02E7), U64(0xD310A7C2CE9B6555), U64(0xBF983FE0FE5D8244),
92    U64(0x9F74D14F7454A824), U64(0x51EBDC4AB9BA3035), U64(0x5C82C505DB9AB0FA), U64(0xFCF7FE8A3430B241),
93    U64(0x3253A729B9BA3DDE), U64(0x8C74C368081B3075), U64(0xB9BC6C87167C33E7), U64(0x7EF48F2B83024E20),
94    U64(0x11D505D4C351BD7F), U64(0x6568FCA92C76A243), U64(0x4DE0B0F40F32A7B8), U64(0x96D693460CC37E5D),
95    U64(0x42E240CB63689F2F), U64(0x6D2BDCDAE2919661), U64(0x42880B0236E4D951), U64(0x5F0F4A5898171BB6),
96    U64(0x39F890F579F92F88), U64(0x93C5B5F47356388B), U64(0x63DC359D8D231B78), U64(0xEC16CA8AEA98AD76),
97    U64(0x5355F900C2A82DC7), U64(0x07FB9F855A997142), U64(0x5093417AA8A7ED5E), U64(0x7BCBC38DA25A7F3C),
98    U64(0x19FC8A768CF4B6D4), U64(0x637A7780DECFC0D9), U64(0x8249A47AEE0E41F7), U64(0x79AD695501E7D1E8),
99    U64(0x14ACBAF4777D5776), U64(0xF145B6BECCDEA195), U64(0xDABF2AC8201752FC), U64(0x24C3C94DF9C8D3F6),
100    U64(0xBB6E2924F03912EA), U64(0x0CE26C0B95C980D9), U64(0xA49CD132BFBF7CC4), U64(0xE99D662AF4243939),
101    U64(0x27E6AD7891165C3F), U64(0x8535F040B9744FF1), U64(0x54B3F4FA5F40D873), U64(0x72B12C32127FED2B),
102    U64(0xEE954D3C7B411F47), U64(0x9A85AC909A24EAA1), U64(0x70AC4CD9F04F21F5), U64(0xF9B89D3E99A075C2),
103    U64(0x87B3E2B2B5C907B1), U64(0xA366E5B8C54F48B8), U64(0xAE4A9346CC3F7CF2), U64(0x1920C04D47267BBD),
104    U64(0x87BF02C6B49E2AE9), U64(0x092237AC237F3859), U64(0xFF07F64EF8ED14D0), U64(0x8DE8DCA9F03CC54E),
105    U64(0x9C1633264DB49C89), U64(0xB3F22C3D0B0B38ED), U64(0x390E5FB44D01144B), U64(0x5BFEA5B4712768E9),
106    U64(0x1E1032911FA78984), U64(0x9A74ACB964E78CB3), U64(0x4F80F7A035DAFB04), U64(0x6304D09A0B3738C4),
107    U64(0x2171E64683023A08), U64(0x5B9B63EB9CEFF80C), U64(0x506AACF489889342), U64(0x1881AFC9A3A701D6),
108    U64(0x6503080440750644), U64(0xDFD395339CDBF4A7), U64(0xEF927DBCF00C20F2), U64(0x7B32F7D1E03680EC),
109    U64(0xB9FD7620E7316243), U64(0x05A7E8A57DB91B77), U64(0xB5889C6E15630A75), U64(0x4A750A09CE9573F7),
110    U64(0xCF464CEC899A2F8A), U64(0xF538639CE705B824), U64(0x3C79A0FF5580EF7F), U64(0xEDE6C87F8477609D),
111    U64(0x799E81F05BC93F31), U64(0x86536B8CF3428A8C), U64(0x97D7374C60087B73), U64(0xA246637CFF328532),
112    U64(0x043FCAE60CC0EBA0), U64(0x920E449535DD359E), U64(0x70EB093B15B290CC), U64(0x73A1921916591CBD),
113    U64(0x56436C9FE1A1AA8D), U64(0xEFAC4B70633B8F81), U64(0xBB215798D45DF7AF), U64(0x45F20042F24F1768),
114    U64(0x930F80F4E8EB7462), U64(0xFF6712FFCFD75EA1), U64(0xAE623FD67468AA70), U64(0xDD2C5BC84BC8D8FC),
115    U64(0x7EED120D54CF2DD9), U64(0x22FE545401165F1C), U64(0xC91800E98FB99929), U64(0x808BD68E6AC10365),
116    U64(0xDEC468145B7605F6), U64(0x1BEDE3A3AEF53302), U64(0x43539603D6C55602), U64(0xAA969B5C691CCB7A),
117    U64(0xA87832D392EFEE56), U64(0x65942C7B3C7E11AE), U64(0xDED2D633CAD004F6), U64(0x21F08570F420E565),
118    U64(0xB415938D7DA94E3C), U64(0x91B859E59ECB6350), U64(0x10CFF333E0ED804A), U64(0x28AED140BE0BB7DD),
119    U64(0xC5CC1D89724FA456), U64(0x5648F680F11A2741), U64(0x2D255069F0B7DAB3), U64(0x9BC5A38EF729ABD4),
120    U64(0xEF2F054308F6A2BC), U64(0xAF2042F5CC5C2858), U64(0x480412BAB7F5BE2A), U64(0xAEF3AF4A563DFE43),
121    U64(0x19AFE59AE451497F), U64(0x52593803DFF1E840), U64(0xF4F076E65F2CE6F0), U64(0x11379625747D5AF3),
122    U64(0xBCE5D2248682C115), U64(0x9DA4243DE836994F), U64(0x066F70B33FE09017), U64(0x4DC4DE189B671A1C),
123    U64(0x51039AB7712457C3), U64(0xC07A3F80C31FB4B4), U64(0xB46EE9C5E64A6E7C), U64(0xB3819A42ABE61C87),
124    U64(0x21A007933A522A20), U64(0x2DF16F761598AA4F), U64(0x763C4A1371B368FD), U64(0xF793C46702E086A0),
125    U64(0xD7288E012AEB8D31), U64(0xDE336A2A4BC1C44B), U64(0x0BF692B38D079F23), U64(0x2C604A7A177326B3),
126    U64(0x4850E73E03EB6064), U64(0xCFC447F1E53C8E1B), U64(0xB05CA3F564268D99), U64(0x9AE182C8BC9474E8),
127    U64(0xA4FC4BD4FC5558CA), U64(0xE755178D58FC4E76), U64(0x69B97DB1A4C03DFE), U64(0xF9B5B7C4ACC67C96),
128    U64(0xFC6A82D64B8655FB), U64(0x9C684CB6C4D24417), U64(0x8EC97D2917456ED0), U64(0x6703DF9D2924E97E),
129    U64(0xC547F57E42A7444E), U64(0x78E37644E7CAD29E), U64(0xFE9A44E9362F05FA), U64(0x08BD35CC38336615),
130    U64(0x9315E5EB3A129ACE), U64(0x94061B871E04DF75), U64(0xDF1D9F9D784BA010), U64(0x3BBA57B68871B59D),
131    U64(0xD2B7ADEEDED1F73F), U64(0xF7A255D83BC373F8), U64(0xD7F4F2448C0CEB81), U64(0xD95BE88CD210FFA7),
132    U64(0x336F52F8FF4728E7), U64(0xA74049DAC312AC71), U64(0xA2F61BB6E437FDB5), U64(0x4F2A5CB07F6A35B3),
133    U64(0x87D380BDA5BF7859), U64(0x16B9F7E06C453A21), U64(0x7BA2484C8A0FD54E), U64(0xF3A678CAD9A2E38C),
134    U64(0x39B0BF7DDE437BA2), U64(0xFCAF55C1BF8A4424), U64(0x18FCF680573FA594), U64(0x4C0563B89F495AC3),
135    U64(0x40E087931A00930D), U64(0x8CFFA9412EB642C1), U64(0x68CA39053261169F), U64(0x7A1EE967D27579E2),
136    U64(0x9D1D60E5076F5B6F), U64(0x3810E399B6F65BA2), U64(0x32095B6D4AB5F9B1), U64(0x35CAB62109DD038A),
137    U64(0xA90B24499FCFAFB1), U64(0x77A225A07CC2C6BD), U64(0x513E5E634C70E331), U64(0x4361C0CA3F692F12),
138    U64(0xD941ACA44B20A45B), U64(0x528F7C8602C5807B), U64(0x52AB92BEB9613989), U64(0x9D1DFA2EFC557F73),
139    U64(0x722FF175F572C348), U64(0x1D1260A51107FE97), U64(0x7A249A57EC0C9BA2), U64(0x04208FE9E8F7F2D6),
140    U64(0x5A110C6058B920A0), U64(0x0CD9A497658A5698), U64(0x56FD23C8F9715A4C), U64(0x284C847B9D887AAE),
141    U64(0x04FEABFBBDB619CB), U64(0x742E1E651C60BA83), U64(0x9A9632E65904AD3C), U64(0x881B82A13B51B9E2),
142    U64(0x506E6744CD974924), U64(0xB0183DB56FFC6A79), U64(0x0ED9B915C66ED37E), U64(0x5E11E86D5873D484),
143    U64(0xF678647E3519AC6E), U64(0x1B85D488D0F20CC5), U64(0xDAB9FE6525D89021), U64(0x0D151D86ADB73615),
144    U64(0xA865A54EDCC0F019), U64(0x93C42566AEF98FFB), U64(0x99E7AFEABE000731), U64(0x48CBFF086DDF285A),
145    U64(0x7F9B6AF1EBF78BAF), U64(0x58627E1A149BBA21), U64(0x2CD16E2ABD791E33), U64(0xD363EFF5F0977996),
146    U64(0x0CE2A38C344A6EED), U64(0x1A804AADB9CFA741), U64(0x907F30421D78C5DE), U64(0x501F65EDB3034D07),
147    U64(0x37624AE5A48FA6E9), U64(0x957BAF61700CFF4E), U64(0x3A6C27934E31188A), U64(0xD49503536ABCA345),
148    U64(0x088E049589C432E0), U64(0xF943AEE7FEBF21B8), U64(0x6C3B8E3E336139D3), U64(0x364F6FFA464EE52E),
149    U64(0xD60F6DCEDC314222), U64(0x56963B0DCA418FC0), U64(0x16F50EDF91E513AF), U64(0xEF1955914B609F93),
150    U64(0x565601C0364E3228), U64(0xECB53939887E8175), U64(0xBAC7A9A18531294B), U64(0xB344C470397BBA52),
151    U64(0x65D34954DAF3CEBD), U64(0xB4B81B3FA97511E2), U64(0xB422061193D6F6A7), U64(0x071582401C38434D),
152    U64(0x7A13F18BBEDC4FF5), U64(0xBC4097B116C524D2), U64(0x59B97885E2F2EA28), U64(0x99170A5DC3115544),
153    U64(0x6F423357E7C6A9F9), U64(0x325928EE6E6F8794), U64(0xD0E4366228B03343), U64(0x565C31F7DE89EA27),
154    U64(0x30F5611484119414), U64(0xD873DB391292ED4F), U64(0x7BD94E1D8E17DEBC), U64(0xC7D9F16864A76E94),
155    U64(0x947AE053EE56E63C), U64(0xC8C93882F9475F5F), U64(0x3A9BF55BA91F81CA), U64(0xD9A11FBB3D9808E4),
156    U64(0x0FD22063EDC29FCA), U64(0xB3F256D8ACA0B0B9), U64(0xB03031A8B4516E84), U64(0x35DD37D5871448AF),
157    U64(0xE9F6082B05542E4E), U64(0xEBFAFA33D7254B59), U64(0x9255ABB50D532280), U64(0xB9AB4CE57F2D34F3),
158    U64(0x693501D628297551), U64(0xC62C58F97DD949BF), U64(0xCD454F8F19C5126A), U64(0xBBE83F4ECC2BDECB),
159    U64(0xDC842B7E2819E230), U64(0xBA89142E007503B8), U64(0xA3BC941D0A5061CB), U64(0xE9F6760E32CD8021),
160    U64(0x09C7E552BC76492F), U64(0x852F54934DA55CC9), U64(0x8107FCCF064FCF56), U64(0x098954D51FFF6580),
161    U64(0x23B70EDB1955C4BF), U64(0xC330DE426430F69D), U64(0x4715ED43E8A45C0A), U64(0xA8D7E4DAB780A08D),
162    U64(0x0572B974F03CE0BB), U64(0xB57D2E985E1419C7), U64(0xE8D9ECBE2CF3D73F), U64(0x2FE4B17170E59750),
163    U64(0x11317BA87905E790), U64(0x7FBF21EC8A1F45EC), U64(0x1725CABFCB045B00), U64(0x964E915CD5E2B207),
164    U64(0x3E2B8BCBF016D66D), U64(0xBE7444E39328A0AC), U64(0xF85B2B4FBCDE44B7), U64(0x49353FEA39BA63B1),
165    U64(0x1DD01AAFCD53486A), U64(0x1FCA8A92FD719F85), U64(0xFC7C95D827357AFA), U64(0x18A6A990C8B35EBD),
166    U64(0xCCCB7005C6B9C28D), U64(0x3BDBB92C43B17F26), U64(0xAA70B5B4F89695A2), U64(0xE94C39A54A98307F),
167    U64(0xB7A0B174CFF6F36E), U64(0xD4DBA84729AF48AD), U64(0x2E18BC1AD9704A68), U64(0x2DE0966DAF2F8B1C),
168    U64(0xB9C11D5B1E43A07E), U64(0x64972D68DEE33360), U64(0x94628D38D0C20584), U64(0xDBC0D2B6AB90A559),
169    U64(0xD2733C4335C6A72F), U64(0x7E75D99D94A70F4D), U64(0x6CED1983376FA72B), U64(0x97FCAACBF030BC24),
170    U64(0x7B77497B32503B12), U64(0x8547EDDFB81CCB94), U64(0x79999CDFF70902CB), U64(0xCFFE1939438E9B24),
171    U64(0x829626E3892D95D7), U64(0x92FAE24291F2B3F1), U64(0x63E22C147B9C3403), U64(0xC678B6D860284A1C),
172    U64(0x5873888850659AE7), U64(0x0981DCD296A8736D), U64(0x9F65789A6509A440), U64(0x9FF38FED72E9052F),
173    U64(0xE479EE5B9930578C), U64(0xE7F28ECD2D49EECD), U64(0x56C074A581EA17FE), U64(0x5544F7D774B14AEF),
174    U64(0x7B3F0195FC6F290F), U64(0x12153635B2C0CF57), U64(0x7F5126DBBA5E0CA7), U64(0x7A76956C3EAFB413),
175    U64(0x3D5774A11D31AB39), U64(0x8A1B083821F40CB4), U64(0x7B4A38E32537DF62), U64(0x950113646D1D6E03),
176    U64(0x4DA8979A0041E8A9), U64(0x3BC36E078F7515D7), U64(0x5D0A12F27AD310D1), U64(0x7F9D1A2E1EBE1327),
177    U64(0xDA3A361B1C5157B1), U64(0xDCDD7D20903D0C25), U64(0x36833336D068F707), U64(0xCE68341F79893389),
178    U64(0xAB9090168DD05F34), U64(0x43954B3252DC25E5), U64(0xB438C2B67F98E5E9), U64(0x10DCD78E3851A492),
179    U64(0xDBC27AB5447822BF), U64(0x9B3CDB65F82CA382), U64(0xB67B7896167B4C84), U64(0xBFCED1B0048EAC50),
180    U64(0xA9119B60369FFEBD), U64(0x1FFF7AC80904BF45), U64(0xAC12FB171817EEE7), U64(0xAF08DA9177DDA93D),
181    U64(0x1B0CAB936E65C744), U64(0xB559EB1D04E5E932), U64(0xC37B45B3F8D6F2BA), U64(0xC3A9DC228CAAC9E9),
182    U64(0xF3B8B6675A6507FF), U64(0x9FC477DE4ED681DA), U64(0x67378D8ECCEF96CB), U64(0x6DD856D94D259236),
183    U64(0xA319CE15B0B4DB31), U64(0x073973751F12DD5E), U64(0x8A8E849EB32781A5), U64(0xE1925C71285279F5),
184    U64(0x74C04BF1790C0EFE), U64(0x4DDA48153C94938A), U64(0x9D266D6A1CC0542C), U64(0x7440FB816508C4FE),
185    U64(0x13328503DF48229F), U64(0xD6BF7BAEE43CAC40), U64(0x4838D65F6EF6748F), U64(0x1E152328F3318DEA),
186    U64(0x8F8419A348F296BF), U64(0x72C8834A5957B511), U64(0xD7A023A73260B45C), U64(0x94EBC8ABCFB56DAE),
187    U64(0x9FC10D0F989993E0), U64(0xDE68A2355B93CAE6), U64(0xA44CFE79AE538BBE), U64(0x9D1D84FCCE371425),
188    U64(0x51D2B1AB2DDFB636), U64(0x2FD7E4B9E72CD38C), U64(0x65CA5B96B7552210), U64(0xDD69A0D8AB3B546D),
189    U64(0x604D51B25FBF70E2), U64(0x73AA8A564FB7AC9E), U64(0x1A8C1E992B941148), U64(0xAAC40A2703D9BEA0),
190    U64(0x764DBEAE7FA4F3A6), U64(0x1E99B96E70A9BE8B), U64(0x2C5E9DEB57EF4743), U64(0x3A938FEE32D29981),
191    U64(0x26E6DB8FFDF5ADFE), U64(0x469356C504EC9F9D), U64(0xC8763C5B08D1908C), U64(0x3F6C6AF859D80055),
192    U64(0x7F7CC39420A3A545), U64(0x9BFB227EBDF4C5CE), U64(0x89039D79D6FC5C5C), U64(0x8FE88B57305E2AB6),
193    U64(0xA09E8C8C35AB96DE), U64(0xFA7E393983325753), U64(0xD6B6D0ECC617C699), U64(0xDFEA21EA9E7557E3),
194    U64(0xB67C1FA481680AF8), U64(0xCA1E3785A9E724E5), U64(0x1CFC8BED0D681639), U64(0xD18D8549D140CAEA),
195    U64(0x4ED0FE7E9DC91335), U64(0xE4DBF0634473F5D2), U64(0x1761F93A44D5AEFE), U64(0x53898E4C3910DA55),
196    U64(0x734DE8181F6EC39A), U64(0x2680B122BAA28D97), U64(0x298AF231C85BAFAB), U64(0x7983EED3740847D5),
197    U64(0x66C1A2A1A60CD889), U64(0x9E17E49642A3E4C1), U64(0xEDB454E7BADC0805), U64(0x50B704CAB602C329),
198    U64(0x4CC317FB9CDDD023), U64(0x66B4835D9EAFEA22), U64(0x219B97E26FFC81BD), U64(0x261E4E4C0A333A9D),
199    U64(0x1FE2CCA76517DB90), U64(0xD7504DFA8816EDBB), U64(0xB9571FA04DC089C8), U64(0x1DDC0325259B27DE),
200    U64(0xCF3F4688801EB9AA), U64(0xF4F5D05C10CAB243), U64(0x38B6525C21A42B0E), U64(0x36F60E2BA4FA6800),
201    U64(0xEB3593803173E0CE), U64(0x9C4CD6257C5A3603), U64(0xAF0C317D32ADAA8A), U64(0x258E5A80C7204C4B),
202    U64(0x8B889D624D44885D), U64(0xF4D14597E660F855), U64(0xD4347F66EC8941C3), U64(0xE699ED85B0DFB40D),
203    U64(0x2472F6207C2D0484), U64(0xC2A1E7B5B459AEB5), U64(0xAB4F6451CC1D45EC), U64(0x63767572AE3D6174),
204    U64(0xA59E0BD101731A28), U64(0x116D0016CB948F09), U64(0x2CF9C8CA052F6E9F), U64(0x0B090A7560A968E3),
205    U64(0xABEEDDB2DDE06FF1), U64(0x58EFC10B06A2068D), U64(0xC6E57A78FBD986E0), U64(0x2EAB8CA63CE802D7),
206    U64(0x14A195640116F336), U64(0x7C0828DD624EC390), U64(0xD74BBE77E6116AC7), U64(0x804456AF10F5FB53),
207    U64(0xEBE9EA2ADF4321C7), U64(0x03219A39EE587A30), U64(0x49787FEF17AF9924), U64(0xA1E9300CD8520548),
208    U64(0x5B45E522E4B1B4EF), U64(0xB49C3B3995091A36), U64(0xD4490AD526F14431), U64(0x12A8F216AF9418C2),
209    U64(0x001F837CC7350524), U64(0x1877B51E57A764D5), U64(0xA2853B80F17F58EE), U64(0x993E1DE72D36D310),
210    U64(0xB3598080CE64A656), U64(0x252F59CF0D9F04BB), U64(0xD23C8E176D113600), U64(0x1BDA0492E7E4586E),
211    U64(0x21E0BD5026C619BF), U64(0x3B097ADAF088F94E), U64(0x8D14DEDB30BE846E), U64(0xF95CFFA23AF5F6F4),
212    U64(0x3871700761B3F743), U64(0xCA672B91E9E4FA16), U64(0x64C8E531BFF53B55), U64(0x241260ED4AD1E87D),
213    U64(0x106C09B972D2E822), U64(0x7FBA195410E5CA30), U64(0x7884D9BC6CB569D8), U64(0x0647DFEDCD894A29),
214    U64(0x63573FF03E224774), U64(0x4FC8E9560F91B123), U64(0x1DB956E450275779), U64(0xB8D91274B9E9D4FB),
215    U64(0xA2EBEE47E2FBFCE1), U64(0xD9F1F30CCD97FB09), U64(0xEFED53D75FD64E6B), U64(0x2E6D02C36017F67F),
216    U64(0xA9AA4D20DB084E9B), U64(0xB64BE8D8B25396C1), U64(0x70CB6AF7C2D5BCF0), U64(0x98F076A4F7A2322E),
217    U64(0xBF84470805E69B5F), U64(0x94C3251F06F90CF3), U64(0x3E003E616A6591E9), U64(0xB925A6CD0421AFF3),
218    U64(0x61BDD1307C66E300), U64(0xBF8D5108E27E0D48), U64(0x240AB57A8B888B20), U64(0xFC87614BAF287E07),
219    U64(0xEF02CDD06FFDB432), U64(0xA1082C0466DF6C0A), U64(0x8215E577001332C8), U64(0xD39BB9C3A48DB6CF),
220    U64(0x2738259634305C14), U64(0x61CF4F94C97DF93D), U64(0x1B6BACA2AE4E125B), U64(0x758F450C88572E0B),
221    U64(0x959F587D507A8359), U64(0xB063E962E045F54D), U64(0x60E8ED72C0DFF5D1), U64(0x7B64978555326F9F),
222    U64(0xFD080D236DA814BA), U64(0x8C90FD9B083F4558), U64(0x106F72FE81E2C590), U64(0x7976033A39F7D952),
223    U64(0xA4EC0132764CA04B), U64(0x733EA705FAE4FA77), U64(0xB4D8F77BC3E56167), U64(0x9E21F4F903B33FD9),
224    U64(0x9D765E419FB69F6D), U64(0xD30C088BA61EA5EF), U64(0x5D94337FBFAF7F5B), U64(0x1A4E4822EB4D7A59),
225    U64(0x6FFE73E81B637FB3), U64(0xDDF957BC36D8B9CA), U64(0x64D0E29EEA8838B3), U64(0x08DD9BDFD96B9F63),
226    U64(0x087E79E5A57D1D13), U64(0xE328E230E3E2B3FB), U64(0x1C2559E30F0946BE), U64(0x720BF5F26F4D2EAA),
227    U64(0xB0774D261CC609DB), U64(0x443F64EC5A371195), U64(0x4112CF68649A260E), U64(0xD813F2FAB7F5C5CA),
228    U64(0x660D3257380841EE), U64(0x59AC2C7873F910A3), U64(0xE846963877671A17), U64(0x93B633ABFA3469F8),
229    U64(0xC0C0F5A60EF4CDCF), U64(0xCAF21ECD4377B28C), U64(0x57277707199B8175), U64(0x506C11B9D90E8B1D),
230    U64(0xD83CC2687A19255F), U64(0x4A29C6465A314CD1), U64(0xED2DF21216235097), U64(0xB5635C95FF7296E2),
231    U64(0x22AF003AB672E811), U64(0x52E762596BF68235), U64(0x9AEBA33AC6ECC6B0), U64(0x944F6DE09134DFB6),
232    U64(0x6C47BEC883A7DE39), U64(0x6AD047C430A12104), U64(0xA5B1CFDBA0AB4067), U64(0x7C45D833AFF07862),
233    U64(0x5092EF950A16DA0B), U64(0x9338E69C052B8E7B), U64(0x455A4B4CFE30E3F5), U64(0x6B02E63195AD0CF8),
234    U64(0x6B17B224BAD6BF27), U64(0xD1E0CCD25BB9C169), U64(0xDE0C89A556B9AE70), U64(0x50065E535A213CF6),
235    U64(0x9C1169FA2777B874), U64(0x78EDEFD694AF1EED), U64(0x6DC93D9526A50E68), U64(0xEE97F453F06791ED),
236    U64(0x32AB0EDB696703D3), U64(0x3A6853C7E70757A7), U64(0x31865CED6120F37D), U64(0x67FEF95D92607890),
237    U64(0x1F2B1D1F15F6DC9C), U64(0xB69E38A8965C6B65), U64(0xAA9119FF184CCCF4), U64(0xF43C732873F24C13),
238    U64(0xFB4A3D794A9A80D2), U64(0x3550C2321FD6109C), U64(0x371F77E76BB8417E), U64(0x6BFA9AAE5EC05779),
239    U64(0xCD04F3FF001A4778), U64(0xE3273522064480CA), U64(0x9F91508BFFCFC14A), U64(0x049A7F41061A9E60),
240    U64(0xFCB6BE43A9F2FE9B), U64(0x08DE8A1C7797DA9B), U64(0x8F9887E6078735A1), U64(0xB5B4071DBFC73A66),
241    U64(0x230E343DFBA08D33), U64(0x43ED7F5A0FAE657D), U64(0x3A88A0FBBCB05C63), U64(0x21874B8B4D2DBC4F),
242    U64(0x1BDEA12E35F6A8C9), U64(0x53C065C6C8E63528), U64(0xE34A1D250E7A8D6B), U64(0xD6B04D3B7651DD7E),
243    U64(0x5E90277E7CB39E2D), U64(0x2C046F22062DC67D), U64(0xB10BB459132D0A26), U64(0x3FA9DDFB67E2F199),
244    U64(0x0E09B88E1914F7AF), U64(0x10E8B35AF3EEAB37), U64(0x9EEDECA8E272B933), U64(0xD4C718BC4AE8AE5F),
245    U64(0x81536D601170FC20), U64(0x91B534F885818A06), U64(0xEC8177F83F900978), U64(0x190E714FADA5156E),
246    U64(0xB592BF39B0364963), U64(0x89C350C893AE7DC1), U64(0xAC042E70F8B383F2), U64(0xB49B52E587A1EE60),
247    U64(0xFB152FE3FF26DA89), U64(0x3E666E6F69AE2C15), U64(0x3B544EBE544C19F9), U64(0xE805A1E290CF2456),
248    U64(0x24B33C9D7ED25117), U64(0xE74733427B72F0C1), U64(0x0A804D18B7097475), U64(0x57E3306D881EDB4F),
249    U64(0x4AE7D6A36EB5DBCB), U64(0x2D8D5432157064C8), U64(0xD1E649DE1E7F268B), U64(0x8A328A1CEDFE552C),
250    U64(0x07A3AEC79624C7DA), U64(0x84547DDC3E203C94), U64(0x990A98FD5071D263), U64(0x1A4FF12616EEFC89),
251    U64(0xF6F7FD1431714200), U64(0x30C05B1BA332F41C), U64(0x8D2636B81555A786), U64(0x46C9FEB55D120902),
252    U64(0xCCEC0A73B49C9921), U64(0x4E9D2827355FC492), U64(0x19EBB029435DCB0F), U64(0x4659D2B743848A2C),
253    U64(0x963EF2C96B33BE31), U64(0x74F85198B05A2E7D), U64(0x5A0F544DD2B1FB18), U64(0x03727073C2E134B1),
254    U64(0xC7F6AA2DE59AEA61), U64(0x352787BAA0D7C22F), U64(0x9853EAB63B5E0B35), U64(0xABBDCDD7ED5C0860),
255    U64(0xCF05DAF5AC8D77B0), U64(0x49CAD48CEBF4A71E), U64(0x7A4C10EC2158C4A6), U64(0xD9E92AA246BF719E),
256    U64(0x13AE978D09FE5557), U64(0x730499AF921549FF), U64(0x4E4B705B92903BA4), U64(0xFF577222C14F0A3A),
257    U64(0x55B6344CF97AAFAE), U64(0xB862225B055B6960), U64(0xCAC09AFBDDD2CDB4), U64(0xDAF8E9829FE96B5F),
258    U64(0xB5FDFC5D3132C498), U64(0x310CB380DB6F7503), U64(0xE87FBB46217A360E), U64(0x2102AE466EBB1148),
259    U64(0xF8549E1A3AA5E00D), U64(0x07A69AFDCC42261A), U64(0xC4C118BFE78FEAAE), U64(0xF9F4892ED96BD438),
260    U64(0x1AF3DBE25D8F45DA), U64(0xF5B4B0B0D2DEEEB4), U64(0x962ACEEFA82E1C84), U64(0x046E3ECAAF453CE9),
261    U64(0xF05D129681949A4C), U64(0x964781CE734B3C84), U64(0x9C2ED44081CE5FBD), U64(0x522E23F3925E319E),
262    U64(0x177E00F9FC32F791), U64(0x2BC60A63A6F3B3F2), U64(0x222BBFAE61725606), U64(0x486289DDCC3D6780),
263    U64(0x7DC7785B8EFDFC80), U64(0x8AF38731C02BA980), U64(0x1FAB64EA29A2DDF7), U64(0xE4D9429322CD065A),
264    U64(0x9DA058C67844F20C), U64(0x24C0E332B70019B0), U64(0x233003B5A6CFE6AD), U64(0xD586BD01C5C217F6),
265    U64(0x5E5637885F29BC2B), U64(0x7EBA726D8C94094B), U64(0x0A56A5F0BFE39272), U64(0xD79476A84EE20D06),
266    U64(0x9E4C1269BAA4BF37), U64(0x17EFEE45B0DEE640), U64(0x1D95B0A5FCF90BC6), U64(0x93CBE0B699C2585D),
267    U64(0x65FA4F227A2B6D79), U64(0xD5F9E858292504D5), U64(0xC2B5A03F71471A6F), U64(0x59300222B4561E00),
268    U64(0xCE2F8642CA0712DC), U64(0x7CA9723FBB2E8988), U64(0x2785338347F2BA08), U64(0xC61BB3A141E50E8C),
269    U64(0x150F361DAB9DEC26), U64(0x9F6A419D382595F4), U64(0x64A53DC924FE7AC9), U64(0x142DE49FFF7A7C3D),
270    U64(0x0C335248857FA9E7), U64(0x0A9C32D5EAE45305), U64(0xE6C42178C4BBB92E), U64(0x71F1CE2490D20B07),
271    U64(0xF1BCC3D275AFE51A), U64(0xE728E8C83C334074), U64(0x96FBF83A12884624), U64(0x81A1549FD6573DA5),
272    U64(0x5FA7867CAF35E149), U64(0x56986E2EF3ED091B), U64(0x917F1DD5F8886C61), U64(0xD20D8C88C8FFE65F),
273    U64(0x31D71DCE64B2C310), U64(0xF165B587DF898190), U64(0xA57E6339DD2CF3A0), U64(0x1EF6E6DBB1961EC9),
274    U64(0x70CC73D90BC26E24), U64(0xE21A6B35DF0C3AD7), U64(0x003A93D8B2806962), U64(0x1C99DED33CB890A1),
275    U64(0xCF3145DE0ADD4289), U64(0xD0E4427A5514FB72), U64(0x77C621CC9FB3A483), U64(0x67A34DAC4356550B),
276    U64(0xF8D626AAAF278509),
277 };
278
279 uint64 *RandomPiece     =Random64;
280 uint64 *RandomCastle    =Random64+768;
281 uint64 *RandomEnPassant =Random64+772;
282 uint64 *RandomTurn      =Random64+780;
283
284
285 uint64
286 hash (int moveNr)
287 {
288     int r, f, p_enc, squareNr, pieceGroup;
289     uint64 key=0, holdingsKey=0, Zobrist;
290     VariantClass v = gameInfo.variant;
291
292     switch(v) {
293         case VariantNormal:
294         case VariantFischeRandom: // compatible with normal
295         case VariantNoCastle:
296         case VariantXiangqi: // for historic reasons; does never collide anyway because of other King type
297             break;
298         case VariantGiveaway: // in opening same as suicide
299             key += VariantSuicide;
300             break;
301         case VariantGothic: // these are special cases of CRC, and can share book
302         case VariantCapablanca:
303             v = VariantCapaRandom;
304         default:
305             key += v; // variant type incorporated in key to allow mixed books without collisions
306     }
307
308     for(f=0; f<BOARD_WIDTH; f++){
309         for(r=0; r<BOARD_HEIGHT;r++){
310             ChessSquare p = boards[moveNr][r][f];
311             if(f == BOARD_LEFT-1 || f == BOARD_RGHT) continue; // between board and holdings
312             if(p != EmptySquare){
313                     int j = (int)p;
314                     j -= (j >= (int)BlackPawn) ? (int)BlackPawn :(int)WhitePawn;
315                     if(j > (int)WhiteQueen) j++;  // make space for King
316                     if(j > (int) WhiteKing) j = (int)WhiteQueen + 1;
317                     p_enc = 2*j + ((int)p < (int)BlackPawn);
318                     // holdings squares get nmbers immediately after board; first left, then right holdings
319                     if(f == BOARD_LEFT-2) squareNr = (BOARD_RGHT - BOARD_LEFT)*BOARD_HEIGHT + r; else
320                     if(f == BOARD_RGHT+1) squareNr = (BOARD_RGHT - BOARD_LEFT + 1)*BOARD_HEIGHT + r; else
321                     squareNr = (BOARD_RGHT - BOARD_LEFT)*r + (f - BOARD_LEFT);
322                     // note that in normal Chess squareNr < 64 and p_enc < 12. The following code
323                     // maps other pieces and squares in this range, and then modify the corresponding
324                     // Zobrist random by rotating its bitpattern according to what the piece really was.
325                     pieceGroup = p_enc / 12;
326                     p_enc      = p_enc % 12;
327                     Zobrist = RandomPiece[64*p_enc + (squareNr & 63)];
328                     switch(pieceGroup) {
329                         case 1: // pieces 5-10 (FEACWM)
330                                 Zobrist = (Zobrist << 16) ^ (Zobrist >> 48);
331                                 break;
332                         case 2: // pieces 11-16 (OHIJGD)
333                                 Zobrist = (Zobrist << 32) ^ (Zobrist >> 32);
334                                 break;
335                         case 3: // pieces 17-20 (VLSU)
336                                 Zobrist = (Zobrist << 48) ^ (Zobrist >> 16);
337                                 break;
338                     }
339                     if(squareNr >= 64) Zobrist = (Zobrist << 8) ^ (Zobrist >> 56);
340                     // holdings have separate (additive) key, to encode presence of multiple pieces on same square
341                     if(f == BOARD_LEFT-2) holdingsKey += Zobrist * boards[moveNr][r][f+1]; else
342                     if(f == BOARD_RGHT+1) holdingsKey += Zobrist * boards[moveNr][r][f-1]; else
343                 key ^= Zobrist;
344             }
345         }
346     }
347
348     if(boards[moveNr][CASTLING][2] != NoRights) {
349         if(boards[moveNr][CASTLING][0] != NoRights) key^=RandomCastle[0];
350         if(boards[moveNr][CASTLING][1] != NoRights) key^=RandomCastle[1];
351     }
352     if(boards[moveNr][CASTLING][5] != NoRights) {
353         if(boards[moveNr][CASTLING][3] != NoRights) key^=RandomCastle[2];
354         if(boards[moveNr][CASTLING][4] != NoRights) key^=RandomCastle[3];
355     }
356
357     f = boards[moveNr][EP_STATUS];
358     if(f >= 0 && f < 8){
359         if(!WhiteOnMove(moveNr)){
360             // the test for neighboring Pawns might not be needed, 
361             // as epStatus already kept track of it, but better safe than sorry.
362             if((f>0 && boards[moveNr][3][f-1]==BlackPawn)||
363                (f<7 && boards[moveNr][3][f+1]==BlackPawn)){
364                 key^=RandomEnPassant[f];
365             }
366         }else{
367             if((f>0 && boards[moveNr][4][f-1]==WhitePawn)||
368                (f<7 && boards[moveNr][4][f+1]==WhitePawn)){
369                 key^=RandomEnPassant[f];
370             }
371         }
372     }
373
374     if(WhiteOnMove(moveNr)){
375         key^=RandomTurn[0];
376     }
377     return key + holdingsKey;
378 }
379
380 #define MOVE_BUF 100
381
382 int
383 int_from_file (FILE *f, int l, uint64 *r)
384 {
385     int i,c;
386     for(i=0;i<l;i++){
387         c=fgetc(f);
388         if(c==EOF){
389             return 1;
390         }
391         (*r)=((*r)<<8)+c;
392     }
393     return 0;
394 }
395
396 int
397 entry_from_file (FILE *f, entry_t *entry)
398 {
399     int ret;
400     uint64 r;
401     ret=int_from_file(f,8,&r);
402     if(ret) return 1;
403     entry->key=r;
404     ret=int_from_file(f,2,&r);
405     if(ret) return 1;
406     entry->move=r;
407     ret=int_from_file(f,2,&r);
408     if(ret) return 1;
409     entry->weight=r;
410     ret=int_from_file(f,2,&r);
411     if(ret) return 1;
412     entry->learnCount=r;
413     ret=int_from_file(f,2,&r);
414     if(ret) return 1;
415     entry->learnPoints=r;
416     return 0;
417 }
418
419 int
420 find_key (FILE *f, uint64 key, entry_t *entry)
421 {
422     int first, last, middle;
423     entry_t first_entry=entry_none, last_entry,middle_entry;
424     first=-1;
425     if(fseek(f,-16,SEEK_END)){
426         *entry=entry_none;
427         entry->key=key+1; //hack
428         return -1;
429     }
430     last=ftell(f)/16;
431     entry_from_file(f,&last_entry);
432     while(1){
433         if(last-first==1){
434             *entry=last_entry;
435             return last;
436         }
437         middle=(first+last)/2;
438         fseek(f,16*middle,SEEK_SET);
439         entry_from_file(f,&middle_entry);
440         if(key<=middle_entry.key){
441             last=middle;
442             last_entry=middle_entry;
443         }else{
444             first=middle;
445             first_entry=middle_entry;
446         }
447     }
448 }
449
450 void
451 move_to_string (char move_s[6], uint16 move)
452 {
453     int f,fr,ff,t,tr,tf,p;
454     int width = BOARD_RGHT - BOARD_LEFT, size; // allow for alternative board formats
455
456     size = width * BOARD_HEIGHT;
457     f  = move / size;
458     fr = f / width;
459     ff = f % width;
460     t  = move % size;
461     tr = t / width;
462     tf = t % width;
463     p = move / (size*size);
464     move_s[0] = ff + 'a';
465     move_s[1] = fr + '1' - (BOARD_HEIGHT > 9);
466     move_s[2] = tf + 'a';
467     move_s[3] = tr + '1' - (BOARD_HEIGHT > 9);
468
469     // kludge: encode drops as special promotion code
470     if(gameInfo.holdingsSize && p == 8) {
471         move_s[0] = f + '@'; // from square encodes piece type
472         move_s[1] = '@';     // drop symbol
473         p = 0;
474     }
475
476     // add promotion piece, if any
477     if(p){
478         move_s[4] = promote_pieces[p];
479         move_s[5] = '\0';
480     }else{
481         move_s[4] = '\0';
482     }
483
484     if(gameInfo.variant != VariantNormal) return;
485
486     // correct FRC-style castlings in variant normal. 
487     // [HGM] This is buggy code! e1h1 could very well be a normal R or Q move.
488     if(!strcmp(move_s,"e1h1")){
489       safeStrCpy(move_s,"e1g1", 6);
490     }else  if(!strcmp(move_s,"e1a1")){
491       safeStrCpy(move_s,"e1c1", 6);
492     }else  if(!strcmp(move_s,"e8h8")){
493       safeStrCpy(move_s,"e8g8", 6);
494     }else  if(!strcmp(move_s,"e8a8")){
495       safeStrCpy(move_s,"e8c8", 6);
496     }
497 }
498
499 int
500 GetBookMoves (int moveNr, char *book, entry_t entries[])
501 {   // retrieve all entries for given position from book in 'entries', return number.
502     static FILE *f = NULL;
503     static char curBook[MSG_SIZ];
504     entry_t entry;
505     int offset;
506     uint64 key;
507     int count;
508     int ret;
509
510     if(book == NULL || moveNr >= 2*appData.bookDepth) return -1; 
511 //    if(gameInfo.variant != VariantNormal) return -1; // Zobrist scheme only works for normal Chess, so far
512     if(!f || strcmp(book, curBook)){ // keep book file open until book changed
513         strncpy(curBook, book, MSG_SIZ);
514         if(f) fclose(f);
515         f = fopen(book,"rb");
516     }
517     if(!f){
518         DisplayError(_("Polyglot book not valid"), 0);
519         appData.usePolyglotBook = FALSE;
520         return -1;
521     }
522
523     key = hash(moveNr);
524     if(appData.debugMode) fprintf(debugFP, "book key = %08x%08x\n", (unsigned int)(key>>32), (unsigned int)key);
525
526     offset=find_key(f, key, &entry);
527     if(entry.key != key) {
528           return FALSE;
529     }
530     entries[0] = entry;
531     count=1;
532     fseek(f, 16*(offset+1), SEEK_SET);
533     while(1){
534         ret=entry_from_file(f, &entry);
535         if(ret){
536             break;
537         }
538         if(entry.key != key){
539             break;
540         }
541         if(count == MOVE_BUF) break;
542         entries[count++] = entry;
543     }
544     return count;
545 }
546
547 char *
548 ProbeBook (int moveNr, char *book)
549 {
550     entry_t entries[MOVE_BUF];
551     int count;
552     int i, j;
553     static char move_s[6];
554     int total_weight;
555
556     if((count = GetBookMoves(moveNr, book, entries)) <= 0) return NULL; // no book, or no hit
557
558     if(appData.bookStrength != 50) { // transform weights
559         double power = 0, maxWeight = 0.0;
560         if(appData.bookStrength) power = (100.-appData.bookStrength)/appData.bookStrength;
561         for(i=0; i<count; i++) if(entries[i].weight > maxWeight) maxWeight = entries[i].weight;
562         for(i=0; i<count; i++){
563             double weight = entries[i].weight / maxWeight;
564               if(weight > 0)
565                 entries[i].weight = appData.bookStrength || weight == 1.0 ? 1e4*exp(power * log(weight)) + 0.5 : 0.0;
566         }
567     }
568     total_weight = 0;
569     for(i=0; i<count; i++){
570         total_weight += entries[i].weight;
571     }
572     if(total_weight == 0) return NULL; // force book miss rather than playing moves with weight 0.
573     j = (random() & 0xFFF) * total_weight >> 12; // create random < total_weight
574     total_weight = 0;
575     for(i=0; i<count; i++){
576         total_weight += entries[i].weight;
577         if(total_weight > j) break;
578     }
579     if(i >= count) DisplayFatalError(_("Book Fault"), 0, 1); // safety catch, cannot happen
580     move_to_string(move_s, entries[i].move);
581     if(appData.debugMode) fprintf(debugFP, "book move field = %d\n", entries[i].move);
582
583     return move_s;
584 }
585
586 extern char yy_textstr[];
587 entry_t lastEntries[MOVE_BUF];
588
589 char *
590 MovesToText (int count, entry_t *entries)
591 {
592         int i, totalWeight = 0;
593         char algMove[6];
594         char *p = (char*) malloc(30*count+1);
595         for(i=0; i<count; i++) totalWeight += entries[i].weight;
596         *p = 0;
597         for(i=0; i<count; i++) {
598             char buf[MSG_SIZ];
599             move_to_string(algMove, entries[i].move);
600             buf[0] = NULLCHAR;
601             if(entries[i].learnCount || entries[i].learnPoints)
602                 snprintf(buf, MSG_SIZ, " {%d/%d}", entries[i].learnPoints, entries[i].learnCount);
603             snprintf(p+strlen(p), 30, "%5.1f%% %5d %s%s\n", 100*entries[i].weight/(totalWeight+0.001),
604                                         entries[i].weight, algMove, buf);
605 //lastEntries[i] = entries[i];
606         }
607         return p;
608 }
609
610 int
611 TextToMoves (char *text, int moveNum, entry_t *entries)
612 {
613         int i, w, count=0;
614       uint64 hashKey = hash(moveNum);
615         int  fromX, fromY, toX, toY, to, from;
616         ChessMove  moveType;
617         char promoChar, valid;
618         float dummy;
619         int width = BOARD_RGHT - BOARD_LEFT;
620
621         entries[0].key = hashKey; // make sure key is returned even if no moves
622         while((i=sscanf(text, "%f%%%d", &dummy, &w))==2 || (i=sscanf(text, "%d", &w))==1) {
623             if(i == 2) text = strchr(text, '%') + 1;  // skip percentage
624             if(w == 1) text = strstr(text, "1 ") + 2; // skip weight that could be recognized as move number one
625             valid = ParseOneMove(text, moveNum, &moveType, &fromX, &fromY, &toX, &toY, &promoChar);
626             text = strstr(text, yy_textstr) + strlen(yy_textstr); // skip what we parsed
627             if(!valid || moveType != NormalMove) continue;
628             if(*text == ' ' && sscanf(text+1, "{%hd/%hd}", &entries[count].learnPoints, &entries[count].learnCount) == 2) {
629                 text = strchr(text+1, '}') + 1;
630             } else {
631                 entries[count].learnPoints = 0;
632                 entries[count].learnCount  = 0;
633             }
634             to = toX + toY * width;
635             from = fromX + fromY * width;
636             for(i=0; promote_pieces[i]; i++) if(promote_pieces[i] == promoChar) break;
637             if(!promote_pieces[i]) i = 0;
638             if(fromY == DROP_RANK) i = 8, from = ToUpper(PieceToChar(fromX)) - '@';
639             entries[count].move = to + (i * width * BOARD_HEIGHT + from) * width * BOARD_HEIGHT;
640             entries[count].key  = hashKey;
641             entries[count].weight = w;
642             count++;
643         }
644         return count;
645 }
646
647 Boolean bookUp;
648 int currentCount;
649
650 Boolean
651 DisplayBook (int moveNr)
652 {
653     entry_t entries[MOVE_BUF];
654     int count;
655     char *p;
656     if(!bookUp) return FALSE;
657     count = currentCount = GetBookMoves(moveNr, appData.polyglotBook, entries);
658     if(count < 0) return FALSE;
659     p = MovesToText(count, entries);
660     EditTagsPopUp(p, NULL);
661     free(p);
662     return TRUE;
663 }
664
665 void
666 EditBookEvent ()
667 {
668       bookUp = TRUE;
669         bookUp = DisplayBook(currentMove);
670 }
671
672 void
673 int_to_file (FILE *f, int l, uint64 r)
674 {
675     int i;
676     for(i=l-1;i>=0;i--) fputc(r>>8*i & 255, f);
677 }
678
679 void
680 entry_to_file (FILE *f, entry_t *entry)
681 {
682     int_to_file(f,8,entry->key);
683     int_to_file(f,2,entry->move);
684     int_to_file(f,2,entry->weight);
685     int_to_file(f,2,entry->learnCount);
686     int_to_file(f,2,entry->learnPoints);
687 }
688
689 char buf1[4096], buf2[4096];
690
691 void
692 SaveToBook (char *text)
693 {
694     entry_t entries[MOVE_BUF], entry;
695     int count = TextToMoves(text, currentMove, entries);
696     int offset, i, len1=0, len2, readpos=0, writepos=0;
697     FILE *f;
698     if(!count && !currentCount) return;
699     f=fopen(appData.polyglotBook, "rb+");
700     if(!f){     DisplayError(_("Polyglot book not valid"), 0); return; }
701     offset=find_key(f, entries[0].key, &entry);
702     if(entries[0].key != entry.key && currentCount) {
703           DisplayError(_("Hash keys are different"), 0);
704           fclose(f);
705           return;
706     }
707     if(count != currentCount) {
708         readpos = 16*(offset + currentCount);
709         writepos = 16*(offset + count);
710         fseek(f, readpos, SEEK_SET);
711         readpos += len1 = fread(buf1, 1, 4096 - 16*currentCount, f); // salvage some entries immediately behind change
712     }
713     fseek(f, 16*(offset), SEEK_SET);
714     for(i=0; i<count; i++) entry_to_file(f, entries + i); // save the change
715     if(count != currentCount) {
716         do {
717             for(i=0; i<len1; i++) buf2[i] = buf1[i]; len2 = len1;
718             if(readpos > writepos) {
719                 fseek(f, readpos, SEEK_SET);
720                 readpos += len1 = fread(buf1, 1, 4096, f);
721             } else len1 = 0; // wrote already past old EOF
722             fseek(f, writepos, SEEK_SET);
723             fwrite(buf2, 1, len2, f);
724             writepos += len2;
725         } while(len1);
726     }
727     fclose(f);
728 }
729