|
|
1.1 root 1: /* This file contains code for X-CHESS.
2: Copyright (C) 1986 Free Software Foundation, Inc.
3:
4: This file is part of X-CHESS.
5:
6: X-CHESS is distributed in the hope that it will be useful,
7: but WITHOUT ANY WARRANTY. No author or distributor
8: accepts responsibility to anyone for the consequences of using it
9: or for whether it serves any particular purpose or works at all,
10: unless he says so in writing. Refer to the X-CHESS General Public
11: License for full details.
12:
13: Everyone is granted permission to copy, modify and redistribute
14: X-CHESS, but only under the conditions described in the
15: X-CHESS General Public License. A copy of this license is
16: supposed to have been given to you along with X-CHESS so you
17: can know your rights and responsibilities. It should be in a
18: file named COPYING. Among other things, the copyright notice
19: and this notice must be preserved on all copies. */
20:
21:
22: /* RCS Info: $Revision: 1.2 $ on $Date: 86/11/23 17:17:59 $
23: * $Source: /users/faustus/xchess/RCS/parse.c,v $
24: * Copyright (c) 1986 Wayne A. Christopher, U. C. Berkeley CAD Group
25: * Permission is granted to do anything with this code except sell it
26: * or remove this message.
27: *
28: * Parse a sequence of chess moves...
29: */
30:
31: #include "xchess.h"
32:
33: bool loading_flag = false;
34: bool loading_paused = false;
35:
36: static char *line;
37:
38: /* Load a record file in. This returns a number of things -- the board, the
39: * list of moves, and whose turn it is.
40: */
41:
42: void
43: load_game(file)
44: char *file;
45: {
46: FILE *fp;
47: char buf[BSIZE];
48: bool eflag;
49: move *m;
50: board *tmpboard = alloc(board);
51:
52: if (eq(file, "xchess.game") && saveflag) {
53: message_add(win1,
54: "Oops, I just overwrote the\nfile xchess.game...\n",
55: true);
56: message_add(win1, "I hope you had another copy.\n", true);
57: return;
58: }
59: if (!(fp = fopen(file, "r"))) {
60: perror(file);
61: return;
62: }
63:
64: /* Get a few lines... */
65: fgets(buf, BSIZE, fp);
66: message_add(win1, buf, false);
67: if (!oneboard)
68: message_add(win2, buf, false);
69:
70: fgets(buf, BSIZE, fp);
71: message_add(win1, buf, false);
72: if (!oneboard)
73: message_add(win2, buf, false);
74:
75: fgets(buf, BSIZE, fp);
76: if (eq(buf, "\tenglish\n"))
77: eflag = true;
78: else if (eq(buf, "\talgebraic\n"))
79: eflag = false;
80: else {
81: fprintf(stderr, "Can't decide whether this is english...\n");
82: return;
83: }
84:
85: board_init(tmpboard);
86: line = NULL;
87: m = parse_file(fp, tmpboard, eflag);
88: tfree(tmpboard);
89:
90: /* Now apply these moves to the board we were given... */
91: loading_flag = true;
92: while (m) {
93: if (!quickflag)
94: XSync(win1->display, 0);
95: win_process(true);
96: if (!quickflag)
97: sleep(1);
98: if (!loading_paused) {
99: prog_move(m);
100: m = m->next;
101: }
102: }
103: loading_flag = false;
104: if (line)
105: message_add(win1, line, false);
106:
107: while (fgets(buf, BSIZE, fp))
108: message_add(win1, buf, false);
109:
110: fclose(fp);
111:
112: return;
113: }
114:
115: /* Given a starting position (usually the beginning board configuration),
116: * read in a file of moves.
117: */
118:
119: move *
120: parse_file(fp, b, english)
121: FILE *fp;
122: board *b;
123: bool english;
124: {
125: move *mvs = NULL, *end = NULL;
126: char buf[BSIZE], *s, *t;
127:
128: while (fgets(buf, BSIZE, fp)) {
129: if (*buf == '#')
130: continue;
131: s = buf;
132:
133: /* The move number... */
134: if (!(t = gettok(&s)))
135: break;
136: if (!isdigit(*t)) {
137: line = copy(buf);
138: break;
139: }
140:
141: if (!(t = gettok(&s)))
142: break;
143: if (end)
144: end = end->next = (english ? parse_move(b, t, WHITE) :
145: parse_imove(b, t, WHITE));
146: else
147: mvs = end = (english ? parse_move(b, t, WHITE) :
148: parse_imove(b, t, WHITE));
149: if (!end) {
150: fprintf(stderr, "Can't parse %s\n", buf);
151: return (NULL);
152: }
153: board_move(b, end);
154:
155: if (!(t = gettok(&s)))
156: break;
157: if (end)
158: end = end->next = (english ? parse_move(b, t, BLACK) :
159: parse_imove(b, t, BLACK));
160: else
161: mvs = end = (english ? parse_move(b, t, BLACK) :
162: parse_imove(b, t, BLACK));
163: if (!end) {
164: fprintf(stderr, "Can't parse %s\n", buf);
165: return (NULL);
166: }
167: board_move(b, end);
168: }
169:
170: return (mvs);
171: }
172:
173: /* Parse a move. The move format accepted is as follows -
174: * move: spec-spec
175: * capture: specxspec
176: * kcastle: 2 o's
177: * qcastle: 3 o's
178: * A spec is either piece/pos, piece, or just pos. A pos consists of a column
179: * name followed by a row number. If the column name is kr, kn, kb, k, q,
180: * qb, qn, or qr, then the row number is according to the english system,
181: * or if it is a-h then it is according to the international system.
182: *
183: *** As of now the spec must include the position.
184: */
185:
186: move *
187: parse_move(b, str, w)
188: board *b;
189: char *str;
190: color w;
191: {
192: move *m = alloc(move);
193: char *s;
194: char spec1[16], spec2[16];
195: int i, j;
196:
197: if (debug) fprintf(stderr, "parsing %s\n", str);
198:
199: /* Check for castles. */
200: for (s = str, i = 0; *s; s++)
201: if ((*s == 'o') || (*s == 'O'))
202: i++;
203: if (i == 2) {
204: m->type = KCASTLE;
205: m->piece.type = KING;
206: m->piece.color = w;
207: return (m);
208: } else if (i == 3) {
209: m->type = QCASTLE;
210: m->piece.type = KING;
211: m->piece.color = w;
212: return (m);
213: }
214: if (index(str, '-'))
215: m->type = MOVE;
216: else if (index(str, 'x'))
217: m->type = CAPTURE;
218: else
219: return (NULL);
220: for (i = 0; str[i]; i++)
221: if ((str[i] == 'x') || (str[i] == '-'))
222: break;
223: else
224: spec1[i] = str[i];
225: spec1[i] = '\0';
226: for (i++, j = 0; str[i]; i++, j++)
227: if ((str[i] == 'x') || (str[i] == '-'))
228: break;
229: else
230: spec2[j] = str[i];
231: spec2[j] = '\0';
232:
233: /* Now decode the specifications. */
234: s = spec1;
235: switch (*s) {
236: case 'p': case 'P':
237: m->piece.type = PAWN; break;
238: case 'r': case 'R':
239: m->piece.type = ROOK; break;
240: case 'n': case 'N':
241: m->piece.type = KNIGHT; break;
242: case 'b': case 'B':
243: m->piece.type = BISHOP; break;
244: case 'q': case 'Q':
245: m->piece.type = QUEEN; break;
246: case 'k': case 'K':
247: m->piece.type = KING; break;
248: default:
249: return (NULL);
250: }
251: m->piece.color = w;
252: s += 2;
253:
254: /* Now get the {q,k}{,b,n,r}n string... */
255: if ((s[0] == 'q') && (s[1] == 'r'))
256: m->fromx = 0, s += 2;
257: else if ((s[0] == 'q') && (s[1] == 'n'))
258: m->fromx = 1, s += 2;
259: else if ((s[0] == 'q') && (s[1] == 'b'))
260: m->fromx = 2, s += 2;
261: else if ((s[0] == 'q') && isdigit(s[1]))
262: m->fromx = 3, s += 1;
263: else if ((s[0] == 'k') && isdigit(s[1]))
264: m->fromx = 4, s += 1;
265: else if ((s[0] == 'k') && (s[1] == 'b'))
266: m->fromx = 5, s += 2;
267: else if ((s[0] == 'k') && (s[1] == 'n'))
268: m->fromx = 6, s += 2;
269: else if ((s[0] == 'k') && (s[1] == 'r'))
270: m->fromx = 7, s += 2;
271: m->fromy = ((w == WHITE) ? (SIZE - atoi(s)) : (atoi(s) - 1));
272:
273: if ((b->square[m->fromy][m->fromx].color != w) ||
274: (b->square[m->fromy][m->fromx].type != m->piece.type)) {
275: fprintf(stderr, "Error: bad stuff\n");
276: return (NULL);
277: }
278:
279: s = spec2;
280: if (m->type == CAPTURE) {
281: switch (*s) {
282: case 'p': case 'P':
283: m->taken.type = PAWN; break;
284: case 'r': case 'R':
285: m->taken.type = ROOK; break;
286: case 'n': case 'N':
287: m->taken.type = KNIGHT; break;
288: case 'b': case 'B':
289: m->taken.type = BISHOP; break;
290: case 'q': case 'Q':
291: m->taken.type = QUEEN; break;
292: case 'k': case 'K':
293: m->taken.type = KING; break;
294: default:
295: return (NULL);
296: }
297: m->taken.color = ((w == WHITE) ? BLACK : WHITE);
298: s += 2;
299: }
300:
301: /* Now get the {q,k}{,b,n,r}n string... */
302: if ((s[0] == 'q') && (s[1] == 'r'))
303: m->tox = 0, s += 2;
304: else if ((s[0] == 'q') && (s[1] == 'n'))
305: m->tox = 1, s += 2;
306: else if ((s[0] == 'q') && (s[1] == 'b'))
307: m->tox = 2, s += 2;
308: else if ((s[0] == 'q') && isdigit(s[1]))
309: m->tox = 3, s += 1;
310: else if ((s[0] == 'k') && isdigit(s[1]))
311: m->tox = 4, s += 1;
312: else if ((s[0] == 'k') && (s[1] == 'b'))
313: m->tox = 5, s += 2;
314: else if ((s[0] == 'k') && (s[1] == 'n'))
315: m->tox = 6, s += 2;
316: else if ((s[0] == 'k') && (s[1] == 'r'))
317: m->tox = 7, s += 2;
318: m->toy = ((w == WHITE) ? (SIZE - atoi(s)) : (atoi(s) - 1));
319:
320: if ((m->type == CAPTURE) && ((b->square[m->toy][m->tox].color !=
321: m->taken.color) || (b->square[m->toy][m->tox].type !=
322: m->taken.type))) {
323: fprintf(stderr, "Error: bad stuff\n");
324: return (NULL);
325: }
326:
327: return (m);
328: }
329:
330: /* Parse an algebraic notation move. This is a lot easier... */
331:
332: move *
333: parse_imove(b, buf, w)
334: board *b;
335: char *buf;
336: color w;
337: {
338: char *s;
339: move *m = alloc(move);
340: int n;
341:
342: if (debug) fprintf(stderr, "(alg) parsing %s\n", buf);
343:
344: for (s = buf, n = 0; *s; s++)
345: if ((*s == 'o') || (*s == 'O'))
346: n++;
347: s = buf;
348:
349: if (n == 2)
350: m->type = KCASTLE;
351: else if (n == 3)
352: m->type = QCASTLE;
353: else {
354: m->fromx = *s++ - 'a';
355: m->fromy = SIZE - (*s++ - '0');
356: m->tox = *s++ - 'a';
357: m->toy = SIZE - (*s++ - '0');
358: m->piece = b->square[m->fromy][m->fromx];
359: m->taken = b->square[m->toy][m->tox];
360: if (m->taken.color == NONE)
361: m->type = MOVE;
362: else
363: m->type = CAPTURE;
364: /* for pawns we must account for en passant */
365: if (m->piece.type == PAWN) {
366: if (m->type == MOVE && m->fromx != m->tox) {
367: m->enpassant = 1;
368: m->type = CAPTURE;
369: }
370: }
371: }
372:
373: if (m->piece.color != w) {
374: fprintf(stderr, "Error: parse_imove: piece of wrong color!\n");
375: return (NULL);
376: }
377: if ((m->piece.type == KING) && (m->fromy == m->toy) && (m->fromx == 4)
378: && (m->tox == 6))
379: m->type = KCASTLE;
380: else if ((m->piece.type == KING) && (m->fromy == m->toy) &&
381: (m->fromx == 4) && (m->tox == 2))
382: m->type = QCASTLE;
383:
384: return (m);
385: }
386:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.