1 #include "includes.h"
2 #include "knightcap.h"
3
4 extern struct state *state;
5
6 extern char opponents_list[];
7 extern char noplay_list[];
8 int white_time, black_time;
9
10 /*
11 Here are some samples of what FICS looks like:
12
13 fics% match
14 jeromed (1601) seeking 2 12 unrated blitz ("play 17" to respond)
15 fics% ThingOne
16 Issuing: tridge (++++) ThingOne (2247) unrated blitz 2 12.
17 --** ThingOne is a computer **--
18 fics%
19 ThingOne accepts your challenge.
20 fics%
21 Creating: ThingOne (2247) tridge (++++) unrated blitz 2 12
22 {Game 34 (ThingOne vs. tridge) Creating unrated blitz match.}
23
24 #@#000tango *tridge :RNBQKBNRPPPP PPP P pppppppprnbqkbnr001B39390011500120P/e2-e4(0:17)@#@
25
26
27
28 fics%
29 Challenge: ixosjaps (1935) Tridge (2128) rated blitz 2 12.
30 Your blitz rating will change: Win: +33, Draw: -32, Loss: -98
31 Your new RD will be 151.7
32 You can "accept" or "decline", or propose different parameters.
33 fics% acceptposition is size 224
34
35 You accept the challenge of ixosjaps.
36
37 Creating: Tridge (2128) ixosjaps (1935) rated blitz 2 12
38 {Game 14 (Tridge vs. ixosjaps) Creating rated blitz match.}
39
40 Game 14 (Tridge vs. ixosjaps)
41
42 #@#013Tridge *ixosjaps :RNBQKBNRPPPPPPPP pppppppprnbqkbnr001W39390012000120none (0:00)@#@
43 fics% W: 20 n/s 105/0 2:2 mo=21/2 hash=0/105 t=0 d2d3
44 W: -12 n/s 639/0 3:4 mo=80/21 hash=65/641 t=0 d2d3
45
46
47 blindfolded accepts your challenge.
48 fics%
49 Creating: blindfolded (1687) KnightCap (1992) rated blitz 2 10
50 {Game 6 (blindfolded vs. KnightCap) Creating rated blitz match.}
51
52 Game 6 (blinposition is size 228
53
54
55 White (KnightCap) : 2 mins, 16 secs
56 Black (mrb) : 1 mins, 34 secs
57
58 Notification: TayxBot, who has an adjourned game with you, has arrived.
59 fics%
60 Challenge: TayxBot (1940) KnightCap (1940) rated blitz 2 10 (adjourned).
61 --** TayxBot is a computer **--
62 Your blitz rating will change: Win: +4, Draw: +0, Loss: -4
63
64 {Game 52 (KlausK vs. KnightCap) KlausK resigns} 0-1
65
66 Tridge offers you a draw.
67
68
69 Tridge would like to abort the game; type "abort" to accept.
70
71 Tridge would like to adjourn the game; type "adjourn" to accept.
72
73 Miuek requests to pause the game.
74
75
76 Notification: tufnel, who has an adjourned game with you, has arrived
77
78 */
79
80 extern char *ics_name;
81 extern char *ics_master;
82 extern char *play_target;
83 extern int seeking;
84 extern int seek_answering;
85
86 #define ICSNAME ics_name
87
88 #define ICSPROMPT1 "aics% "
89 #define ICSPROMPT2 "fics% "
90 #define ICSEND "} "
91 #define ICSDISCONNECT "disconnected"
92 #define ICSNOGAME1 "re neither playing,"
93 #define ICSNOGAME2 "re not observing or playing"
94 #define ICSADJOURN1 "requests adjournment"
95 #define ICSADJOURN2 "would like to adjourn the game"
96 #define ICSABORT1 "requests that the game be aborted"
97 #define ICSABORT2 "would like to abort the game"
98 #define ICSRATING1 "Rating changes:"
99 #define ICSRATING2 "rating will change:"
100 #define ICSGAMEOVER "{Game %d %s vs. %s"
101 #define NOPLAY "KnightC is learning its eval so it accepts seeks from other computers (computer play helps). But it never accepts against the same computer twice, so it will play you very infrequently. If you don't like this, please message KnightC and KnightC will stop playing you."
102
ics_thanks(void)103 void ics_thanks(void)
104 {
105 prog_printf("say thanks for the game\n");
106 }
107
parse_ics_special(char * line)108 static void parse_ics_special(char *line)
109 {
110 char white_player[1000];
111 char black_player[1000];
112 char white_rating[1000], black_rating[1000];
113 int game_num, game_time, increment;
114 char dum[1000], dum1[1000], dum2[1000];
115 char last_opponent[1000],
116 opponent[1000], last_last_opponent[1000];
117 int temp_time, temp_inc, rating;
118 static FILE *f;
119
120 extern struct state *state;
121
122 if (strlen(line) > 900) {
123 lprintf(0,"hacker attack?? len=%d\n", strlen(line));
124 return;
125 }
126
127 if (!state->ics_robot)
128 return;
129
130 if (!f) {
131 f = fopen("ics.log", "w");
132 if (!f)
133 f = fopen("/tmp/ics.log", "w");
134 setlinebuf(f);
135 }
136
137 if (ics_master && sscanf(line,"%s tells you: icsrun ", dum) == 1 &&
138 strstr(line," tells you: icsrun ") &&
139 strcmp(dum, ics_master) == 0) {
140 char *p = strstr(line,"icsrun ");
141 p += strlen("icsrun ");
142 if (!parse_stdin(p)) {
143 if (prog_running()) {
144 prog_printf("%s\n",p);
145 }
146 }
147 return;
148 }
149
150 /* answer computer seeks in ICS (probably doesn't work for FICS
151 right now) */
152 if (state->open && seek_answering && !strstr(line, "KnightC") &&
153 strstr(line, "seeking") && !strstr(line, "unrated") &&
154 (strstr(line, "blitz") || strstr(line, "Blitz"))) {
155 sscanf(line, "%s (%d) %s %s %d %d", opponent, &rating,
156 dum1, dum2, &temp_time, &temp_inc);
157 lprintf(0, "%s %s %s %d %d %d %d\n", last_last_opponent,
158 last_opponent, opponent,
159 strcmp(opponent, last_opponent),
160 strstr(noplay_list, opponent), rating, temp_time,
161 temp_inc);
162 if (strcmp(opponent, last_last_opponent) !=0 &&
163 strcmp(opponent, last_opponent) !=0 &&
164 strstr(noplay_list, opponent) == NULL &&
165 rating >= 2000) {
166 int game_num;
167 char *p = strstr(line, "play ");
168 p += strlen("play ");
169 sscanf(p, "%d", &game_num);
170 prog_printf("play %d\n", game_num);
171 lprintf(0,"challenged: %s\n", opponent);
172 strcpy(last_last_opponent,last_opponent);
173 strcpy(last_opponent,opponent);
174 if (!strstr(opponents_list,opponent)) {
175 FILE *f1;
176
177 prog_printf("mess %s %s\n", opponent, NOPLAY);
178 strcat(opponents_list, opponent);
179 f1 = fopen("opponents.dat", "w");
180 fprintf(f1, "%s", opponents_list);
181 fclose(f1);
182 }
183 }
184 }
185
186 /* ignore all other tells */
187 if (strstr(line,"tells you:")) {
188 return;
189 }
190
191 /* maybe we think we are playing, but we're not */
192 if (strstr(line,ICSNOGAME1) || strstr(line,ICSNOGAME2)) {
193 state->computer = 0;
194 return;
195 }
196
197 /* someone offers us a draw? */
198 if (strstr(line,"offers you a draw.")) {
199 if ((state->position.flags & FLAG_ACCEPT_DRAW)){
200 #if !LEARN_EVAL
201 prog_printf("draw\n");
202 #endif
203 } else {
204 prog_printf("say my programming says this is not a draw (it may be wrong)\n");
205 }
206 return;
207 }
208
209 /* someone wants to abort? only abort at the very start of a game */
210 if (strstr(line,ICSABORT1) || strstr(line,ICSABORT2)) {
211 if (state->position.move_num < 6) {
212 prog_printf("abort\n");
213 } else {
214 prog_printf("say this computer only accepts aborts in the first 3 moves of a game\n");
215 }
216 return;
217 }
218
219 /* someone wants to pause? */
220 if (strstr(line,"requests to pause the game")) {
221 prog_printf("pause\n");
222 return;
223 }
224
225 /* someone wants to unpause? */
226 if (strstr(line,"requests to unpause the game")) {
227 prog_printf("unpause\n");
228 return;
229 }
230
231 /* someone wants to adjourn? always accept */
232 if (strstr(line,ICSADJOURN1) || strstr(line,ICSADJOURN2)) {
233 prog_printf("adjourn\n");
234 return;
235 }
236
237 /* is it all over? */
238 if (sscanf(line,ICSGAMEOVER,
239 &game_num, white_player, black_player) == 3 &&
240 strstr(line,ics_name) && !strstr(line,"Creating")) {
241 if (strstr(line,"1-0") || strstr(line,"1/2-1/2") ||
242 strstr(line,"0-1")) {
243 char *p = strstr(line, ICSEND);
244 p += strlen(ICSEND);
245 fprintf(f, "%s\n", p);
246 ics_thanks();
247 if (strstr(line,"checkmated") || strstr(line, "resigns")) {
248 if ((strstr(line,"1-0") &&
249 strstr(white_player, ics_name)) ||
250 (strstr(line,"0-1") &&
251 strstr(black_player, ics_name)))
252 state->won = 1;
253 else
254 state->won = 0;
255 } else if (strstr(line, "draw")) {
256 state->won = STALEMATE;
257 } else {
258 state->won = TIME_FORFEIT;
259 }
260 } else if (strstr(line, ICSDISCONNECT)) {
261 fprintf(f,"%s\n", line);
262 }
263 state->computer = 0;
264 sleep(1);
265 return;
266 }
267
268 /* has someone challenged us? */
269 if (sscanf(line,"Challenge: %s", dum) == 1) {
270 if (!state->open) {
271 prog_printf("tell %s I am cleaning my brain. Should be finished in a few minutes (I'll let you know when I am done)\n", dum);
272 state->notified = 1;
273 strcpy(state->notifyee, dum);
274 return;
275 }
276 if (state->autoplay && state->open) {
277 /* auto accept! */
278 prog_printf("accept %s\n", dum);
279 fprintf(f, "accepted challenge\n");
280 }
281 return;
282 }
283
284 /* has someone with an adjourned game arrived? */
285 if (strstr(line,"adjourned") &&
286 sscanf(line,"Notification: %s who has an adjourned game with you",
287 dum) == 1) {
288 if (dum[strlen(dum)-1] == ',')
289 dum[strlen(dum)-1] = 0;
290 if (state->autoplay && state->open) {
291 prog_printf("tell %s Shall we finish our adjourned game?\n",
292 dum);
293 if (state->computer == 0)
294 prog_printf("match %s\n",dum);
295 }
296 return;
297 }
298
299 /* has a match been created? */
300 if (sscanf(line,"Creating: %s %s %s %s %s %s %d %d",
301 white_player, white_rating,
302 black_player, black_rating,
303 dum, dum,
304 &game_time, &increment) == 8) {
305
306 reset_board();
307 timer_estimate(game_time*60, game_time*60, increment);
308
309 if (strstr(line, "blitz")) {
310 strcpy(state->game_type, "blitz");
311 } else if (strstr(line, "bullet") || strstr(line, "lightning")) {
312 strcpy(state->game_type, "bullet");
313 } else if (strstr(line, "standard")) {
314 strcpy(state->game_type,"standard");
315 } else {
316 strcpy(state->game_type,"unknown");
317 }
318
319 prog_printf("kibitz Hello from KnightCap! (running in ICS robot mode)\n");
320 fprintf(f, "Creating %s vs %s mt=%2.1f\n",
321 white_player, black_player, state->move_time);
322 sscanf(white_rating, "(%d)", &state->krating);
323 sscanf(black_rating, "(%d)", &state->orating);
324 if (strstr(black_player, ics_name)) {
325 int temp=state->krating;
326 state->krating = state->orating;
327 state->orating = temp;
328 }
329
330 prog_printf("re\n");
331 return;
332 }
333
334 /* get the rating changes */
335 if (strstr(line,ICSRATING1) || strstr(line,ICSRATING2)) {
336 char *p = strstr(line, "Draw: ");
337 p += strlen("Draw: ");
338 if (sscanf(p, "%d", &(state->rating_change)) == 1) {
339 lprintf(0, "***Rating Change: %d\n",
340 state->rating_change);
341 }
342 }
343 }
344
345
parse_ics_move(char * line,int player,Move * move,Piece * promotion)346 int parse_ics_move(char *line,int player, Move *move, Piece *promotion)
347 {
348 extern struct state *state;
349 int nextplayer, x, y;
350 char board[20][9]; /* its made too long to be less error prone */
351 char tomove;
352 int pawnfile, wshort, wlong, bshort, blong, fiftycount, game;
353 char whiteplayer[100], blackplayer[100];
354 int relation;
355 int initial_time;
356 int increment;
357 int movenum;
358 char prevmove[20];
359 Position b1, b2;
360 Position *b = &state->position;
361 int bad_move = 0;
362 int wstrength, bstrength;
363 int from, to;
364
365 while (*line && !isprint(*line))
366 line++;
367
368 while (strncmp(line,ICSPROMPT1,strlen(ICSPROMPT1)) == 0)
369 line += strlen(ICSPROMPT1);
370
371 while (strncmp(line,ICSPROMPT2,strlen(ICSPROMPT2)) == 0)
372 line += strlen(ICSPROMPT2);
373
374 memset(board, 0, sizeof(board));
375
376 if (sscanf(line,"<12> %s %s %s %s %s %s %s %s %c %d %d %d %d %d %d %d %s %s %d %d %d %d %d %d %d %d %s",
377 board[7], board[6], board[5], board[4],
378 board[3], board[2], board[1], board[0],
379 &tomove,
380 &pawnfile,
381 &wshort, &wlong,
382 &bshort, &blong,
383 &fiftycount,
384 &game,
385 whiteplayer, blackplayer,
386 &relation,
387 &initial_time,
388 &increment,
389 &wstrength,
390 &bstrength,
391 &white_time,
392 &black_time,
393 &movenum,
394 prevmove) != 27) {
395 parse_ics_special(line);
396 return 0;
397 }
398
399 state->increment = increment;
400 state->game_time = initial_time;
401 state->wtime = white_time;
402 state->btime = black_time;
403
404 if (tomove == 'W') {
405 nextplayer = 1;
406 } else if (tomove == 'B') {
407 nextplayer = -1;
408 } else {
409 return 0;
410 }
411
412 strcpy(state->white_player, whiteplayer);
413 strcpy(state->black_player, blackplayer);
414
415 if (strcmp(ics_name, whiteplayer) == 0) {
416 timer_estimate(white_time, black_time, increment);
417 if (black_time <= 0)
418 prog_printf("flag\n");
419 state->colour = 1;
420 }
421
422 if (strcmp(ics_name, blackplayer) == 0) {
423 timer_estimate(black_time, white_time, increment);
424 if (white_time <= 0)
425 prog_printf("flag\n");
426 state->colour = -1;
427 }
428
429 if (tomove == 'W') {
430 lprintf(0,"*%s: %d:%02d %s %d:%02d %d. ... %s mtime=%2.1f\n",
431 whiteplayer, white_time/60, white_time%60,
432 blackplayer, black_time/60, black_time%60,
433 movenum, prevmove, state->move_time);
434 } else {
435 lprintf(0," %s: %d:%02d *%s %d:%02d %d. %s mtime=%2.1f\n",
436 whiteplayer, white_time/60, white_time%60,
437 blackplayer, black_time/60, black_time%60,
438 movenum, prevmove, state->move_time);
439 }
440
441 if (!strncmp(prevmove, "none", 4)) {
442 /* its a new game */
443 reset_board();
444 if (abs(relation) == 1 && state->ics_robot) {
445 if (strcmp(whiteplayer, ics_name) == 0) {
446 state->computer = 1;
447 state->colour = 1;
448 } else {
449 state->computer = -1;
450 state->colour = -1;
451 }
452
453 }
454 return 0;
455 } else if (!strncmp(prevmove, "o-o-o", 5)) {
456 if (nextplayer < 0) {
457 move->from = E1;
458 move->to = C1;
459 } else {
460 move->from = E8;
461 move->to = C8;
462 }
463 } else if (!strncmp(prevmove, "o-o", 3)) {
464 if (nextplayer < 0) {
465 move->from = E1;
466 move->to = G1;
467 } else {
468 move->from = E8;
469 move->to = G8;
470 }
471 } else {
472 if (prevmove[1] != '/') {
473 return 0;
474 }
475
476 if (prevmove[4] != '-') {
477 return 0;
478 }
479
480 if (!parse_square(prevmove+2, &from) ||
481 !parse_square(prevmove+5, &to))
482 return 0;
483
484 move->from = from;
485 move->to = to;
486 }
487
488 if (!legal_move(&state->position, move) ||
489 nextplayer != -player) {
490 bad_move = 1;
491 }
492
493 memset(&b1, 0, sizeof(b1));
494
495 for (x=0;x<8;x++)
496 for (y=0;y<8;y++) {
497 Piece p;
498 p = charpiece(board[y][x]);
499 if (islower(board[y][x])) p = -p;
500 b1.board[POSN(x,y)] = p;
501 }
502
503 if (memcmp(b->board, b1.board, sizeof(b1.board)) == 0) {
504 /* we already have the right position */
505 return 0;
506 }
507
508 if (wshort)
509 b1.flags |= WHITE_CASTLE_SHORT;
510 if (bshort)
511 b1.flags |= BLACK_CASTLE_SHORT;
512 if (wlong)
513 b1.flags |= WHITE_CASTLE_LONG;
514 if (blong)
515 b1.flags |= BLACK_CASTLE_LONG;
516
517 if (pawnfile != -1) {
518 if (nextplayer == -1)
519 b1.enpassent = POSN(pawnfile, 2);
520 else
521 b1.enpassent = POSN(pawnfile, 5);
522 }
523
524 b1.fifty_count = fiftycount;
525
526 if (!bad_move) {
527 if (!do_move(&b2, b, move)) {
528 bad_move = 1;
529 }
530 if (memcmp(b2.board, b1.board, sizeof(b1.board)) != 0) {
531 bad_move = 1;
532 }
533 }
534
535 if (bad_move) {
536 /* assume ICS is right! We try to generate a valid
537 position from what its given us */
538 state->computer = 0;
539
540 (*b) = b1;
541
542 b->move_num = ((movenum-1) * 2);
543 if (nextplayer == -1) {
544 b->move_num++;
545 }
546
547 memset(state->hash_list, 0,
548 sizeof(state->hash_list[0])*b->move_num);
549
550 /* now the tricky bit - getting the pboard and piece
551 list reasonable */
552 create_pboard(b);
553
554 if (abs(relation) == 1 && state->ics_robot) {
555 if (strcmp(whiteplayer, ics_name) == 0) {
556 state->computer = 1;
557 /* Need an extra flag for td updates */
558 } else {
559 state->computer = -1;
560 }
561 }
562
563 lprintf(0,"generated position\n");
564 return 0;
565 }
566
567 /* its all ok! */
568
569 return 1;
570 }
571