src/chess/pgn.c

Wed, 29 Apr 2026 17:41:00 +0200

author
Mike Becker <universe@uap-core.de>
date
Wed, 29 Apr 2026 17:41:00 +0200
changeset 118
0f2ffbc408ce
parent 117
ee539a9691f0
permissions
-rw-r--r--

prettier line breaking in exported PGNs

resolves #836

50
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
1 /*
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
3 *
55
54ea19938d57 updated copyright and version info
Mike Becker <universe@uap-core.de>
parents: 54
diff changeset
4 * Copyright 2016 Mike Becker. All rights reserved.
50
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
5 *
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
6 * Redistribution and use in source and binary forms, with or without
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
7 * modification, are permitted provided that the following conditions are met:
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
8 *
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
9 * 1. Redistributions of source code must retain the above copyright
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
10 * notice, this list of conditions and the following disclaimer.
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
11 *
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
12 * 2. Redistributions in binary form must reproduce the above copyright
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
13 * notice, this list of conditions and the following disclaimer in the
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
14 * documentation and/or other materials provided with the distribution.
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
15 *
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
26 * POSSIBILITY OF SUCH DAMAGE.
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
27 *
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
28 */
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
29
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
30 #include "pgn.h"
107
36dd94278142 fix that PGN (with comments) can exceed 80 chars
Mike Becker <universe@uap-core.de>
parents: 106
diff changeset
31
36dd94278142 fix that PGN (with comments) can exceed 80 chars
Mike Becker <universe@uap-core.de>
parents: 106
diff changeset
32 #include <stdlib.h>
50
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
33 #include <ctype.h>
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
34 #include <string.h>
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
35
60
0c50aac49e55 adds error messages to PGN reader
Mike Becker <universe@uap-core.de>
parents: 59
diff changeset
36 enum {
0c50aac49e55 adds error messages to PGN reader
Mike Becker <universe@uap-core.de>
parents: 59
diff changeset
37 pgn_error_missing_quote = 1,
0c50aac49e55 adds error messages to PGN reader
Mike Becker <universe@uap-core.de>
parents: 59
diff changeset
38 pgn_error_missing_bracket,
70
5427beba96d1 pgn parser can now handle comments (although it ignores them for now)
Mike Becker <universe@uap-core.de>
parents: 65
diff changeset
39 pgn_error_missing_brace,
60
0c50aac49e55 adds error messages to PGN reader
Mike Becker <universe@uap-core.de>
parents: 59
diff changeset
40 pgn_error_missing_dot,
0c50aac49e55 adds error messages to PGN reader
Mike Becker <universe@uap-core.de>
parents: 59
diff changeset
41 pgn_error_move_syntax,
0c50aac49e55 adds error messages to PGN reader
Mike Becker <universe@uap-core.de>
parents: 59
diff changeset
42 pgn_error_move_semantics
0c50aac49e55 adds error messages to PGN reader
Mike Becker <universe@uap-core.de>
parents: 59
diff changeset
43 };
0c50aac49e55 adds error messages to PGN reader
Mike Becker <universe@uap-core.de>
parents: 59
diff changeset
44
0c50aac49e55 adds error messages to PGN reader
Mike Becker <universe@uap-core.de>
parents: 59
diff changeset
45 static const char* pgn_error_strings[] = {
0c50aac49e55 adds error messages to PGN reader
Mike Becker <universe@uap-core.de>
parents: 59
diff changeset
46 "No Error.",
0c50aac49e55 adds error messages to PGN reader
Mike Becker <universe@uap-core.de>
parents: 59
diff changeset
47 "Tag values must be enclosed in double-quotes.",
70
5427beba96d1 pgn parser can now handle comments (although it ignores them for now)
Mike Becker <universe@uap-core.de>
parents: 65
diff changeset
48 "Missing closing brace '}' for comment.",
60
0c50aac49e55 adds error messages to PGN reader
Mike Becker <universe@uap-core.de>
parents: 59
diff changeset
49 "Tags must be enclosed in square brackets: '[Key \"Value\"]'.",
0c50aac49e55 adds error messages to PGN reader
Mike Becker <universe@uap-core.de>
parents: 59
diff changeset
50 "Move numbers must be terminated with a dot (e.g. '13.' - not '13').",
0c50aac49e55 adds error messages to PGN reader
Mike Becker <universe@uap-core.de>
parents: 59
diff changeset
51 "Move is syntactically incorrect.",
0c50aac49e55 adds error messages to PGN reader
Mike Becker <universe@uap-core.de>
parents: 59
diff changeset
52 "Move is not valid according to chess rules."
0c50aac49e55 adds error messages to PGN reader
Mike Becker <universe@uap-core.de>
parents: 59
diff changeset
53 };
0c50aac49e55 adds error messages to PGN reader
Mike Becker <universe@uap-core.de>
parents: 59
diff changeset
54
0c50aac49e55 adds error messages to PGN reader
Mike Becker <universe@uap-core.de>
parents: 59
diff changeset
55 const char* pgn_error_str(int code) {
0c50aac49e55 adds error messages to PGN reader
Mike Becker <universe@uap-core.de>
parents: 59
diff changeset
56 return pgn_error_strings[code];
0c50aac49e55 adds error messages to PGN reader
Mike Becker <universe@uap-core.de>
parents: 59
diff changeset
57 }
0c50aac49e55 adds error messages to PGN reader
Mike Becker <universe@uap-core.de>
parents: 59
diff changeset
58
50
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
59 int read_pgn(FILE* stream, GameState *gamestate, GameInfo *gameinfo) {
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
60 int c, i;
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
61
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
62 char result[8];
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
63
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
64 char tagkey[32];
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
65 char tagvalue[128];
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
66
64
4eda5df55f86 fixes castling not printed correctly to PGN
Mike Becker <universe@uap-core.de>
parents: 60
diff changeset
67 /* read tag pairs */
82
e75865d90111 remove unnecessary loop variable
Mike Becker <universe@uap-core.de>
parents: 81
diff changeset
68 while (true) {
50
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
69 while (isspace(c = fgetc(stream)));
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
70 if (c == '1') {
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
71 break;
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
72 }
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
73 if (c != '[') {
60
0c50aac49e55 adds error messages to PGN reader
Mike Becker <universe@uap-core.de>
parents: 59
diff changeset
74 return pgn_error_missing_bracket;
50
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
75 }
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
76 while (isspace(c = fgetc(stream)));
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
77 i = 0;
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
78 do {
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
79 tagkey[i++] = c;
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
80 } while (!isspace(c = fgetc(stream)));
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
81 tagkey[i] = '\0';
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
82 while (isspace(c = fgetc(stream)));
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
83 if (c != '"') {
60
0c50aac49e55 adds error messages to PGN reader
Mike Becker <universe@uap-core.de>
parents: 59
diff changeset
84 return pgn_error_missing_quote;
50
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
85 }
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
86 i = 0;
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
87 while ((c = fgetc(stream)) != '"') {
60
0c50aac49e55 adds error messages to PGN reader
Mike Becker <universe@uap-core.de>
parents: 59
diff changeset
88 if (c == '\n' || c == EOF) {
0c50aac49e55 adds error messages to PGN reader
Mike Becker <universe@uap-core.de>
parents: 59
diff changeset
89 return pgn_error_missing_quote;
50
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
90 }
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
91 tagvalue[i++] = c;
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
92 }
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
93 tagvalue[i] = '\0';
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
94 if (fgetc(stream) != ']') {
60
0c50aac49e55 adds error messages to PGN reader
Mike Becker <universe@uap-core.de>
parents: 59
diff changeset
95 return pgn_error_missing_bracket;
50
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
96 }
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
97
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
98 if (strcmp("Result", tagkey) == 0) {
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
99 memcpy(result, tagvalue, 8);
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
100 }
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
101 }
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
102
64
4eda5df55f86 fixes castling not printed correctly to PGN
Mike Becker <universe@uap-core.de>
parents: 60
diff changeset
103 /* read moves */
50
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
104 if (fgetc(stream) != '.') {
60
0c50aac49e55 adds error messages to PGN reader
Mike Becker <universe@uap-core.de>
parents: 59
diff changeset
105 return pgn_error_missing_dot;
50
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
106 }
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
107
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
108 char movestr[10];
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
109 Move move;
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
110 uint8_t curcol = WHITE;
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
111
82
e75865d90111 remove unnecessary loop variable
Mike Becker <universe@uap-core.de>
parents: 81
diff changeset
112 while (true) {
64
4eda5df55f86 fixes castling not printed correctly to PGN
Mike Becker <universe@uap-core.de>
parents: 60
diff changeset
113 /* move */
50
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
114 while (isspace(c = fgetc(stream)));
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
115 i = 0;
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
116 do {
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
117 movestr[i++] = c;
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
118 if (i >= 10) {
81
82d3b044aa69 fix incorrect error value when a move string is too long in a PGN
Mike Becker <universe@uap-core.de>
parents: 80
diff changeset
119 return pgn_error_move_syntax;
50
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
120 }
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
121 } while (!isspace(c = fgetc(stream)));
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
122 movestr[i] = '\0';
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
123 if (eval_move(gamestate, movestr, &move, curcol)
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
124 != VALID_MOVE_SYNTAX) {
60
0c50aac49e55 adds error messages to PGN reader
Mike Becker <universe@uap-core.de>
parents: 59
diff changeset
125 return pgn_error_move_syntax;
50
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
126 }
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
127 if (validate_move(gamestate, &move) != VALID_MOVE_SEMANTICS) {
60
0c50aac49e55 adds error messages to PGN reader
Mike Becker <universe@uap-core.de>
parents: 59
diff changeset
128 return pgn_error_move_semantics;
50
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
129 }
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
130 apply_move(gamestate, &move);
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
131
70
5427beba96d1 pgn parser can now handle comments (although it ignores them for now)
Mike Becker <universe@uap-core.de>
parents: 65
diff changeset
132 /* skip spaces */
5427beba96d1 pgn parser can now handle comments (although it ignores them for now)
Mike Becker <universe@uap-core.de>
parents: 65
diff changeset
133 while (isspace(c = fgetc(stream)));
5427beba96d1 pgn parser can now handle comments (although it ignores them for now)
Mike Becker <universe@uap-core.de>
parents: 65
diff changeset
134
5427beba96d1 pgn parser can now handle comments (although it ignores them for now)
Mike Becker <universe@uap-core.de>
parents: 65
diff changeset
135 /* parse possible comment */
5427beba96d1 pgn parser can now handle comments (although it ignores them for now)
Mike Becker <universe@uap-core.de>
parents: 65
diff changeset
136 if (c == '{') {
5427beba96d1 pgn parser can now handle comments (although it ignores them for now)
Mike Becker <universe@uap-core.de>
parents: 65
diff changeset
137 // TODO: interpret comment (may contain clock info)
5427beba96d1 pgn parser can now handle comments (although it ignores them for now)
Mike Becker <universe@uap-core.de>
parents: 65
diff changeset
138 do {
5427beba96d1 pgn parser can now handle comments (although it ignores them for now)
Mike Becker <universe@uap-core.de>
parents: 65
diff changeset
139 c = fgetc(stream);
5427beba96d1 pgn parser can now handle comments (although it ignores them for now)
Mike Becker <universe@uap-core.de>
parents: 65
diff changeset
140 } while (c != '}' && c != EOF);
5427beba96d1 pgn parser can now handle comments (although it ignores them for now)
Mike Becker <universe@uap-core.de>
parents: 65
diff changeset
141 if (c == EOF) {
5427beba96d1 pgn parser can now handle comments (although it ignores them for now)
Mike Becker <universe@uap-core.de>
parents: 65
diff changeset
142 return pgn_error_missing_brace;
5427beba96d1 pgn parser can now handle comments (although it ignores them for now)
Mike Becker <universe@uap-core.de>
parents: 65
diff changeset
143 }
88
e4a648fe6ce7 fix PGN parser
Mike Becker <universe@uap-core.de>
parents: 82
diff changeset
144 /* skip spaces */
e4a648fe6ce7 fix PGN parser
Mike Becker <universe@uap-core.de>
parents: 82
diff changeset
145 while (isspace(c = fgetc(stream)));
70
5427beba96d1 pgn parser can now handle comments (although it ignores them for now)
Mike Becker <universe@uap-core.de>
parents: 65
diff changeset
146 }
5427beba96d1 pgn parser can now handle comments (although it ignores them for now)
Mike Becker <universe@uap-core.de>
parents: 65
diff changeset
147
64
4eda5df55f86 fixes castling not printed correctly to PGN
Mike Becker <universe@uap-core.de>
parents: 60
diff changeset
148 /* end of game data encountered */
50
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
149 if (c == EOF) {
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
150 break;
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
151 }
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
152 if (c == '1' || c == '0') {
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
153 c = fgetc(stream);
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
154 if (c == '-') {
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
155 gamestate->resign = !gamestate->checkmate;
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
156 break;
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
157 } else if (c == '/') {
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
158 gamestate->remis = !gamestate->stalemate;
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
159 break;
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
160 } else {
64
4eda5df55f86 fixes castling not printed correctly to PGN
Mike Becker <universe@uap-core.de>
parents: 60
diff changeset
161 /* oops, it was a move number, go back! */
50
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
162 fseek(stream, -1, SEEK_CUR);
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
163 }
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
164 }
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
165
64
4eda5df55f86 fixes castling not printed correctly to PGN
Mike Becker <universe@uap-core.de>
parents: 60
diff changeset
166 /* we have eaten the next valuable byte, so go back */
50
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
167 fseek(stream, -1, SEEK_CUR);
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
168
64
4eda5df55f86 fixes castling not printed correctly to PGN
Mike Becker <universe@uap-core.de>
parents: 60
diff changeset
169 /* skip move number after black move */
50
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
170 if (curcol == BLACK) {
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
171 while (isdigit(c = fgetc(stream)));
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
172 if (c != '.') {
60
0c50aac49e55 adds error messages to PGN reader
Mike Becker <universe@uap-core.de>
parents: 59
diff changeset
173 return pgn_error_missing_dot;
50
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
174 }
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
175 }
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
176 curcol = opponent_color(curcol);
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
177 }
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
178
59
3fa1de896666 fixes inappropriate use of EXIT_ macros + adds a sample PGN file
Mike Becker <universe@uap-core.de>
parents: 55
diff changeset
179 return 0;
50
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
180 }
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
181
107
36dd94278142 fix that PGN (with comments) can exceed 80 chars
Mike Becker <universe@uap-core.de>
parents: 106
diff changeset
182 static void pgn_insert_newlines(char *block) {
36dd94278142 fix that PGN (with comments) can exceed 80 chars
Mike Becker <universe@uap-core.de>
parents: 106
diff changeset
183 size_t pos = 0;
36dd94278142 fix that PGN (with comments) can exceed 80 chars
Mike Becker <universe@uap-core.de>
parents: 106
diff changeset
184 size_t last_space_pos = 0;
36dd94278142 fix that PGN (with comments) can exceed 80 chars
Mike Becker <universe@uap-core.de>
parents: 106
diff changeset
185 size_t line_len = 0;
36dd94278142 fix that PGN (with comments) can exceed 80 chars
Mike Becker <universe@uap-core.de>
parents: 106
diff changeset
186 while (block[pos] != '\0') {
118
0f2ffbc408ce prettier line breaking in exported PGNs
Mike Becker <universe@uap-core.de>
parents: 117
diff changeset
187 if (block[pos] == 0x1f) {
0f2ffbc408ce prettier line breaking in exported PGNs
Mike Becker <universe@uap-core.de>
parents: 117
diff changeset
188 block[pos++] = ' ';
0f2ffbc408ce prettier line breaking in exported PGNs
Mike Becker <universe@uap-core.de>
parents: 117
diff changeset
189 continue;
0f2ffbc408ce prettier line breaking in exported PGNs
Mike Becker <universe@uap-core.de>
parents: 117
diff changeset
190 }
107
36dd94278142 fix that PGN (with comments) can exceed 80 chars
Mike Becker <universe@uap-core.de>
parents: 106
diff changeset
191 if (block[pos] == ' ') {
36dd94278142 fix that PGN (with comments) can exceed 80 chars
Mike Becker <universe@uap-core.de>
parents: 106
diff changeset
192 last_space_pos = pos;
36dd94278142 fix that PGN (with comments) can exceed 80 chars
Mike Becker <universe@uap-core.de>
parents: 106
diff changeset
193 }
36dd94278142 fix that PGN (with comments) can exceed 80 chars
Mike Becker <universe@uap-core.de>
parents: 106
diff changeset
194 line_len++;
36dd94278142 fix that PGN (with comments) can exceed 80 chars
Mike Becker <universe@uap-core.de>
parents: 106
diff changeset
195 if (line_len > 80) {
36dd94278142 fix that PGN (with comments) can exceed 80 chars
Mike Becker <universe@uap-core.de>
parents: 106
diff changeset
196 block[last_space_pos] = '\n';
36dd94278142 fix that PGN (with comments) can exceed 80 chars
Mike Becker <universe@uap-core.de>
parents: 106
diff changeset
197 line_len = pos - last_space_pos;
36dd94278142 fix that PGN (with comments) can exceed 80 chars
Mike Becker <universe@uap-core.de>
parents: 106
diff changeset
198 }
36dd94278142 fix that PGN (with comments) can exceed 80 chars
Mike Becker <universe@uap-core.de>
parents: 106
diff changeset
199 pos++;
36dd94278142 fix that PGN (with comments) can exceed 80 chars
Mike Becker <universe@uap-core.de>
parents: 106
diff changeset
200 }
36dd94278142 fix that PGN (with comments) can exceed 80 chars
Mike Becker <universe@uap-core.de>
parents: 106
diff changeset
201 }
36dd94278142 fix that PGN (with comments) can exceed 80 chars
Mike Becker <universe@uap-core.de>
parents: 106
diff changeset
202
117
ee539a9691f0 add prompt whether PGN should be exported with comments
Mike Becker <universe@uap-core.de>
parents: 107
diff changeset
203 void write_pgn(FILE* stream, GameState *gamestate, GameInfo *gameinfo,
ee539a9691f0 add prompt whether PGN should be exported with comments
Mike Becker <universe@uap-core.de>
parents: 107
diff changeset
204 bool export_comments) {
50
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
205 // TODO: tag pairs
102
463c648e6a9b change return type of write_pgn to void
Mike Becker <universe@uap-core.de>
parents: 101
diff changeset
206
64
4eda5df55f86 fixes castling not printed correctly to PGN
Mike Becker <universe@uap-core.de>
parents: 60
diff changeset
207 /* Result */
50
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
208 char *result;
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
209 if (gamestate->stalemate || gamestate->remis) {
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
210 result = "1/2-1/2";
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
211 } else if (gamestate->checkmate || gamestate->resign) {
98
9cb41383540f change move list from linked list to array (prepares game replays)
Mike Becker <universe@uap-core.de>
parents: 88
diff changeset
212 if (gamestate->movecount > 0) {
9cb41383540f change move list from linked list to array (prepares game replays)
Mike Becker <universe@uap-core.de>
parents: 88
diff changeset
213 result = (last_move(gamestate).piece & COLOR_MASK) == WHITE ?
50
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
214 "1-0" : "0-1";
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
215 } else {
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
216 result = "0-1";
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
217 }
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
218 } else {
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
219 result = "*";
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
220 }
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
221 fprintf(stream, "[Result \"%s\"]\n\n", result);
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
222
64
4eda5df55f86 fixes castling not printed correctly to PGN
Mike Becker <universe@uap-core.de>
parents: 60
diff changeset
223 /* moves */
107
36dd94278142 fix that PGN (with comments) can exceed 80 chars
Mike Becker <universe@uap-core.de>
parents: 106
diff changeset
224 size_t moveblkcap = 4096;
36dd94278142 fix that PGN (with comments) can exceed 80 chars
Mike Becker <universe@uap-core.de>
parents: 106
diff changeset
225 char *moveblk = malloc(moveblkcap);
36dd94278142 fix that PGN (with comments) can exceed 80 chars
Mike Becker <universe@uap-core.de>
parents: 106
diff changeset
226 char *moveblkptr = moveblk;
36dd94278142 fix that PGN (with comments) can exceed 80 chars
Mike Becker <universe@uap-core.de>
parents: 106
diff changeset
227 if (moveblk == NULL) {
36dd94278142 fix that PGN (with comments) can exceed 80 chars
Mike Becker <universe@uap-core.de>
parents: 106
diff changeset
228 // TODO: error handling (for the entire function actually)
36dd94278142 fix that PGN (with comments) can exceed 80 chars
Mike Becker <universe@uap-core.de>
parents: 106
diff changeset
229 abort();
36dd94278142 fix that PGN (with comments) can exceed 80 chars
Mike Becker <universe@uap-core.de>
parents: 106
diff changeset
230 }
98
9cb41383540f change move list from linked list to array (prepares game replays)
Mike Becker <universe@uap-core.de>
parents: 88
diff changeset
231 for (unsigned i = 0 ; i < gamestate->movecount ; i++) {
107
36dd94278142 fix that PGN (with comments) can exceed 80 chars
Mike Becker <universe@uap-core.de>
parents: 106
diff changeset
232 /* reallocate move block buffer if needed */
36dd94278142 fix that PGN (with comments) can exceed 80 chars
Mike Becker <universe@uap-core.de>
parents: 106
diff changeset
233 {
36dd94278142 fix that PGN (with comments) can exceed 80 chars
Mike Becker <universe@uap-core.de>
parents: 106
diff changeset
234 size_t moveblksize = moveblkptr - moveblk;
36dd94278142 fix that PGN (with comments) can exceed 80 chars
Mike Becker <universe@uap-core.de>
parents: 106
diff changeset
235 if (moveblksize + 128 < moveblkcap) {
36dd94278142 fix that PGN (with comments) can exceed 80 chars
Mike Becker <universe@uap-core.de>
parents: 106
diff changeset
236 moveblkcap *= 2;
36dd94278142 fix that PGN (with comments) can exceed 80 chars
Mike Becker <universe@uap-core.de>
parents: 106
diff changeset
237 char *newmoveblk = realloc(moveblk, moveblkcap);
36dd94278142 fix that PGN (with comments) can exceed 80 chars
Mike Becker <universe@uap-core.de>
parents: 106
diff changeset
238 if (newmoveblk == NULL) {
36dd94278142 fix that PGN (with comments) can exceed 80 chars
Mike Becker <universe@uap-core.de>
parents: 106
diff changeset
239 free(moveblk);
36dd94278142 fix that PGN (with comments) can exceed 80 chars
Mike Becker <universe@uap-core.de>
parents: 106
diff changeset
240 abort();
36dd94278142 fix that PGN (with comments) can exceed 80 chars
Mike Becker <universe@uap-core.de>
parents: 106
diff changeset
241 }
36dd94278142 fix that PGN (with comments) can exceed 80 chars
Mike Becker <universe@uap-core.de>
parents: 106
diff changeset
242 moveblk = newmoveblk;
36dd94278142 fix that PGN (with comments) can exceed 80 chars
Mike Becker <universe@uap-core.de>
parents: 106
diff changeset
243 moveblkptr = moveblk + moveblksize;
36dd94278142 fix that PGN (with comments) can exceed 80 chars
Mike Becker <universe@uap-core.de>
parents: 106
diff changeset
244 }
36dd94278142 fix that PGN (with comments) can exceed 80 chars
Mike Becker <universe@uap-core.de>
parents: 106
diff changeset
245 }
36dd94278142 fix that PGN (with comments) can exceed 80 chars
Mike Becker <universe@uap-core.de>
parents: 106
diff changeset
246
36dd94278142 fix that PGN (with comments) can exceed 80 chars
Mike Becker <universe@uap-core.de>
parents: 106
diff changeset
247 int snpr; /* return value of printf calls */
36dd94278142 fix that PGN (with comments) can exceed 80 chars
Mike Becker <universe@uap-core.de>
parents: 106
diff changeset
248
98
9cb41383540f change move list from linked list to array (prepares game replays)
Mike Becker <universe@uap-core.de>
parents: 88
diff changeset
249 if (i % 2 == 0) {
118
0f2ffbc408ce prettier line breaking in exported PGNs
Mike Becker <universe@uap-core.de>
parents: 117
diff changeset
250 snpr = snprintf(moveblkptr, 16, "%d.\x1f%s",
107
36dd94278142 fix that PGN (with comments) can exceed 80 chars
Mike Becker <universe@uap-core.de>
parents: 106
diff changeset
251 1+i/2, gamestate->moves[i].string);
50
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
252 } else {
107
36dd94278142 fix that PGN (with comments) can exceed 80 chars
Mike Becker <universe@uap-core.de>
parents: 106
diff changeset
253 snpr = snprintf(moveblkptr, 16, "%s",
36dd94278142 fix that PGN (with comments) can exceed 80 chars
Mike Becker <universe@uap-core.de>
parents: 106
diff changeset
254 gamestate->moves[i].string);
50
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
255 }
107
36dd94278142 fix that PGN (with comments) can exceed 80 chars
Mike Becker <universe@uap-core.de>
parents: 106
diff changeset
256 moveblkptr += snpr;
101
d4f19182fdc2 add clock times to PGN output
Mike Becker <universe@uap-core.de>
parents: 98
diff changeset
257
117
ee539a9691f0 add prompt whether PGN should be exported with comments
Mike Becker <universe@uap-core.de>
parents: 107
diff changeset
258 if (!export_comments) {
ee539a9691f0 add prompt whether PGN should be exported with comments
Mike Becker <universe@uap-core.de>
parents: 107
diff changeset
259 *(moveblkptr++) = ' ';
ee539a9691f0 add prompt whether PGN should be exported with comments
Mike Becker <universe@uap-core.de>
parents: 107
diff changeset
260 continue;
ee539a9691f0 add prompt whether PGN should be exported with comments
Mike Becker <universe@uap-core.de>
parents: 107
diff changeset
261 }
ee539a9691f0 add prompt whether PGN should be exported with comments
Mike Becker <universe@uap-core.de>
parents: 107
diff changeset
262
101
d4f19182fdc2 add clock times to PGN output
Mike Becker <universe@uap-core.de>
parents: 98
diff changeset
263 /* add clock times when the game was under time control */
d4f19182fdc2 add clock times to PGN output
Mike Becker <universe@uap-core.de>
parents: 98
diff changeset
264 if (gameinfo->timecontrol) {
107
36dd94278142 fix that PGN (with comments) can exceed 80 chars
Mike Becker <universe@uap-core.de>
parents: 106
diff changeset
265 memcpy(moveblkptr, " {[%clk ", 8);
36dd94278142 fix that PGN (with comments) can exceed 80 chars
Mike Becker <universe@uap-core.de>
parents: 106
diff changeset
266 moveblkptr += 8;
101
d4f19182fdc2 add clock times to PGN output
Mike Becker <universe@uap-core.de>
parents: 98
diff changeset
267 unsigned clkmv = i + 2; /* time for the next move! */
d4f19182fdc2 add clock times to PGN output
Mike Becker <universe@uap-core.de>
parents: 98
diff changeset
268 uint16_t clk = remaining_movetime2(gameinfo, gamestate, clkmv);
107
36dd94278142 fix that PGN (with comments) can exceed 80 chars
Mike Becker <universe@uap-core.de>
parents: 106
diff changeset
269 snpr = print_clk(clk, moveblkptr, true);
36dd94278142 fix that PGN (with comments) can exceed 80 chars
Mike Becker <universe@uap-core.de>
parents: 106
diff changeset
270 moveblkptr += snpr;
36dd94278142 fix that PGN (with comments) can exceed 80 chars
Mike Becker <universe@uap-core.de>
parents: 106
diff changeset
271 *(moveblkptr++) = ']';
36dd94278142 fix that PGN (with comments) can exceed 80 chars
Mike Becker <universe@uap-core.de>
parents: 106
diff changeset
272 *(moveblkptr++) = '}';
106
bdc9528d3e2b add elapsed move time commands to PGN exports
Mike Becker <universe@uap-core.de>
parents: 102
diff changeset
273
bdc9528d3e2b add elapsed move time commands to PGN exports
Mike Becker <universe@uap-core.de>
parents: 102
diff changeset
274 /* elapsed move time */
107
36dd94278142 fix that PGN (with comments) can exceed 80 chars
Mike Becker <universe@uap-core.de>
parents: 106
diff changeset
275 memcpy(moveblkptr, " {[%emt ", 8);
36dd94278142 fix that PGN (with comments) can exceed 80 chars
Mike Becker <universe@uap-core.de>
parents: 106
diff changeset
276 moveblkptr += 8;
36dd94278142 fix that PGN (with comments) can exceed 80 chars
Mike Becker <universe@uap-core.de>
parents: 106
diff changeset
277 uint16_t emt = gamestate->moves[i].movetime.tv_sec;
36dd94278142 fix that PGN (with comments) can exceed 80 chars
Mike Becker <universe@uap-core.de>
parents: 106
diff changeset
278 snpr = print_clk(emt, moveblkptr, true);
36dd94278142 fix that PGN (with comments) can exceed 80 chars
Mike Becker <universe@uap-core.de>
parents: 106
diff changeset
279 moveblkptr += snpr;
36dd94278142 fix that PGN (with comments) can exceed 80 chars
Mike Becker <universe@uap-core.de>
parents: 106
diff changeset
280 *(moveblkptr++) = ']';
36dd94278142 fix that PGN (with comments) can exceed 80 chars
Mike Becker <universe@uap-core.de>
parents: 106
diff changeset
281 *(moveblkptr++) = '}';
101
d4f19182fdc2 add clock times to PGN output
Mike Becker <universe@uap-core.de>
parents: 98
diff changeset
282 }
50
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
283
107
36dd94278142 fix that PGN (with comments) can exceed 80 chars
Mike Becker <universe@uap-core.de>
parents: 106
diff changeset
284 *(moveblkptr++) = ' ';
50
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
285 }
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
286
107
36dd94278142 fix that PGN (with comments) can exceed 80 chars
Mike Becker <universe@uap-core.de>
parents: 106
diff changeset
287 if (result[0] != '*') {
36dd94278142 fix that PGN (with comments) can exceed 80 chars
Mike Becker <universe@uap-core.de>
parents: 106
diff changeset
288 size_t rlen = strlen(result);
36dd94278142 fix that PGN (with comments) can exceed 80 chars
Mike Becker <universe@uap-core.de>
parents: 106
diff changeset
289 memcpy(moveblkptr, result, rlen);
36dd94278142 fix that PGN (with comments) can exceed 80 chars
Mike Becker <universe@uap-core.de>
parents: 106
diff changeset
290 moveblkptr += rlen;
50
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
291 }
107
36dd94278142 fix that PGN (with comments) can exceed 80 chars
Mike Becker <universe@uap-core.de>
parents: 106
diff changeset
292 *(moveblkptr++) = '\n';
36dd94278142 fix that PGN (with comments) can exceed 80 chars
Mike Becker <universe@uap-core.de>
parents: 106
diff changeset
293 *moveblkptr = 0;
36dd94278142 fix that PGN (with comments) can exceed 80 chars
Mike Becker <universe@uap-core.de>
parents: 106
diff changeset
294
36dd94278142 fix that PGN (with comments) can exceed 80 chars
Mike Becker <universe@uap-core.de>
parents: 106
diff changeset
295 pgn_insert_newlines(moveblk);
36dd94278142 fix that PGN (with comments) can exceed 80 chars
Mike Becker <universe@uap-core.de>
parents: 106
diff changeset
296 fputs(moveblk, stream);
36dd94278142 fix that PGN (with comments) can exceed 80 chars
Mike Becker <universe@uap-core.de>
parents: 106
diff changeset
297
36dd94278142 fix that PGN (with comments) can exceed 80 chars
Mike Becker <universe@uap-core.de>
parents: 106
diff changeset
298 free(moveblk);
50
41017d0a72c5 added pgn parser and writer (without comment support yet) + minor refactorings
Mike Becker <universe@uap-core.de>
parents:
diff changeset
299 }
54
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
300
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
301 static size_t fen_pieces(char *str, GameState *gamestate) {
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
302 size_t i = 0;
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
303 for (int row = 7 ; row >= 0 ; row--) {
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
304 unsigned int skip = 0;
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
305 for (int file = 0 ; file < 8 ; file++) {
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
306 if (gamestate->board[row][file]) {
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
307 if (skip > 0) {
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
308 str[i++] = '0'+skip;
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
309 skip = 0;
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
310 }
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
311 switch (gamestate->board[row][file] & ~ENPASSANT_THREAT) {
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
312 case WHITE|KING: str[i++] = 'K'; break;
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
313 case WHITE|QUEEN: str[i++] = 'Q'; break;
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
314 case WHITE|BISHOP: str[i++] = 'B'; break;
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
315 case WHITE|KNIGHT: str[i++] = 'N'; break;
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
316 case WHITE|ROOK: str[i++] = 'R'; break;
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
317 case WHITE|PAWN: str[i++] = 'P'; break;
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
318 case BLACK|KING: str[i++] = 'k'; break;
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
319 case BLACK|QUEEN: str[i++] = 'q'; break;
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
320 case BLACK|BISHOP: str[i++] = 'b'; break;
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
321 case BLACK|KNIGHT: str[i++] = 'n'; break;
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
322 case BLACK|ROOK: str[i++] = 'r'; break;
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
323 case BLACK|PAWN: str[i++] = 'p'; break;
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
324 }
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
325 } else {
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
326 skip++;
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
327 }
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
328 }
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
329 if (skip > 0) {
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
330 str[i++] = '0'+skip;
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
331 }
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
332 if (row > 0) {
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
333 str[i++] = '/';
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
334 }
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
335 }
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
336
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
337 return i;
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
338 }
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
339
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
340 static size_t fen_color(char *str, GameState *gamestate) {
98
9cb41383540f change move list from linked list to array (prepares game replays)
Mike Becker <universe@uap-core.de>
parents: 88
diff changeset
341 uint8_t color = opponent_color(gamestate->movecount > 0 ?
9cb41383540f change move list from linked list to array (prepares game replays)
Mike Becker <universe@uap-core.de>
parents: 88
diff changeset
342 (last_move(gamestate).piece & COLOR_MASK) : BLACK);
54
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
343
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
344 str[0] = color == WHITE ? 'w' : 'b';
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
345
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
346 return 1;
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
347 }
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
348
80
b980a7192b5a replace _Bool with bool from C23 and/or stdbool.h
Mike Becker <universe@uap-core.de>
parents: 78
diff changeset
349 static bool fen_castling_chkmoved(GameState *gamestate,
54
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
350 uint8_t row, uint8_t file) {
98
9cb41383540f change move list from linked list to array (prepares game replays)
Mike Becker <universe@uap-core.de>
parents: 88
diff changeset
351
9cb41383540f change move list from linked list to array (prepares game replays)
Mike Becker <universe@uap-core.de>
parents: 88
diff changeset
352 for (unsigned i = 0 ; i < gamestate->movecount ; i++) {
9cb41383540f change move list from linked list to array (prepares game replays)
Mike Becker <universe@uap-core.de>
parents: 88
diff changeset
353 if (gamestate->moves[i].fromfile == file
9cb41383540f change move list from linked list to array (prepares game replays)
Mike Becker <universe@uap-core.de>
parents: 88
diff changeset
354 && gamestate->moves[i].fromrow == row) {
80
b980a7192b5a replace _Bool with bool from C23 and/or stdbool.h
Mike Becker <universe@uap-core.de>
parents: 78
diff changeset
355 return true;
54
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
356 }
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
357 }
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
358
80
b980a7192b5a replace _Bool with bool from C23 and/or stdbool.h
Mike Becker <universe@uap-core.de>
parents: 78
diff changeset
359 return false;
54
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
360 }
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
361
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
362 static size_t fen_castling(char *str, GameState *gamestate) {
80
b980a7192b5a replace _Bool with bool from C23 and/or stdbool.h
Mike Becker <universe@uap-core.de>
parents: 78
diff changeset
363 bool K, Q, k, q;
54
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
364
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
365 if (fen_castling_chkmoved(gamestate, rowidx('1'), fileidx('e'))) {
80
b980a7192b5a replace _Bool with bool from C23 and/or stdbool.h
Mike Becker <universe@uap-core.de>
parents: 78
diff changeset
366 K = Q = false;
54
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
367 } else {
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
368 K = !fen_castling_chkmoved(gamestate, rowidx('1'), fileidx('h'));
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
369 Q = !fen_castling_chkmoved(gamestate, rowidx('1'), fileidx('a'));
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
370 }
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
371 if (fen_castling_chkmoved(gamestate, rowidx('8'), fileidx('e'))) {
80
b980a7192b5a replace _Bool with bool from C23 and/or stdbool.h
Mike Becker <universe@uap-core.de>
parents: 78
diff changeset
372 k = q = false;
54
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
373 } else {
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
374 k = !fen_castling_chkmoved(gamestate, rowidx('8'), fileidx('h'));
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
375 q = !fen_castling_chkmoved(gamestate, rowidx('8'), fileidx('a'));
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
376 }
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
377
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
378 size_t i = 0;
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
379 if (K) str[i++] = 'K';
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
380 if (Q) str[i++] = 'Q';
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
381 if (k) str[i++] = 'k';
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
382 if (q) str[i++] = 'q';
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
383 if (!i) str[i++] = '-';
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
384
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
385 return i;
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
386 }
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
387
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
388 static size_t fen_enpassant(char *str, GameState *gamestate) {
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
389
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
390 str[0] = '-'; str[1] = '\0';
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
391
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
392 for (int file = 0 ; file < 8 ; file++) {
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
393 if (gamestate->board[3][file] & ENPASSANT_THREAT) {
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
394 str[0] = filechr(file);
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
395 str[1] = rowchr(2);
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
396 }
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
397 if (gamestate->board[4][file] & ENPASSANT_THREAT) {
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
398 str[0] = filechr(file);
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
399 str[1] = rowchr(5);
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
400 }
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
401 }
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
402
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
403 return str[0] == '-' ? 1 : 2;
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
404 }
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
405
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
406 static size_t fen_halfmove(char *str, GameState *gamestate) {
98
9cb41383540f change move list from linked list to array (prepares game replays)
Mike Becker <universe@uap-core.de>
parents: 88
diff changeset
407 unsigned int hm = 0;
9cb41383540f change move list from linked list to array (prepares game replays)
Mike Becker <universe@uap-core.de>
parents: 88
diff changeset
408 for (unsigned int i = 0; i < gamestate->movecount; i++) {
9cb41383540f change move list from linked list to array (prepares game replays)
Mike Becker <universe@uap-core.de>
parents: 88
diff changeset
409 if (gamestate->moves[i].capture
9cb41383540f change move list from linked list to array (prepares game replays)
Mike Becker <universe@uap-core.de>
parents: 88
diff changeset
410 || (gamestate->moves[i].piece & PIECE_MASK) == PAWN) {
9cb41383540f change move list from linked list to array (prepares game replays)
Mike Becker <universe@uap-core.de>
parents: 88
diff changeset
411 hm = 0;
54
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
412 } else {
98
9cb41383540f change move list from linked list to array (prepares game replays)
Mike Becker <universe@uap-core.de>
parents: 88
diff changeset
413 hm++;
54
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
414 }
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
415 }
98
9cb41383540f change move list from linked list to array (prepares game replays)
Mike Becker <universe@uap-core.de>
parents: 88
diff changeset
416
9cb41383540f change move list from linked list to array (prepares game replays)
Mike Becker <universe@uap-core.de>
parents: 88
diff changeset
417 return sprintf(str, "%u", hm);
54
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
418 }
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
419
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
420 static size_t fen_movenr(char *str, GameState *gamestate) {
98
9cb41383540f change move list from linked list to array (prepares game replays)
Mike Becker <universe@uap-core.de>
parents: 88
diff changeset
421 return sprintf(str, "%u", gamestate->movecount);
54
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
422 }
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
423
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
424 void compute_fen(char *str, GameState *gamestate) {
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
425 str += fen_pieces(str, gamestate);
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
426 *str = ' '; str++;
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
427 str += fen_color(str, gamestate);
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
428 *str = ' '; str++;
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
429 str += fen_castling(str, gamestate);
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
430 *str = ' '; str++;
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
431 str += fen_enpassant(str, gamestate);
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
432 *str = ' '; str++;
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
433 str += fen_halfmove(str, gamestate);
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
434 *str = ' '; str++;
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
435 str += fen_movenr(str, gamestate);
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
436 str[0] = '\0';
eef745ba3774 implemented FEN
Mike Becker <universe@uap-core.de>
parents: 50
diff changeset
437 }

mercurial