Rev 1805 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1805 | yogev_ezra | 1 | #ifndef _HEADER_HISTORY_H |
2 | #define _HEADER_HISTORY_H |
||
3 | |||
4 | #include "position.h" |
||
5 | #include "hash.h" |
||
6 | #include "sysproc.h" |
||
7 | |||
8 | class THistory |
||
9 | { |
||
5123 | clevermous | 10 | #ifndef NO_FILES |
1805 | yogev_ezra | 11 | public: |
12 | static char FileName[1024]; |
||
13 | #endif |
||
14 | public: |
||
15 | THistory(int id = 0) {if (id >= 0) Hid = NHid++; else Hid = id;} |
||
16 | |||
17 | int GetId() const {return Hid;} |
||
18 | static int GetNId() {return NHid;} |
||
19 | |||
20 | int Start(const Position &pos) const; |
||
21 | int Move(const Position &pos, const unsigned char mv[], int nmove) const; |
||
22 | int Play(const PlayWrite &play) const; |
||
23 | |||
5123 | clevermous | 24 | #ifndef NO_FILES |
1805 | yogev_ezra | 25 | static int InitHFile(char *dname = 0); |
26 | static int HRead(FILE *f, PlayWrite *&play); |
||
27 | protected: |
||
28 | int Print(const char *str) const; |
||
29 | #endif |
||
30 | |||
31 | int Hid; |
||
32 | |||
33 | static int NHid; |
||
34 | protected: |
||
35 | struct TStr |
||
36 | { |
||
37 | TStr(const char *ss = 0) : s(0) {(*this) = ss;} |
||
38 | TStr(const TStr &ss) : s(0) {(*this) = ss.s;} |
||
39 | ~TStr() {(*this) = 0;} |
||
40 | |||
41 | TStr &operator=(const char *ss); |
||
42 | TStr &operator=(const TStr &ss) {return (*this) = ss.s;} |
||
43 | |||
44 | operator char*() {return s;} |
||
45 | operator const char*() const {return s;} |
||
46 | char &operator*() {return *s;} |
||
47 | const char &operator*() const {return *s;} |
||
48 | char &operator[](int i) {return s[i];} |
||
49 | const char &operator[](int i) const {return s[i];} |
||
50 | void Extend(int n); |
||
51 | |||
52 | friend int operator==(const TStr &s1, const TStr &s2) |
||
53 | {return strcmp(s1, s2) == 0;} |
||
54 | friend int operator==(const char *s1, const TStr &s2) |
||
55 | {return strcmp(s1, s2) == 0;} |
||
56 | friend int operator==(const TStr &s1, const char *s2) |
||
57 | {return strcmp(s1, s2) == 0;} |
||
58 | friend int operator!=(const TStr &s1, const TStr &s2) |
||
59 | {return strcmp(s1, s2) != 0;} |
||
60 | friend int operator!=(const char *s1, const TStr &s2) |
||
61 | {return strcmp(s1, s2) != 0;} |
||
62 | friend int operator!=(const TStr &s1, const char *s2) |
||
63 | {return strcmp(s1, s2) != 0;} |
||
64 | friend int operator>=(const TStr &s1, const TStr &s2) |
||
65 | {return strcmp(s1, s2) >= 0;} |
||
66 | friend int operator>=(const char *s1, const TStr &s2) |
||
67 | {return strcmp(s1, s2) >= 0;} |
||
68 | friend int operator>=(const TStr &s1, const char *s2) |
||
69 | {return strcmp(s1, s2) >= 0;} |
||
70 | friend int operator<=(const TStr &s1, const TStr &s2) |
||
71 | {return strcmp(s1, s2) <= 0;} |
||
72 | friend int operator<=(const char *s1, const TStr &s2) |
||
73 | {return strcmp(s1, s2) <= 0;} |
||
74 | friend int operator<=(const TStr &s1, const char *s2) |
||
75 | {return strcmp(s1, s2) <= 0;} |
||
76 | friend int operator>(const TStr &s1, const TStr &s2) |
||
77 | {return strcmp(s1, s2) > 0;} |
||
78 | friend int operator>(const char *s1, const TStr &s2) |
||
79 | {return strcmp(s1, s2) > 0;} |
||
80 | friend int operator>(const TStr &s1, const char *s2) |
||
81 | {return strcmp(s1, s2) > 0;} |
||
82 | friend int operator<(const TStr &s1, const TStr &s2) |
||
83 | {return strcmp(s1, s2) < 0;} |
||
84 | friend int operator<(const char *s1, const TStr &s2) |
||
85 | {return strcmp(s1, s2) < 0;} |
||
86 | friend int operator<(const TStr &s1, const char *s2) |
||
87 | {return strcmp(s1, s2) < 0;} |
||
88 | |||
89 | char *s; |
||
90 | }; |
||
91 | |||
92 | class THash |
||
93 | { |
||
94 | public: |
||
95 | void init(int _m); |
||
96 | int operator()(const TStr &str) const; |
||
97 | protected: |
||
98 | int m; |
||
99 | int K[16]; |
||
100 | }; |
||
101 | |||
102 | struct TTableItem |
||
103 | { |
||
104 | TTableItem(const char *s = 0, int k = 0) : str(s), k(k) {} |
||
105 | TTableItem(const TStr &s, int k = 0) : str(s), k(k) {} |
||
106 | TTableItem(const TTableItem &t) : str(t.str), k(t.k) {} |
||
107 | |||
108 | operator TStr&() {return str;} |
||
109 | operator const TStr&() const {return str;} |
||
110 | |||
111 | TStr str; |
||
112 | int k; |
||
113 | }; |
||
114 | }; |
||
115 | |||
5123 | clevermous | 116 | #ifndef NO_FILES |
1805 | yogev_ezra | 117 | char THistory::FileName[1024] = "history.che"; |
118 | #endif |
||
119 | int THistory::NHid = 0; |
||
120 | |||
5123 | clevermous | 121 | #ifndef NO_FILES |
1805 | yogev_ezra | 122 | int THistory::Print(const char *str) const |
123 | { |
||
124 | char *line = new char[30 + strlen(str)]; |
||
125 | if (!line) return 0; |
||
126 | unsigned long pr_id = GetProcessId(); |
||
127 | if (Hid == -1) sprintf(line, "%lu %s\n", pr_id, str); |
||
128 | else if (Hid < 0) sprintf(line, "%lu%c %s\n", pr_id, (char)Hid, str); |
||
129 | else sprintf(line, "%lu:%d %s\n", pr_id, Hid, str); |
||
130 | FILE *f = fopen(FileName, "at"); |
||
131 | if (!f) |
||
132 | { |
||
133 | clock_t cc = clock(); |
||
134 | do {f = fopen(FileName, "at");} |
||
135 | while(!f && (clock() - cc) <= 0.05 * CLOCKS_PER_SEC); |
||
136 | } |
||
137 | if (!f) {delete[] line; return 0;} |
||
138 | fputs(line, f); |
||
139 | fclose(f); |
||
140 | delete[] line; |
||
141 | return 1; |
||
142 | } |
||
143 | #endif |
||
144 | |||
145 | int THistory::Start(const Position &pos) const |
||
146 | { |
||
5123 | clevermous | 147 | #ifndef NO_FILES |
1805 | yogev_ezra | 148 | char str[20 + NUM_CELL] = "Start "; |
149 | if (!pos.Write(str + strlen(str), 1)) return 0; |
||
150 | if (!Print(str)) return 0; |
||
151 | #endif |
||
152 | return 1; |
||
153 | } |
||
154 | |||
155 | int THistory::Move(const Position &pos, const unsigned char mv[], int nmove) const |
||
156 | { |
||
5123 | clevermous | 157 | #ifndef NO_FILES |
1805 | yogev_ezra | 158 | char *str = new char[15 + pos.GetLenMvEx(mv, 11)]; |
159 | if (!str) return 0; |
||
160 | sprintf(str, "%d.%s ", (nmove + 1) / 2, (nmove % 2 == 0) ? ".." : ""); |
||
161 | pos.WriteMvEx(mv, str + strlen(str), 11); |
||
162 | if (!Print(str)) {delete[] str; return 0;} |
||
5123 | clevermous | 163 | delete[] str; |
1805 | yogev_ezra | 164 | #endif |
165 | return 1; |
||
166 | } |
||
167 | |||
168 | int THistory::Play(const PlayWrite &play) const |
||
169 | { |
||
170 | if (play.GetN() <= 0) return 0; |
||
171 | Position pos; |
||
172 | if (play.GetPos(pos, 0) < 0) return 0; |
||
173 | if (!Start(pos)) return 0; |
||
174 | int i; |
||
175 | unsigned char mv[NUM_CELL]; |
||
176 | for (i = 1; i < play.GetN(); i++) |
||
177 | { |
||
178 | if (play.GetPos(pos, i - 1) < 0) return 0; |
||
179 | if (play.GetMove(mv, i) < 0) return 0; |
||
180 | if (!Move(pos, mv, i)) return 0; |
||
181 | } |
||
182 | return 1; |
||
183 | } |
||
184 | |||
5123 | clevermous | 185 | #ifndef NO_FILES |
1805 | yogev_ezra | 186 | int THistory::InitHFile(char *dname) |
187 | { |
||
188 | if (dname && dname[0]) |
||
189 | { |
||
190 | char fnm[1024]; |
||
191 | strcpy(fnm, dname); |
||
192 | int i; |
||
193 | for (i = strlen(fnm) - 1; i >= 0; i--) |
||
194 | { |
||
195 | if (fnm[i] == DIR_SEPARATOR) break; |
||
196 | } |
||
197 | if (i >= 0) |
||
198 | { |
||
199 | strcpy(fnm + i + 1, FileName); |
||
200 | strcpy(FileName, fnm); |
||
201 | } |
||
202 | } |
||
203 | int e = 1; |
||
204 | FILE *f = fopen(FileName, "rt"); |
||
205 | if (f) {e = feof(f); fclose(f);} |
||
206 | if (!e) return 0; |
||
207 | f = fopen(FileName, "wt"); |
||
208 | if (!f) return -1; |
||
209 | fputs("checkers-history_1.1\n", f); |
||
210 | fclose(f); |
||
211 | return 1; |
||
212 | } |
||
213 | #endif |
||
214 | |||
215 | THistory::TStr &THistory::TStr::operator=(const char *ss) |
||
216 | { |
||
217 | if (s) delete[] s; |
||
218 | if (ss) |
||
219 | { |
||
220 | s = new char[strlen(ss) + 1]; |
||
221 | strcpy(s, ss); |
||
222 | } |
||
223 | else s = 0; |
||
224 | return *this; |
||
225 | } |
||
226 | |||
227 | void THistory::TStr::Extend(int n) |
||
228 | { |
||
229 | if (n <= 0) {(*this) = 0; return;} |
||
230 | char *ss = s; |
||
231 | s = new char[n+1]; |
||
232 | if (ss) |
||
233 | { |
||
234 | strncpy(s, ss, n); |
||
235 | s[n] = 0; |
||
236 | delete[] ss; |
||
237 | } |
||
238 | else s[0] = 0; |
||
239 | } |
||
240 | |||
241 | void THistory::THash::init(int _m) |
||
242 | { |
||
243 | m = _m; |
||
244 | for (int i = 0; i < 16; i++) |
||
245 | { |
||
246 | K[i] = (2*random(32767) + 1) & ((1 << m) - 1); |
||
247 | } |
||
248 | } |
||
249 | |||
250 | int THistory::THash::operator()(const TStr &str) const |
||
251 | { |
||
252 | int i, r = 0; |
||
253 | const char *s = str; |
||
254 | for (i = 0; *s; i = (i+1) & 15) r += *(s++) * K[i]; |
||
255 | r &= (1 << m) - 1; |
||
256 | return r; |
||
257 | } |
||
258 | |||
5123 | clevermous | 259 | #ifndef NO_FILES |
1805 | yogev_ezra | 260 | int THistory::HRead(FILE *f, PlayWrite *&play) |
261 | { |
||
262 | const int MAX_INP_WORD = 100; |
||
263 | int nplay = 0, mplay = 10; |
||
264 | play = new PlayWrite[mplay]; |
||
265 | THashTable |
||
266 | TStr word; |
||
267 | char inp_word[MAX_INP_WORD + 1]; |
||
268 | int r, maxword = 0; |
||
269 | unsigned char ch; |
||
270 | int i, k = 0, kind = 0, wasspace = 1, nmove = 0; |
||
271 | for (;;) |
||
272 | { |
||
273 | r = (fread(&ch, 1, 1, f) == 1); |
||
274 | if (!r || isspace(ch)) |
||
275 | { |
||
276 | if (!wasspace) |
||
277 | { |
||
278 | if (kind == 0) kind = 1; |
||
279 | else if (kind == 2) |
||
280 | { |
||
281 | for (i = 0; inp_word[i]; i++) |
||
282 | { |
||
283 | inp_word[i] = (char)tolower((unsigned char)inp_word[i]); |
||
284 | } |
||
285 | if (strcmp(inp_word, "start") == 0) kind = 5; |
||
286 | else kind = -1; |
||
287 | inp_word[0] = 0; k = 0; |
||
288 | } |
||
289 | else if (kind == 3) |
||
290 | { |
||
291 | nmove *= 2; |
||
292 | if (k <= 1) nmove--; |
||
293 | inp_word[0] = 0; |
||
294 | k = 0; kind = 4; |
||
295 | } |
||
296 | else if (kind == 4) |
||
297 | { |
||
298 | TTableItem *n_pl = table.find(word); |
||
299 | if (!n_pl) kind = -1; |
||
300 | else if (nmove < 1 || nmove > play[n_pl->k].GetN()) kind = -1; |
||
301 | else |
||
302 | { |
||
303 | PlayWrite::PMv pmv; |
||
304 | if (play[n_pl->k].GetPos(pmv.pos, nmove - 1) < 0) kind = -1; |
||
305 | else if (!pmv.pos.ReadMv(pmv.mv, inp_word, 1)) kind = -1; |
||
306 | else |
||
307 | { |
||
308 | play[n_pl->k].ClearFrom(nmove); |
||
309 | if (play[n_pl->k].Add(pmv.mv) != 0) kind = -1; |
||
310 | else {k = n_pl->k; kind = 11;} |
||
311 | } |
||
312 | } |
||
313 | } |
||
314 | else if (kind == 5) |
||
315 | { |
||
316 | Position pos; |
||
317 | pos.Read(inp_word, 1); |
||
318 | if (pos.IsNull()) kind = -1; |
||
319 | else |
||
320 | { |
||
321 | TTableItem *n_pl = table.find(word); |
||
322 | if (!n_pl) |
||
323 | { |
||
324 | table.push(TTableItem(word, nplay)); |
||
325 | n_pl = table.find(word); |
||
326 | } |
||
327 | if (!n_pl) kind = -1; |
||
328 | else |
||
329 | { |
||
330 | if (nplay >= mplay) |
||
331 | { |
||
332 | PlayWrite *play0 = play; |
||
333 | int mplay0 = mplay; |
||
334 | mplay = 2*nplay + 3; |
||
335 | play = new PlayWrite[mplay]; |
||
336 | if (play0) |
||
337 | { |
||
338 | for (i = 0; i < mplay0; i++) play[i] = play0[i]; |
||
339 | delete[] play0; |
||
340 | } |
||
341 | } |
||
342 | n_pl->k = nplay++; |
||
343 | play[n_pl->k].Add(0, pos); |
||
344 | k = n_pl->k; kind = 12; |
||
345 | } |
||
346 | } |
||
347 | } |
||
348 | } |
||
349 | if (!r || ch == '\n' || ch == '\r') |
||
350 | { |
||
351 | k = 0; |
||
352 | kind = 0; |
||
353 | if (!r) break; |
||
354 | } |
||
355 | wasspace = 1; |
||
356 | } |
||
357 | else |
||
358 | { |
||
359 | if (kind == 0) |
||
360 | { |
||
361 | if (k >= maxword) word.Extend(2*k + 3); |
||
362 | word[k++] = ch; |
||
363 | word[k] = 0; |
||
364 | } |
||
365 | else if (kind == 1) |
||
366 | { |
||
367 | if (isdigit(ch)) {nmove = ch - '0'; k = 0; kind = 3;} |
||
368 | else |
||
369 | { |
||
370 | inp_word[0] = ch; |
||
371 | inp_word[1] = 0; |
||
372 | k = 1; kind = 2; |
||
373 | } |
||
374 | } |
||
375 | else if (kind == 2 || kind == 4 || kind == 5) |
||
376 | { |
||
377 | if (k < MAX_INP_WORD) |
||
378 | { |
||
379 | inp_word[k++] = ch; |
||
380 | inp_word[k] = 0; |
||
381 | } |
||
382 | } |
||
383 | else if (kind == 3) |
||
384 | { |
||
385 | if (k == 0 && isdigit(ch)) nmove = 10 * nmove + ch - '0'; |
||
386 | else if (ch == '.') k++; |
||
387 | else kind = -1; |
||
388 | } |
||
389 | wasspace = 0; |
||
390 | } |
||
391 | } |
||
392 | return nplay; |
||
393 | } |
||
394 | #endif |
||
395 | |||
396 | #endif //_HEADER_HISTORY_H>>>>=>><>><>>=>>>>>=>=>>>(const>>(const>>(const>=>=(const>=>=(const>=>=(const> |