Wed, 28 May 2014 15:47:57 +0200
refactoring of getlocation mechanism for better short algebraic notation support (does now respect pinned pieces) + fixed a bug where a pawn could advance through a piece (e.g. e2e4 could jump over a piece on e3)
1 /*
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3 *
4 * Copyright 2014 Mike Becker. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 *
28 */
30 #include "terminal-chess.h"
31 #include "game.h"
32 #include "input.h"
33 #include "colors.h"
34 #include <string.h>
35 #include <time.h>
36 #include <getopt.h>
38 int get_settings(int argc, char **argv, Settings *settings) {
39 char *valid;
40 unsigned long int time, port;
41 uint8_t timeunit = 60;
42 size_t len;
44 for (int opt ; (opt = getopt(argc, argv, "a:bc:hp:rst:")) != -1 ;) {
45 switch (opt) {
46 case 'c':
47 settings->continuepgn = optarg;
48 break;
49 case 'b':
50 settings->gameinfo.servercolor = BLACK;
51 break;
52 case 'r':
53 settings->gameinfo.servercolor = rand() & 1 ? WHITE : BLACK;
54 break;
55 case 's':
56 settings->singlemachine = 1;
57 break;
58 case 't':
59 case 'a':
60 len = strlen(optarg);
61 if (optarg[len-1] == 's') {
62 optarg[len-1] = '\0';
63 timeunit = 1;
64 }
66 if ((time = strtoul(optarg, &valid, 10))*timeunit > UINT16_MAX
67 || *valid != '\0') {
68 fprintf(stderr, "Specified time is invalid (%s)"
69 "- Maximum: 65535 seconds (1092 minutes)\n", optarg);
70 return 1;
71 } else {
72 settings->gameinfo.timecontrol = 1;
73 if (opt=='t') {
74 settings->gameinfo.time = timeunit * time;
75 } else {
76 settings->gameinfo.addtime = time;
77 }
78 }
79 break;
80 case 'p':
81 port = strtol(optarg, &valid, 10);
82 if (port < 1025 || port > 65535 || *valid != '\0') {
83 fprintf(stderr,
84 "Invalid port number (%s) - choose a number between "
85 "1025 and 65535\n",
86 optarg);
87 return 1;
88 } else {
89 settings->port = optarg;
90 }
91 break;
92 case 'h':
93 case '?':
94 settings->printhelp = 1;
95 break;
96 }
97 }
99 if (optind == argc - 1) {
100 settings->serverhost = argv[optind];
101 } else if (optind < argc - 1) {
102 fprintf(stderr, "Too many arguments\n");
103 return 1;
104 }
106 return 0;
107 }
109 Settings default_settings() {
110 Settings settings;
111 memset(&settings, 0, sizeof(Settings));
112 settings.gameinfo.servercolor = WHITE;
113 settings.port = "27015";
114 settings.continuepgn = NULL;
115 return settings;
116 }
118 void dump_gameinfo(GameInfo *gameinfo) {
119 int serverwhite = gameinfo->servercolor == WHITE;
120 attron(A_UNDERLINE);
121 printw("Game details\n");
122 attroff(A_UNDERLINE);
123 printw(" Server: %s\n Client: %s\n",
124 serverwhite?"White":"Black", serverwhite?"Black":"White"
125 );
126 if (gameinfo->timecontrol) {
127 if (gameinfo->time % 60) {
128 printw(" Time limit: %ds + %ds\n",
129 gameinfo->time, gameinfo->addtime);
130 } else {
131 printw(" Time limit: %dm + %ds\n",
132 gameinfo->time/60, gameinfo->addtime);
133 }
134 } else {
135 printw(" No time limit\n");
136 }
137 refresh();
138 }
140 void leavescr() {
141 endwin();
142 }
144 int main(int argc, char **argv) {
145 srand(time(NULL));
147 Settings settings = default_settings();
148 if (get_settings(argc, argv, &settings)) {
149 return 1;
150 }
152 if (settings.printhelp) {
153 printf(
154 "Usage: terminal-chess [OPTION]... [HOST]\n"
155 "Starts/joins a network chess game\n"
156 "\nGeneral options\n"
157 " -h This help page\n"
158 " -p TCP port to use (default: 27015)\n"
159 "\nServer options\n"
160 " -a <time> Specifies the time to add after each move\n"
161 " -b Server plays black pieces (default: white)\n"
162 // TODO: implement and activate feature
163 //" -c <PGN file> Continue the specified game\n"
164 " -r Distribute color randomly\n"
165 " -s Single machine mode\n"
166 // TODO: implement and activate feature
167 //" -S <PGN file> Compute and print statistics for the specified game\n"
168 " -t <time> Specifies time limit (default: no limit)\n"
169 "\nNotes\n"
170 "The time unit for -a is seconds and for -t minutes by default. To "
171 "specify\nseconds for the -t option, use the s suffix.\n"
172 "Example: -t 150s\n\n"
173 "Use '-' for PGN files to read PGN data from standard input\n"
174 );
175 return EXIT_SUCCESS;
176 }
177 initscr();
178 halfdelay(1);
179 keypad(stdscr, TRUE);
180 if (has_colors()) {
181 start_color();
182 init_colorpairs();
183 bkgd(COLOR_PAIR(COL_APP));
184 } else {
185 fprintf(stderr, "Non-colored terminals are not supported yet.");
186 endwin();
187 return EXIT_FAILURE;
188 }
189 atexit(leavescr);
191 int exitcode;
192 if (settings.singlemachine) {
193 game_start_singlemachine(&settings);
194 exitcode = EXIT_SUCCESS;
195 } else {
196 exitcode = is_server(&settings) ?
197 server_run(&settings) : client_run(&settings);
198 }
200 mvaddstr(getmaxy(stdscr)-1, 0,
201 "Game has ended. Press any key to leave...");
202 refresh();
203 cbreak();
204 flushinp();
205 getch();
207 return exitcode;
208 }