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