27 * |
27 * |
28 */ |
28 */ |
29 |
29 |
30 #include "terminal-chess.h" |
30 #include "terminal-chess.h" |
31 #include <string.h> |
31 #include <string.h> |
|
32 #include <time.h> |
32 |
33 |
33 int get_settings(int argc, char **argv, Settings *settings) { |
34 int get_settings(int argc, char **argv, Settings *settings) { |
34 char *valid; |
35 char *valid; |
35 |
36 unsigned long int time, port; |
36 for (char opt ; (opt = getopt(argc, argv, "hp:")) != -1 ;) { |
37 uint8_t timeunit = 60; |
|
38 size_t len; |
|
39 |
|
40 for (char opt ; (opt = getopt(argc, argv, "a:bhp:rt:")) != -1 ;) { |
37 switch (opt) { |
41 switch (opt) { |
38 case 'p': |
42 case 'b': |
39 if (strtol(optarg, &valid, 10) < 1025 || *valid != '\0') { |
43 settings->gameinfo.servercolor = BLACK; |
40 fprintf(stderr, |
44 break; |
41 "Invalid port number (%s) - choose a number > 1024\n", |
45 case 'r': |
42 optarg); |
46 settings->gameinfo.servercolor = (rand()>>5) & 1 ? WHITE : BLACK; |
43 return 1; |
47 break; |
|
48 case 't': |
|
49 case 'a': |
|
50 len = strlen(optarg); |
|
51 if (optarg[len-1] == 's') { |
|
52 optarg[len-1] = '\0'; |
|
53 timeunit = 1; |
|
54 } |
|
55 |
|
56 if ((time = strtoul(optarg, &valid, 10)) > TIME_MAX |
|
57 || *valid != '\0') { |
|
58 fprintf(stderr, "Specified time is invalid (%s)\n", optarg); |
|
59 return 1; |
|
60 } else { |
|
61 if (opt=='t') { |
|
62 settings->gameinfo.time = timeunit * time; |
44 } else { |
63 } else { |
45 settings->port = optarg; |
64 settings->gameinfo.addtime = time; |
46 } |
65 } |
47 break; |
66 } |
48 case 'h': |
67 break; |
49 case '?': |
68 case 'p': |
50 settings->printhelp = 1; |
69 port = strtol(optarg, &valid, 10); |
51 break; |
70 if (port < 1025 || port > 65535 || *valid != '\0') { |
|
71 fprintf(stderr, |
|
72 "Invalid port number (%s) - choose a number between " |
|
73 "1025 and 65535\n", |
|
74 optarg); |
|
75 return 1; |
|
76 } else { |
|
77 settings->port = optarg; |
|
78 } |
|
79 break; |
|
80 case 'h': |
|
81 case '?': |
|
82 settings->printhelp = 1; |
|
83 break; |
52 } |
84 } |
53 } |
85 } |
54 |
86 |
55 if (optind == argc - 1) { |
87 if (optind == argc - 1) { |
56 settings->serverhost = argv[optind]; |
88 settings->serverhost = argv[optind]; |
63 } |
95 } |
64 |
96 |
65 Settings default_settings() { |
97 Settings default_settings() { |
66 Settings settings; |
98 Settings settings; |
67 memset(&settings, 0, sizeof(Settings)); |
99 memset(&settings, 0, sizeof(Settings)); |
|
100 settings.gameinfo.servercolor = WHITE; |
68 settings.port = "27015"; |
101 settings.port = "27015"; |
69 return settings; |
102 return settings; |
|
103 } |
|
104 |
|
105 void dump_gameinfo(Gameinfo *gameinfo) { |
|
106 int serverwhite = gameinfo->servercolor == WHITE; |
|
107 printf( |
|
108 "Game details:\n" |
|
109 " Server plays %s - Client plays %s\n", |
|
110 serverwhite?"white":"black", serverwhite?"black":"White" |
|
111 ); |
|
112 if (gameinfo->time > 0) { |
|
113 if (gameinfo->time % 60) { |
|
114 printf(" Time limit: %ds + %ds\n", |
|
115 gameinfo->time, gameinfo->addtime); |
|
116 } else { |
|
117 printf(" Time limit: %dm + %ds\n", |
|
118 gameinfo->time/60, gameinfo->addtime); |
|
119 } |
|
120 } else { |
|
121 printf(" No time limit\n"); |
|
122 } |
70 } |
123 } |
71 |
124 |
72 int cleanup(Settings *settings, int exitcode) { |
125 int cleanup(Settings *settings, int exitcode) { |
73 if (settings->server) { |
126 if (settings->server) { |
74 if (net_destroy(settings->server)) { |
127 if (net_destroy(settings->server)) { |
78 |
131 |
79 return exitcode; |
132 return exitcode; |
80 } |
133 } |
81 |
134 |
82 int main(int argc, char **argv) { |
135 int main(int argc, char **argv) { |
|
136 srand(time(NULL)); |
83 |
137 |
84 Settings settings = default_settings(); |
138 Settings settings = default_settings(); |
85 get_settings(argc, argv, &settings); |
139 if (get_settings(argc, argv, &settings)) { |
|
140 return 1; |
|
141 } |
86 |
142 |
87 if (settings.printhelp) { |
143 if (settings.printhelp) { |
88 printf( |
144 printf( |
89 "Usage: %s [OPTION]... [HOST]\n" |
145 "Usage: terminal-chess [OPTION]... [HOST]\n" |
90 "Starts/joins a network chess game\n\n" |
146 "Starts/joins a network chess game\n" |
|
147 "\nGeneral options\n" |
91 " -h This help page\n" |
148 " -h This help page\n" |
92 " -p TCP port to use (default: 27015)\n", |
149 " -p TCP port to use (default: 27015)\n" |
93 argv[0]); |
150 "\nServer options\n" |
|
151 " -a <time> Specifies the time to add after each move\n" |
|
152 " -b Server plays black pieces (default: white)\n" |
|
153 " -r Distribute color randomly\n" |
|
154 " -t <time> Specifies time limit (default: no limit)\n" |
|
155 "\nNotes\n" |
|
156 "White pieces are displayed as uppercase and black pieces as " |
|
157 "lowercase letters.\n" |
|
158 "The time unit for -a is seconds and for -t minutes by default. To " |
|
159 "specify\nseconds for the -t option, use the s suffix.\n" |
|
160 "Example: -t 150s\n" |
|
161 ); |
94 return EXIT_SUCCESS; |
162 return EXIT_SUCCESS; |
95 } |
163 } |
96 |
164 |
97 Server server; |
165 Server server; |
98 settings.server = &server; |
166 settings.server = &server; |
99 |
167 |
100 if (is_server(&settings)) { |
168 if (is_server(&settings)) { |
|
169 dump_gameinfo(&(settings.gameinfo)); |
|
170 printf("\nListening for client...\n"); |
|
171 if (net_create(&server, settings.port)) { |
|
172 perror("Server creation failed"); |
|
173 return cleanup(&settings, EXIT_FAILURE); |
|
174 } |
|
175 |
|
176 if (net_listen(&server)) { |
|
177 perror("Listening for client failed"); |
|
178 return cleanup(&settings, EXIT_FAILURE); |
|
179 } |
|
180 |
|
181 printf("Client connected - transmitting gameinfo...\n"); |
|
182 net_send(server.client->fd, NETCODE_GAMEINFO, |
|
183 &(settings.gameinfo), sizeof(settings.gameinfo)); |
|
184 } else { |
101 if (net_find(&server, settings.serverhost, settings.port)) { |
185 if (net_find(&server, settings.serverhost, settings.port)) { |
102 perror("Can't find server"); |
186 perror("Can't find server"); |
103 return cleanup(&settings, EXIT_FAILURE); |
187 return cleanup(&settings, EXIT_FAILURE); |
104 } |
188 } |
105 |
189 |
106 if (net_connect(&server)) { |
190 if (net_connect(&server)) { |
107 perror("Can't connect to server"); |
191 perror("Can't connect to server"); |
108 return cleanup(&settings, EXIT_FAILURE); |
192 return cleanup(&settings, EXIT_FAILURE); |
109 } |
193 } |
110 } else { |
194 |
111 if (net_create(&server, settings.port)) { |
195 printf("Connection established!\n\n"); |
112 perror("Server creation failed"); |
196 if (net_recieve_code(server.fd) == NETCODE_GAMEINFO) { |
113 return cleanup(&settings, EXIT_FAILURE); |
197 net_recieve_data(server.fd, &(settings.gameinfo), |
114 } |
198 sizeof(settings.gameinfo)); |
115 |
199 dump_gameinfo(&(settings.gameinfo)); |
116 if (net_listen(&server)) { |
200 } else { |
117 perror("Listening for client failed"); |
201 fprintf(stderr, "Server sent invalid gameinfo.\n"); |
118 return cleanup(&settings, EXIT_FAILURE); |
|
119 } |
202 } |
120 } |
203 } |
121 |
204 |
122 return cleanup(&settings, EXIT_SUCCESS); |
205 return cleanup(&settings, EXIT_SUCCESS); |
123 } |
206 } |