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