~ubuntu-branches/ubuntu/trusty/polyglot/trusty

« back to all changes in this revision

Viewing changes to adapter.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Oliver Korff
  • Date: 2005-10-09 21:56:20 UTC
  • Revision ID: james.westby@ubuntu.com-20051009215620-dcuqynujzvmiglpj
Tags: upstream-1.3
ImportĀ upstreamĀ versionĀ 1.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
 
 
2
// adapter.cpp
 
3
 
 
4
// includes
 
5
 
 
6
#include <cerrno>
 
7
#include <cstdarg>
 
8
#include <cstdio>
 
9
#include <cstdlib>
 
10
#include <cstring>
 
11
 
 
12
#include <sys/select.h>
 
13
#include <sys/types.h> // Mac OS X needs this one
 
14
#include <unistd.h>
 
15
 
 
16
#include "adapter.h"
 
17
#include "board.h"
 
18
#include "book.h"
 
19
#include "colour.h"
 
20
#include "engine.h"
 
21
#include "fen.h"
 
22
#include "game.h"
 
23
#include "io.h"
 
24
#include "line.h"
 
25
#include "move.h"
 
26
#include "move_do.h"
 
27
#include "move_legal.h"
 
28
#include "option.h"
 
29
#include "parse.h"
 
30
#include "san.h"
 
31
#include "uci.h"
 
32
#include "util.h"
 
33
 
 
34
// constants
 
35
 
 
36
static const bool UseDebug = false;
 
37
static const bool DelayPong = false;
 
38
 
 
39
static const int StringSize = 4096;
 
40
 
 
41
// types
 
42
 
 
43
struct xboard_t {
 
44
   io_t io[1];
 
45
};
 
46
 
 
47
struct state_t {
 
48
   int state;
 
49
   bool computer[ColourNb];
 
50
   int exp_move;
 
51
   int resign_nb;
 
52
   my_timer_t timer[1];
 
53
};
 
54
 
 
55
struct xb_t {
 
56
 
 
57
   bool analyse;
 
58
   bool computer;
 
59
   const char * name;
 
60
   bool ics;
 
61
   bool new_hack; // "new" is a C++ keyword
 
62
   bool ponder;
 
63
   int ping;
 
64
   bool post;
 
65
   int proto_ver;
 
66
   bool result;
 
67
 
 
68
   int mps;
 
69
   double base;
 
70
   double inc;
 
71
 
 
72
   bool time_limit;
 
73
   double time_max;
 
74
 
 
75
   bool depth_limit;
 
76
   int depth_max;
 
77
 
 
78
   double my_time;
 
79
   double opp_time;
 
80
};
 
81
 
 
82
enum dummy_state_t { WAIT, THINK, PONDER, ANALYSE };
 
83
 
 
84
// variables
 
85
 
 
86
static xboard_t XBoard[1];
 
87
 
 
88
static state_t State[1];
 
89
static xb_t XB[1];
 
90
 
 
91
// prototypes
 
92
 
 
93
static void adapter_step   ();
 
94
 
 
95
static void xboard_step    ();
 
96
static void engine_step    ();
 
97
 
 
98
static void comp_move      (int move);
 
99
static void move_step      (int move);
 
100
static void board_update   ();
 
101
 
 
102
static void mess           ();
 
103
static void no_mess        (int move);
 
104
 
 
105
static void search_update  ();
 
106
static void search_clear   ();
 
107
 
 
108
static bool active         ();
 
109
static bool ponder_ok      (int ponder_move);
 
110
 
 
111
static void stop_search    ();
 
112
static void quit           ();
 
113
 
 
114
static void send_board     (int extra_move);
 
115
static void send_pv        ();
 
116
 
 
117
static void xboard_get     (xboard_t * xboard, char string[], int size);
 
118
static void xboard_send    (xboard_t * xboard, const char format[], ...);
 
119
 
 
120
static void learn          (int result);
 
121
 
 
122
// functions
 
123
 
 
124
// adapter_loop()
 
125
 
 
126
void adapter_loop() {
 
127
 
 
128
   // init
 
129
 
 
130
   game_clear(Game);
 
131
 
 
132
   // state
 
133
 
 
134
   State->state = WAIT;
 
135
 
 
136
   State->computer[White] = false;
 
137
   State->computer[Black] = true;
 
138
 
 
139
   State->exp_move = MoveNone;
 
140
   State->resign_nb = 0;
 
141
   my_timer_reset(State->timer);
 
142
 
 
143
   // xboard
 
144
 
 
145
   XBoard->io->in_fd = STDIN_FILENO;
 
146
   XBoard->io->out_fd = STDOUT_FILENO;
 
147
   XBoard->io->name = "XBOARD";
 
148
 
 
149
   io_init(XBoard->io);
 
150
 
 
151
   XB->analyse = false;
 
152
   XB->computer = false;
 
153
   XB->name = NULL;
 
154
   my_string_set(&XB->name,"<empty>");
 
155
   XB->ics = false;
 
156
   XB->new_hack = true;
 
157
   XB->ping = -1;
 
158
   XB->ponder = false;
 
159
   XB->post = false;
 
160
   XB->proto_ver = 1;
 
161
   XB->result = false;
 
162
 
 
163
   XB->mps = 0;
 
164
   XB->base = 300.0;
 
165
   XB->inc = 0.0;
 
166
 
 
167
   XB->time_limit = false;
 
168
   XB->time_max = 5.0;
 
169
 
 
170
   XB->depth_limit = false;
 
171
   XB->depth_max = 127;
 
172
 
 
173
   XB->my_time = 300.0;
 
174
   XB->opp_time = 300.0;
 
175
 
 
176
   // loop
 
177
 
 
178
   while (true) adapter_step();
 
179
}
 
180
 
 
181
// adapter_step()
 
182
 
 
183
static void adapter_step() {
 
184
 
 
185
   fd_set set[1];
 
186
   int fd_max;
 
187
   int val;
 
188
 
 
189
   // process buffered lines
 
190
 
 
191
   while (io_line_ready(XBoard->io)) xboard_step(); // process available xboard lines
 
192
   while (io_line_ready(Engine->io)) engine_step(); // process available engine lines
 
193
 
 
194
   // init
 
195
 
 
196
   FD_ZERO(set);
 
197
   fd_max = -1; // HACK
 
198
 
 
199
   // add xboard input
 
200
 
 
201
   ASSERT(XBoard->io->in_fd>=0);
 
202
 
 
203
   FD_SET(XBoard->io->in_fd,set);
 
204
   if (XBoard->io->in_fd > fd_max) fd_max = XBoard->io->in_fd;
 
205
 
 
206
   // add engine input
 
207
 
 
208
   ASSERT(Engine->io->in_fd>=0);
 
209
 
 
210
   FD_SET(Engine->io->in_fd,set);
 
211
   if (Engine->io->in_fd > fd_max) fd_max = Engine->io->in_fd;
 
212
 
 
213
   // wait for something to read (no timeout)
 
214
 
 
215
   ASSERT(fd_max>=0);
 
216
 
 
217
   val = select(fd_max+1,set,NULL,NULL,NULL);
 
218
   if (val == -1 && errno != EINTR) my_fatal("adapter_step(): select(): %s\n",strerror(errno));
 
219
 
 
220
   if (val > 0) {
 
221
      if (FD_ISSET(XBoard->io->in_fd,set)) io_get_update(XBoard->io); // read some xboard input
 
222
      if (FD_ISSET(Engine->io->in_fd,set)) io_get_update(Engine->io); // read some engine input
 
223
   }
 
224
}
 
225
 
 
226
// xboard_step()
 
227
 
 
228
static void xboard_step() {
 
229
 
 
230
   char string[StringSize];
 
231
   int move;
 
232
   char move_string[256];
 
233
   board_t board[1];
 
234
 
 
235
   xboard_get(XBoard,string,StringSize);
 
236
 
 
237
   if (false) {
 
238
 
 
239
   } else if (match(string,"accepted *")) {
 
240
 
 
241
      // ignore
 
242
 
 
243
   } else if (match(string,"analyze")) {
 
244
 
 
245
      State->computer[White] = false;
 
246
      State->computer[Black] = false;
 
247
 
 
248
      XB->analyse = true;
 
249
      XB->new_hack = false;
 
250
      ASSERT(!XB->result);
 
251
      XB->result = false;
 
252
 
 
253
      mess();
 
254
 
 
255
   } else if (match(string,"bk")) {
 
256
 
 
257
      if (option_get_bool("Book")) {
 
258
         game_get_board(Game,board);
 
259
         book_disp(board);
 
260
      }
 
261
 
 
262
   } else if (match(string,"black")) {
 
263
 
 
264
      if (colour_is_black(game_turn(Game))) {
 
265
 
 
266
         State->computer[White] = true;
 
267
         State->computer[Black] = false;
 
268
 
 
269
         XB->new_hack = true;
 
270
         XB->result = false;
 
271
 
 
272
         mess();
 
273
      }
 
274
 
 
275
   } else if (match(string,"computer")) {
 
276
 
 
277
      XB->computer = true;
 
278
 
 
279
   } else if (match(string,"draw")) {
 
280
 
 
281
      // ignore
 
282
 
 
283
   } else if (match(string,"easy")) {
 
284
 
 
285
      XB->ponder = false;
 
286
 
 
287
      mess();
 
288
 
 
289
   } else if (match(string,"edit")) {
 
290
 
 
291
      // refuse
 
292
 
 
293
      xboard_send(XBoard,"Error (unknown command): %s",string);
 
294
 
 
295
   } else if (match(string,"exit")) {
 
296
 
 
297
      State->computer[White] = false;
 
298
      State->computer[Black] = false;
 
299
 
 
300
      XB->analyse = false;
 
301
 
 
302
      mess();
 
303
 
 
304
   } else if (match(string,"force")) {
 
305
 
 
306
      State->computer[White] = false;
 
307
      State->computer[Black] = false;
 
308
 
 
309
      mess();
 
310
 
 
311
   } else if (match(string,"go")) {
 
312
 
 
313
      State->computer[game_turn(Game)] = true;
 
314
      State->computer[colour_opp(game_turn(Game))] = false;
 
315
 
 
316
      XB->new_hack = false;
 
317
      ASSERT(!XB->result);
 
318
      XB->result = false;
 
319
 
 
320
      mess();
 
321
 
 
322
   } else if (match(string,"hard")) {
 
323
 
 
324
      XB->ponder = true;
 
325
 
 
326
      mess();
 
327
 
 
328
   } else if (match(string,"hint")) {
 
329
 
 
330
      if (option_get_bool("Book")) {
 
331
 
 
332
         game_get_board(Game,board);
 
333
         move = book_move(board,false);
 
334
 
 
335
         if (move != MoveNone && move_is_legal(move,board)) {
 
336
            move_to_san(move,board,move_string,256);
 
337
            xboard_send(XBoard,"Hint: %s",move_string);
 
338
         }
 
339
      }
 
340
 
 
341
   } else if (match(string,"ics *")) {
 
342
 
 
343
      XB->ics = true;
 
344
 
 
345
   } else if (match(string,"level * *:* *")) {
 
346
 
 
347
      XB->mps  = atoi(Star[0]);
 
348
      XB->base = double(atoi(Star[1])) * 60.0 + double(atoi(Star[2]));
 
349
      XB->inc  = double(atoi(Star[3]));
 
350
 
 
351
   } else if (match(string,"level * * *")) {
 
352
 
 
353
      XB->mps  = atoi(Star[0]);
 
354
      XB->base = double(atoi(Star[1])) * 60.0;
 
355
      XB->inc  = double(atoi(Star[2]));
 
356
 
 
357
   } else if (match(string,"name *")) {
 
358
 
 
359
      my_string_set(&XB->name,Star[0]);
 
360
 
 
361
   } else if (match(string,"new")) {
 
362
 
 
363
      my_log("POLYGLOT NEW GAME\n");
 
364
 
 
365
      game_clear(Game);
 
366
 
 
367
      if (XB->analyse) {
 
368
         State->computer[White] = false;
 
369
         State->computer[Black] = false;
 
370
      } else {
 
371
         State->computer[White] = false;
 
372
         State->computer[Black] = true;
 
373
      }
 
374
 
 
375
      XB->new_hack = true;
 
376
      XB->result = false;
 
377
 
 
378
      XB->depth_limit = false;
 
379
 
 
380
      XB->computer = false;
 
381
      my_string_set(&XB->name,"<empty>");
 
382
 
 
383
      board_update();
 
384
      mess();
 
385
 
 
386
      uci_send_ucinewgame(Uci);
 
387
 
 
388
   } else if (match(string,"nopost")) {
 
389
 
 
390
      XB->post = false;
 
391
 
 
392
   } else if (match(string,"otim *")) {
 
393
 
 
394
      XB->opp_time = double(atoi(Star[0])) / 100.0;
 
395
      if (XB->opp_time < 0.0) XB->opp_time = 0.0;
 
396
 
 
397
   } else if (match(string,"pause")) {
 
398
 
 
399
      // refuse
 
400
 
 
401
      xboard_send(XBoard,"Error (unknown command): %s",string);
 
402
 
 
403
   } else if (match(string,"ping *")) {
 
404
 
 
405
      // HACK; TODO: answer only after an engine move
 
406
 
 
407
      if (DelayPong) {
 
408
         if (XB->ping >= 0) xboard_send(XBoard,"pong %d",XB->ping); // HACK: get rid of old ping
 
409
         XB->ping = atoi(Star[0]);
 
410
         uci_send_isready(Uci);
 
411
      } else {
 
412
         ASSERT(XB->ping==-1);
 
413
         xboard_send(XBoard,"pong %s",Star[0]);
 
414
      }
 
415
 
 
416
   } else if (match(string,"playother")) {
 
417
 
 
418
      State->computer[game_turn(Game)] = false;
 
419
      State->computer[colour_opp(game_turn(Game))] = true;
 
420
 
 
421
      XB->new_hack = false;
 
422
      ASSERT(!XB->result);
 
423
      XB->result = false;
 
424
 
 
425
      mess();
 
426
 
 
427
   } else if (match(string,"post")) {
 
428
 
 
429
      XB->post = true;
 
430
 
 
431
   } else if (match(string,"protover *")) {
 
432
 
 
433
      XB->proto_ver = atoi(Star[0]);
 
434
      ASSERT(XB->proto_ver>=2);
 
435
 
 
436
      xboard_send(XBoard,"feature done=0");
 
437
 
 
438
      xboard_send(XBoard,"feature analyze=1");
 
439
      xboard_send(XBoard,"feature colors=0");
 
440
      xboard_send(XBoard,"feature draw=1");
 
441
      xboard_send(XBoard,"feature ics=1");
 
442
      xboard_send(XBoard,"feature myname=\"%s\"",option_get_string("EngineName"));
 
443
      xboard_send(XBoard,"feature name=1");
 
444
      xboard_send(XBoard,"feature pause=0");
 
445
      xboard_send(XBoard,"feature ping=1");
 
446
      xboard_send(XBoard,"feature playother=1");
 
447
      xboard_send(XBoard,"feature reuse=1");
 
448
      xboard_send(XBoard,"feature san=0");
 
449
      xboard_send(XBoard,"feature setboard=1");
 
450
      xboard_send(XBoard,"feature sigint=0");
 
451
      xboard_send(XBoard,"feature sigterm=0");
 
452
      xboard_send(XBoard,"feature time=1");
 
453
      xboard_send(XBoard,"feature usermove=1");
 
454
      xboard_send(XBoard,"feature variants=\"normal\"");
 
455
 
 
456
      if (Uci->ready) xboard_send(XBoard,"feature done=1");
 
457
 
 
458
      // "feature done=1" will be sent when the engine is ready
 
459
 
 
460
   } else if (match(string,"quit")) {
 
461
 
 
462
      my_log("POLYGLOT *** \"quit\" from XBoard ***\n");
 
463
      quit();
 
464
 
 
465
   } else if (match(string,"random")) {
 
466
 
 
467
      // ignore
 
468
 
 
469
   } else if (match(string,"rating * *")) {
 
470
 
 
471
      // ignore
 
472
 
 
473
   } else if (match(string,"remove")) {
 
474
 
 
475
      if (game_pos(Game) >= 2) {
 
476
 
 
477
         game_goto(Game,game_pos(Game)-2);
 
478
 
 
479
         ASSERT(!XB->new_hack);
 
480
         XB->new_hack = false; // HACK?
 
481
         XB->result = false;
 
482
 
 
483
         board_update();
 
484
         mess();
 
485
      }
 
486
 
 
487
   } else if (match(string,"rejected *")) {
 
488
 
 
489
      // ignore
 
490
 
 
491
   } else if (match(string,"reset")) { // protover 3?
 
492
 
 
493
      // refuse
 
494
 
 
495
      xboard_send(XBoard,"Error (unknown command): %s",string);
 
496
 
 
497
   } else if (false
 
498
           || match(string,"result * {*}")
 
499
           || match(string,"result * {* }")
 
500
           || match(string,"result * { *}")
 
501
           || match(string,"result * { * }")) {
 
502
 
 
503
      my_log("POLYGLOT GAME END\n");
 
504
 
 
505
      XB->result = true;
 
506
 
 
507
      mess();
 
508
 
 
509
      // book learning
 
510
 
 
511
      if (option_get_bool("Book") && option_get_bool("BookLearn")) {
 
512
 
 
513
         if (false) {
 
514
         } else if (my_string_equal(Star[0],"1-0")) {
 
515
            learn(+1);
 
516
         } else if (my_string_equal(Star[0],"0-1")) {
 
517
            learn(-1);
 
518
         } else if (my_string_equal(Star[0],"1/2-1/2")) {
 
519
            learn(0);
 
520
         }
 
521
      }
 
522
 
 
523
   } else if (match(string,"resume")) {
 
524
 
 
525
      // refuse
 
526
 
 
527
      xboard_send(XBoard,"Error (unknown command): %s",string);
 
528
 
 
529
   } else if (match(string,"sd *")) {
 
530
 
 
531
      XB->depth_limit = true;
 
532
      XB->depth_max = atoi(Star[0]);
 
533
 
 
534
   } else if (match(string,"setboard *")) {
 
535
 
 
536
      my_log("POLYGLOT FEN %s\n",Star[0]);
 
537
 
 
538
      if (!game_init(Game,Star[0])) my_fatal("xboard_step(): bad FEN \"%s\"\n",Star[0]);
 
539
 
 
540
      State->computer[White] = false;
 
541
      State->computer[Black] = false;
 
542
 
 
543
      XB->new_hack = true; // HACK?
 
544
      XB->result = false;
 
545
 
 
546
      board_update();
 
547
      mess();
 
548
 
 
549
   } else if (match(string,"st *")) {
 
550
 
 
551
      XB->time_limit = true;
 
552
      XB->time_max = double(atoi(Star[0]));
 
553
 
 
554
   } else if (match(string,"time *")) {
 
555
 
 
556
      XB->my_time = double(atoi(Star[0])) / 100.0;
 
557
      if (XB->my_time < 0.0) XB->my_time = 0.0;
 
558
 
 
559
   } else if (match(string,"undo")) {
 
560
 
 
561
      if (game_pos(Game) >= 1) {
 
562
 
 
563
         game_goto(Game,game_pos(Game)-1);
 
564
 
 
565
         ASSERT(!XB->new_hack);
 
566
         XB->new_hack = false; // HACK?
 
567
         XB->result = false;
 
568
 
 
569
         board_update();
 
570
         mess();
 
571
      }
 
572
 
 
573
   } else if (match(string,"usermove *")) {
 
574
 
 
575
      game_get_board(Game,board);
 
576
      move = move_from_san(Star[0],board);
 
577
 
 
578
      if (move != MoveNone && move_is_legal(move,board)) {
 
579
 
 
580
         XB->new_hack = false;
 
581
         ASSERT(!XB->result);
 
582
         XB->result = false;
 
583
 
 
584
         move_step(move);
 
585
         no_mess(move);
 
586
 
 
587
      } else {
 
588
 
 
589
         xboard_send(XBoard,"Illegal move: %s",Star[0]);
 
590
      }
 
591
 
 
592
   } else if (match(string,"variant *")) {
 
593
 
 
594
      // refuse
 
595
 
 
596
      xboard_send(XBoard,"Error (unknown command): %s",string);
 
597
 
 
598
   } else if (match(string,"white")) {
 
599
 
 
600
      if (colour_is_white(game_turn(Game))) {
 
601
 
 
602
         State->computer[White] = false;
 
603
         State->computer[Black] = true;
 
604
 
 
605
         XB->new_hack = true;
 
606
         XB->result = false;
 
607
 
 
608
         mess();
 
609
      }
 
610
 
 
611
   } else if (match(string,"xboard")) {
 
612
 
 
613
      // ignore
 
614
 
 
615
   } else if (match(string,".")) { // analyse info
 
616
 
 
617
      if (State->state == ANALYSE) {
 
618
 
 
619
         ASSERT(Uci->searching);
 
620
         ASSERT(Uci->pending_nb>=1);
 
621
 
 
622
         if (Uci->root_move != MoveNone && move_is_legal(Uci->root_move,Uci->board)) {
 
623
            move_to_san(Uci->root_move,Uci->board,move_string,256);
 
624
            xboard_send(XBoard,"stat01: %.0f %lld %d %d %d %s",Uci->time*100.0,Uci->node_nb,Uci->depth,Uci->root_move_nb-(Uci->root_move_pos+1),Uci->root_move_nb,move_string);
 
625
         } else {
 
626
            xboard_send(XBoard,"stat01: %.0f %lld %d %d %d",Uci->time*100.0,Uci->node_nb,Uci->depth,0,0); // HACK
 
627
         }
 
628
      }
 
629
 
 
630
   } else if (match(string,"?")) { // move now
 
631
 
 
632
      if (State->state == THINK) {
 
633
 
 
634
         ASSERT(Uci->searching);
 
635
         ASSERT(Uci->pending_nb>=1);
 
636
 
 
637
         stop_search();
 
638
      }
 
639
 
 
640
   } else { // unknown command, maybe a move?
 
641
 
 
642
      game_get_board(Game,board);
 
643
      move = move_from_san(string,board);
 
644
 
 
645
      if (move != MoveNone && move_is_legal(move,board)) {
 
646
 
 
647
         XB->new_hack = false;
 
648
         ASSERT(!XB->result);
 
649
         XB->result = false;
 
650
 
 
651
         move_step(move);
 
652
         no_mess(move);
 
653
 
 
654
      } else if (move != MoveNone) {
 
655
 
 
656
         xboard_send(XBoard,"Illegal move: %s",string);
 
657
 
 
658
      } else {
 
659
 
 
660
         xboard_send(XBoard,"Error (unknown command): %s",string);
 
661
      }
 
662
   }
 
663
}
 
664
 
 
665
// engine_step()
 
666
 
 
667
static void engine_step() {
 
668
 
 
669
   char string[StringSize];
 
670
   int event;
 
671
 
 
672
   // parse UCI line
 
673
 
 
674
   engine_get(Engine,string,StringSize);
 
675
   event = uci_parse(Uci,string);
 
676
 
 
677
   // react to events
 
678
 
 
679
   if ((event & EVENT_READY) != 0) {
 
680
 
 
681
      // the engine is now ready
 
682
 
 
683
      if (!Uci->ready) {
 
684
         Uci->ready = true;
 
685
         if (XB->proto_ver >= 2) xboard_send(XBoard,"feature done=1");
 
686
      }
 
687
 
 
688
      if (!DelayPong && XB->ping >= 0) {
 
689
         xboard_send(XBoard,"pong %d",XB->ping);
 
690
         XB->ping = -1;
 
691
      }
 
692
   }
 
693
 
 
694
   if ((event & EVENT_MOVE) != 0 && State->state == THINK) {
 
695
 
 
696
      // the engine is playing a move
 
697
 
 
698
      // MEGA HACK: estimate remaining time because XBoard won't send it!
 
699
 
 
700
      my_timer_stop(State->timer);
 
701
 
 
702
      XB->my_time -= my_timer_elapsed_real(State->timer);
 
703
      XB->my_time += XB->inc;
 
704
      if (XB->mps != 0 && (game_move_nb(Game) + 1) % XB->mps == 0) XB->my_time += XB->base;
 
705
 
 
706
      if (XB->my_time < 0.0) XB->my_time = 0.0;
 
707
 
 
708
      // play the engine move
 
709
 
 
710
      comp_move(Uci->best_move);
 
711
   }
 
712
 
 
713
   if ((event & EVENT_PV) != 0) {
 
714
 
 
715
      // the engine has sent a new PV
 
716
 
 
717
      send_pv();
 
718
   }
 
719
}
 
720
 
 
721
// comp_move()
 
722
 
 
723
static void comp_move(int move) {
 
724
 
 
725
   char string[256];
 
726
 
 
727
   ASSERT(move_is_ok(move));
 
728
 
 
729
   ASSERT(State->state==THINK);
 
730
   ASSERT(!XB->analyse);
 
731
 
 
732
   send_pv();
 
733
 
 
734
   if (!move_to_can(move,string,256)) my_fatal("comp_move(): move_to_can() failed\n");
 
735
   xboard_send(XBoard,"move %s",string);
 
736
 
 
737
   if (option_get_bool("Resign") && Uci->root_move_nb > 1) {
 
738
 
 
739
      if (Uci->best_score <= -abs(option_get_int("ResignScore"))) {
 
740
 
 
741
         State->resign_nb++;
 
742
         my_log("POLYGLOT %d move%s with resign score\n",State->resign_nb,(State->resign_nb>1)?"s":"");
 
743
 
 
744
         if (State->resign_nb >= option_get_int("ResignMoves")) {
 
745
            my_log("POLYGLOT *** RESIGN ***\n");
 
746
            xboard_send(XBoard,"resign");
 
747
         }
 
748
 
 
749
      } else {
 
750
 
 
751
         if (State->resign_nb > 0) my_log("POLYGLOT resign reset (State->resign_nb=%d)\n",State->resign_nb);
 
752
         State->resign_nb = 0;
 
753
      }
 
754
   }
 
755
 
 
756
   move_step(move);
 
757
   no_mess(move);
 
758
}
 
759
 
 
760
// move_step()
 
761
 
 
762
static void move_step(int move) {
 
763
 
 
764
   board_t board[1];
 
765
   char move_string[256];
 
766
 
 
767
   ASSERT(move_is_ok(move));
 
768
 
 
769
   // log
 
770
 
 
771
   game_get_board(Game,board);
 
772
 
 
773
   if (move != MoveNone && move_is_legal(move,board)) {
 
774
 
 
775
      move_to_san(move,board,move_string,256);
 
776
      my_log("POLYGLOT MOVE %s\n",move_string);
 
777
 
 
778
   } else {
 
779
 
 
780
      move_to_can(move,move_string,256);
 
781
      my_log("POLYGLOT ILLEGAL MOVE \"%s\"\n",move_string);
 
782
      board_disp(board);
 
783
 
 
784
      my_fatal("move_step(): illegal move \"%s\"\n",move_string);
 
785
   }
 
786
 
 
787
   // play the move
 
788
 
 
789
   game_add_move(Game,move);
 
790
   board_update();
 
791
}
 
792
 
 
793
// board_update()
 
794
 
 
795
static void board_update() {
 
796
 
 
797
   // handle game end
 
798
 
 
799
   ASSERT(!XB->result);
 
800
 
 
801
   switch (game_status(Game)) {
 
802
   case PLAYING :
 
803
      break;
 
804
   case WHITE_MATES :
 
805
      xboard_send(XBoard,"1-0 {White mates}");
 
806
      break;
 
807
   case BLACK_MATES :
 
808
      xboard_send(XBoard,"0-1 {Black mates}");
 
809
      break;
 
810
   case STALEMATE :
 
811
      xboard_send(XBoard,"1/2-1/2 {Stalemate}");
 
812
      break;
 
813
   case DRAW_MATERIAL :
 
814
      xboard_send(XBoard,"1/2-1/2 {Draw by insufficient material}");
 
815
      break;
 
816
   case DRAW_FIFTY :
 
817
      xboard_send(XBoard,"1/2-1/2 {Draw by fifty-move rule}");
 
818
      break;
 
819
   case DRAW_REPETITION :
 
820
      xboard_send(XBoard,"1/2-1/2 {Draw by repetition}");
 
821
      break;
 
822
   default :
 
823
      ASSERT(false);
 
824
      break;
 
825
   }
 
826
}
 
827
 
 
828
// mess()
 
829
 
 
830
static void mess() {
 
831
 
 
832
   // clear state variables
 
833
 
 
834
   State->resign_nb = 0;
 
835
   State->exp_move = MoveNone;
 
836
   my_timer_reset(State->timer);
 
837
 
 
838
   // abort a possible search
 
839
 
 
840
   stop_search();
 
841
 
 
842
   // calculate the new state
 
843
 
 
844
   if (false) {
 
845
   } else if (!active()) {
 
846
      State->state = WAIT;
 
847
      my_log("POLYGLOT WAIT\n");
 
848
   } else if (XB->analyse) {
 
849
      State->state = ANALYSE;
 
850
      my_log("POLYGLOT ANALYSE\n");
 
851
   } else if (State->computer[game_turn(Game)]) {
 
852
      State->state = THINK;
 
853
      my_log("POLYGLOT THINK\n");
 
854
   } else {
 
855
      State->state = WAIT;
 
856
      my_log("POLYGLOT WAIT\n");
 
857
   }
 
858
 
 
859
   search_update();
 
860
}
 
861
 
 
862
// no_mess()
 
863
 
 
864
static void no_mess(int move) {
 
865
 
 
866
   ASSERT(move_is_ok(move));
 
867
 
 
868
   // just received a move, calculate the new state
 
869
 
 
870
   if (false) {
 
871
 
 
872
   } else if (!active()) {
 
873
 
 
874
      stop_search(); // abort a possible search
 
875
 
 
876
      State->state = WAIT;
 
877
      State->exp_move = MoveNone;
 
878
 
 
879
      my_log("POLYGLOT WAIT\n");
 
880
 
 
881
   } else if (State->state == WAIT) {
 
882
 
 
883
      ASSERT(State->computer[game_turn(Game)]);
 
884
      ASSERT(!State->computer[colour_opp(game_turn(Game))]);
 
885
      ASSERT(!XB->analyse);
 
886
 
 
887
      my_log("POLYGLOT WAIT -> THINK\n");
 
888
 
 
889
      State->state = THINK;
 
890
      State->exp_move = MoveNone;
 
891
 
 
892
   } else if (State->state == THINK) {
 
893
 
 
894
      ASSERT(!State->computer[game_turn(Game)]);
 
895
      ASSERT(State->computer[colour_opp(game_turn(Game))]);
 
896
      ASSERT(!XB->analyse);
 
897
 
 
898
      if (XB->ponder && ponder_ok(Uci->ponder_move)) {
 
899
 
 
900
         my_log("POLYGLOT THINK -> PONDER\n");
 
901
 
 
902
         State->state = PONDER;
 
903
         State->exp_move = Uci->ponder_move;
 
904
 
 
905
      } else {
 
906
 
 
907
         my_log("POLYGLOT THINK -> WAIT\n");
 
908
 
 
909
         State->state = WAIT;
 
910
         State->exp_move = MoveNone;
 
911
      }
 
912
 
 
913
   } else if (State->state == PONDER) {
 
914
 
 
915
      ASSERT(State->computer[game_turn(Game)]);
 
916
      ASSERT(!State->computer[colour_opp(game_turn(Game))]);
 
917
      ASSERT(!XB->analyse);
 
918
 
 
919
      if (move == State->exp_move && Uci->searching) {
 
920
 
 
921
         ASSERT(Uci->searching);
 
922
         ASSERT(Uci->pending_nb>=1);
 
923
 
 
924
         my_timer_reset(State->timer);
 
925
         my_timer_start(State->timer);
 
926
 
 
927
         my_log("POLYGLOT PONDER -> THINK (*** HIT ***)\n");
 
928
         engine_send(Engine,"ponderhit");
 
929
 
 
930
         State->state = THINK;
 
931
         State->exp_move = MoveNone;
 
932
 
 
933
         send_pv(); // update display
 
934
 
 
935
         return; // do not launch a new search
 
936
 
 
937
      } else {
 
938
 
 
939
         my_log("POLYGLOT PONDER -> THINK (miss)\n");
 
940
 
 
941
         stop_search();
 
942
 
 
943
         State->state = THINK;
 
944
         State->exp_move = MoveNone;
 
945
      }
 
946
 
 
947
   } else if (State->state == ANALYSE) {
 
948
 
 
949
      ASSERT(XB->analyse);
 
950
 
 
951
      my_log("POLYGLOT ANALYSE -> ANALYSE\n");
 
952
 
 
953
      stop_search();
 
954
 
 
955
   } else {
 
956
 
 
957
      ASSERT(false);
 
958
   }
 
959
 
 
960
   search_update();
 
961
}
 
962
 
 
963
// search_update()
 
964
 
 
965
static void search_update() {
 
966
 
 
967
   int move;
 
968
   int move_nb;
 
969
   board_t board[1];
 
970
 
 
971
   ASSERT(!Uci->searching);
 
972
 
 
973
   // launch a new search if needed
 
974
 
 
975
   if (State->state == THINK || State->state == PONDER || State->state == ANALYSE) {
 
976
 
 
977
      // opening book
 
978
 
 
979
      if (State->state == THINK && option_get_bool("Book")) {
 
980
 
 
981
         game_get_board(Game,Uci->board);
 
982
 
 
983
         move = book_move(Uci->board,option_get_bool("BookRandom"));
 
984
 
 
985
         if (move != MoveNone && move_is_legal(move,Uci->board)) {
 
986
 
 
987
            my_log("POLYGLOT *BOOK MOVE*\n");
 
988
 
 
989
            search_clear(); // clears Uci->ponder_move
 
990
            Uci->best_move = move;
 
991
 
 
992
            board_copy(board,Uci->board);
 
993
            move_do(board,move);
 
994
            Uci->ponder_move = book_move(board,false); // expected move = best book move
 
995
 
 
996
            Uci->best_pv[0] = Uci->best_move;
 
997
            Uci->best_pv[1] = Uci->ponder_move; // can be MoveNone
 
998
            Uci->best_pv[2] = MoveNone;
 
999
 
 
1000
            comp_move(Uci->best_move);
 
1001
 
 
1002
            return;
 
1003
         }
 
1004
      }
 
1005
 
 
1006
      // engine search
 
1007
 
 
1008
      my_log("POLYGLOT START SEARCH\n");
 
1009
 
 
1010
      // options
 
1011
 
 
1012
      if (option_get_int("UCIVersion") >= 2) {
 
1013
         uci_send_option(Uci,"UCI_Opponent","none none %s %s",(XB->computer)?"computer":"human",XB->name);
 
1014
         uci_send_option(Uci,"UCI_AnalyseMode","%s",(XB->analyse)?"true":"false");
 
1015
      }
 
1016
 
 
1017
      uci_send_option(Uci,"Ponder","%s",(XB->ponder)?"true":"false");
 
1018
 
 
1019
      // position
 
1020
 
 
1021
      move = (State->state == PONDER) ? State->exp_move : MoveNone;
 
1022
      send_board(move); // updates Uci->board global variable
 
1023
 
 
1024
      // search
 
1025
 
 
1026
      if (State->state == THINK || State->state == PONDER) {
 
1027
 
 
1028
         engine_send_queue(Engine,"go");
 
1029
 
 
1030
         if (XB->time_limit) {
 
1031
 
 
1032
            // fixed time per move
 
1033
 
 
1034
            engine_send_queue(Engine," movetime %.0f",XB->time_max*1000.0);
 
1035
 
 
1036
         } else {
 
1037
 
 
1038
            // time controls
 
1039
 
 
1040
            if (colour_is_white(Uci->board->turn)) {
 
1041
               engine_send_queue(Engine," wtime %.0f btime %.0f",XB->my_time*1000.0,XB->opp_time*1000.0);
 
1042
            } else {
 
1043
               engine_send_queue(Engine," wtime %.0f btime %.0f",XB->opp_time*1000.0,XB->my_time*1000.0);
 
1044
            }
 
1045
 
 
1046
            if (XB->inc != 0.0) engine_send_queue(Engine," winc %.0f binc %.0f",XB->inc*1000.0,XB->inc*1000.0);
 
1047
 
 
1048
            if (XB->mps != 0) {
 
1049
 
 
1050
               move_nb = XB->mps - (Uci->board->move_nb % XB->mps);
 
1051
               ASSERT(move_nb>=1&&move_nb<=XB->mps);
 
1052
 
 
1053
               engine_send_queue(Engine," movestogo %d",move_nb);
 
1054
            }
 
1055
         }
 
1056
 
 
1057
         if (XB->depth_limit) engine_send_queue(Engine," depth %d",XB->depth_max);
 
1058
 
 
1059
         if (State->state == PONDER) engine_send_queue(Engine," ponder");
 
1060
 
 
1061
         engine_send(Engine,""); // newline
 
1062
 
 
1063
      } else if (State->state == ANALYSE) {
 
1064
 
 
1065
         engine_send(Engine,"go infinite");
 
1066
 
 
1067
      } else {
 
1068
 
 
1069
         ASSERT(false);
 
1070
      }
 
1071
 
 
1072
      // init search info
 
1073
 
 
1074
      ASSERT(!Uci->searching);
 
1075
 
 
1076
      search_clear();
 
1077
 
 
1078
      Uci->searching = true;
 
1079
      Uci->pending_nb++;
 
1080
   }
 
1081
}
 
1082
 
 
1083
// search_clear()
 
1084
 
 
1085
static void search_clear() {
 
1086
 
 
1087
   uci_clear(Uci);
 
1088
 
 
1089
   // TODO: MOVE ME
 
1090
 
 
1091
   my_timer_reset(State->timer);
 
1092
   my_timer_start(State->timer);
 
1093
}
 
1094
 
 
1095
// active()
 
1096
 
 
1097
static bool active() {
 
1098
 
 
1099
   board_t board[1];
 
1100
 
 
1101
   game_get_board(Game,board);
 
1102
   if (!board_can_play(board)) return false; // no legal move => mate or stalemate
 
1103
 
 
1104
   // if (game_status(Game) != PLAYING) return false; // draw
 
1105
 
 
1106
   if (XB->analyse) return true; // analysing
 
1107
 
 
1108
   if (!State->computer[White] && !State->computer[Black]) return false; // force mode
 
1109
 
 
1110
   if (XB->new_hack || XB->result) return false; // unstarted or ended game
 
1111
 
 
1112
   return true; // playing
 
1113
}
 
1114
 
 
1115
// ponder_ok()
 
1116
 
 
1117
static bool ponder_ok(int move) {
 
1118
 
 
1119
   board_t board[1];
 
1120
 
 
1121
   ASSERT(move==MoveNone||move_is_ok(move));
 
1122
 
 
1123
   if (move == MoveNone) return false;
 
1124
 
 
1125
   game_get_board(Game,board);
 
1126
 
 
1127
   if (!move_is_legal(move,board)) return false;
 
1128
   move_do(board,move);
 
1129
 
 
1130
   if (!board_can_play(board)) return false;
 
1131
 
 
1132
   if (option_get_bool("Book") && is_in_book(board)) {
 
1133
      return false;
 
1134
   }
 
1135
 
 
1136
   // TODO: draws
 
1137
 
 
1138
   return true;
 
1139
}
 
1140
 
 
1141
// stop_search()
 
1142
 
 
1143
static void stop_search() {
 
1144
 
 
1145
   if (Uci->searching) {
 
1146
 
 
1147
      ASSERT(Uci->searching);
 
1148
      ASSERT(Uci->pending_nb>=1);
 
1149
 
 
1150
      my_log("POLYGLOT STOP SEARCH\n");
 
1151
      engine_send(Engine,"stop");
 
1152
 
 
1153
      Uci->searching = false;
 
1154
   }
 
1155
}
 
1156
 
 
1157
// quit()
 
1158
 
 
1159
static void quit() {
 
1160
 
 
1161
   char string[StringSize];
 
1162
 
 
1163
   my_log("POLYGLOT *** QUIT ***\n");
 
1164
 
 
1165
   stop_search();
 
1166
   engine_send(Engine,"quit");
 
1167
 
 
1168
   // wait for the engine to quit
 
1169
 
 
1170
   while (true) {
 
1171
      engine_get(Engine,string,StringSize); // HACK: calls exit() on receiving EOF
 
1172
   }
 
1173
 
 
1174
   uci_close(Uci);
 
1175
   exit(EXIT_SUCCESS);
 
1176
}
 
1177
 
 
1178
// send_board()
 
1179
 
 
1180
static void send_board(int extra_move) {
 
1181
 
 
1182
   char fen[256];
 
1183
   int start, end;
 
1184
   board_t board[1];
 
1185
   int pos;
 
1186
   int move;
 
1187
   char string[256];
 
1188
 
 
1189
   ASSERT(extra_move==MoveNone||move_is_ok(extra_move));
 
1190
 
 
1191
   ASSERT(!Uci->searching);
 
1192
 
 
1193
   // init
 
1194
 
 
1195
   game_get_board(Game,Uci->board);
 
1196
   if (extra_move != MoveNone) move_do(Uci->board,extra_move);
 
1197
 
 
1198
   board_to_fen(Uci->board,fen,256);
 
1199
   my_log("POLYGLOT FEN %s\n",fen);
 
1200
 
 
1201
   ASSERT(board_can_play(Uci->board));
 
1202
 
 
1203
   // more init
 
1204
 
 
1205
   start = 0;
 
1206
   end = game_pos(Game);
 
1207
   ASSERT(end>=start);
 
1208
 
 
1209
   // position
 
1210
 
 
1211
   game_get_board(Game,board,start);
 
1212
   board_to_fen(board,string,256);
 
1213
 
 
1214
   engine_send_queue(Engine,"position");
 
1215
 
 
1216
   if (my_string_equal(string,StartFen)) {
 
1217
      engine_send_queue(Engine," startpos");
 
1218
   } else {
 
1219
      engine_send_queue(Engine," fen %s",string);
 
1220
   }
 
1221
 
 
1222
   // move list
 
1223
 
 
1224
   if (end > start || extra_move != MoveNone) engine_send_queue(Engine," moves");
 
1225
 
 
1226
   for (pos = start; pos < end; pos++) { // game moves
 
1227
 
 
1228
      move = game_move(Game,pos);
 
1229
 
 
1230
      move_to_can(move,string,256);
 
1231
      engine_send_queue(Engine," %s",string);
 
1232
   }
 
1233
 
 
1234
   if (extra_move != MoveNone) { // move to ponder on
 
1235
      move_to_can(extra_move,string,256);
 
1236
      engine_send_queue(Engine," %s",string);
 
1237
   }
 
1238
 
 
1239
   // end
 
1240
 
 
1241
   engine_send(Engine,""); // newline
 
1242
}
 
1243
 
 
1244
// send_pv()
 
1245
 
 
1246
static void send_pv() {
 
1247
 
 
1248
   char pv_string[StringSize];
 
1249
   board_t board[1];
 
1250
   int move;
 
1251
   char move_string[StringSize];
 
1252
 
 
1253
   ASSERT(State->state!=WAIT);
 
1254
 
 
1255
   if (Uci->best_depth == 0) return;
 
1256
 
 
1257
   // xboard search information
 
1258
 
 
1259
   if (XB->post) {
 
1260
 
 
1261
      if (State->state == THINK || State->state == ANALYSE) {
 
1262
 
 
1263
         line_to_san(Uci->best_pv,Uci->board,pv_string,StringSize);
 
1264
         xboard_send(XBoard,"%d %+d %.0f %lld %s",Uci->best_depth,Uci->best_score,Uci->time*100.0,Uci->node_nb,pv_string);
 
1265
 
 
1266
      } else if (State->state == PONDER && option_get_bool("ShowPonder")) {
 
1267
 
 
1268
         game_get_board(Game,board);
 
1269
         move = State->exp_move;
 
1270
 
 
1271
         if (move != MoveNone && move_is_legal(move,board)) {
 
1272
            move_to_san(move,board,move_string,256);
 
1273
            line_to_san(Uci->best_pv,Uci->board,pv_string,StringSize);
 
1274
            xboard_send(XBoard,"%d %+d %.0f %lld (%s) %s",Uci->best_depth,Uci->best_score,Uci->time*100.0,Uci->node_nb,move_string,pv_string);
 
1275
         }
 
1276
      }
 
1277
   }
 
1278
 
 
1279
   // kibitz
 
1280
 
 
1281
   if ((Uci->searching && option_get_bool("KibitzPV") && Uci->time >= option_get_double("KibitzDelay"))
 
1282
    || (!Uci->searching && option_get_bool("KibitzMove"))) {
 
1283
 
 
1284
      if (State->state == THINK || State->state == ANALYSE) {
 
1285
 
 
1286
         line_to_san(Uci->best_pv,Uci->board,pv_string,StringSize);
 
1287
         xboard_send(XBoard,"%s depth=%d time=%.2f node=%lld speed=%.0f score=%+.2f pv=\"%s\"",option_get_string("KibitzCommand"),Uci->best_depth,Uci->time,Uci->node_nb,Uci->speed,double(Uci->best_score)/100.0,pv_string);
 
1288
 
 
1289
      } else if (State->state == PONDER) {
 
1290
 
 
1291
         game_get_board(Game,board);
 
1292
         move = State->exp_move;
 
1293
 
 
1294
         if (move != MoveNone && move_is_legal(move,board)) {
 
1295
            move_to_san(move,board,move_string,256);
 
1296
            line_to_san(Uci->best_pv,Uci->board,pv_string,StringSize);
 
1297
            xboard_send(XBoard,"%s depth=%d time=%.2f node=%lld speed=%.0f score=%+.2f pv=\"(%s) %s\"",option_get_string("KibitzCommand"),Uci->best_depth,Uci->time,Uci->node_nb,Uci->speed,double(Uci->best_score)/100.0,move_string,pv_string);
 
1298
         }
 
1299
      }
 
1300
   }
 
1301
}
 
1302
 
 
1303
// xboard_get()
 
1304
 
 
1305
static void xboard_get(xboard_t * xboard, char string[], int size) {
 
1306
 
 
1307
   ASSERT(xboard!=NULL);
 
1308
   ASSERT(string!=NULL);
 
1309
   ASSERT(size>=256);
 
1310
 
 
1311
   if (!io_get_line(xboard->io,string,size)) { // EOF
 
1312
      my_log("POLYGLOT *** EOF from XBoard ***\n");
 
1313
      quit();
 
1314
   }
 
1315
}
 
1316
 
 
1317
// xboard_send()
 
1318
 
 
1319
static void xboard_send(xboard_t * xboard, const char format[], ...) {
 
1320
 
 
1321
   va_list arg_list;
 
1322
   char string[StringSize];
 
1323
 
 
1324
   ASSERT(xboard!=NULL);
 
1325
   ASSERT(format!=NULL);
 
1326
 
 
1327
   // format
 
1328
 
 
1329
   va_start(arg_list,format);
 
1330
   vsprintf(string,format,arg_list);
 
1331
   va_end(arg_list);
 
1332
 
 
1333
   // send
 
1334
 
 
1335
   io_send(xboard->io,"%s",string);
 
1336
}
 
1337
 
 
1338
// learn()
 
1339
 
 
1340
static void learn(int result) {
 
1341
 
 
1342
   int pos;
 
1343
   board_t board[1];
 
1344
   int move;
 
1345
 
 
1346
   ASSERT(result>=-1&&result<=+1);
 
1347
 
 
1348
   ASSERT(XB->result);
 
1349
   ASSERT(State->computer[White]||State->computer[Black]);
 
1350
 
 
1351
   // init
 
1352
 
 
1353
   pos = 0;
 
1354
 
 
1355
   if (false) {
 
1356
   } else if (State->computer[White]) {
 
1357
      pos = 0;
 
1358
   } else if (State->computer[Black]) {
 
1359
      pos = 1;
 
1360
      result = -result;
 
1361
   } else {
 
1362
      my_fatal("learn(): unknown side\n");
 
1363
   }
 
1364
 
 
1365
   if (false) {
 
1366
   } else if (result > 0) {
 
1367
      my_log("POLYGLOT *LEARN WIN*\n");
 
1368
   } else if (result < 0) {
 
1369
      my_log("POLYGLOT *LEARN LOSS*\n");
 
1370
   } else {
 
1371
      my_log("POLYGLOT *LEARN DRAW*\n");
 
1372
   }
 
1373
 
 
1374
   // loop
 
1375
 
 
1376
   for (; pos < Game->size; pos += 2) {
 
1377
 
 
1378
      game_get_board(Game,board,pos);
 
1379
      move = game_move(Game,pos);
 
1380
 
 
1381
      book_learn_move(board,move,result);
 
1382
   }
 
1383
 
 
1384
   book_flush();
 
1385
}
 
1386
 
 
1387
// end of adapter.cpp
 
1388