Projects/khet
Projects
/
khet
Archived
6
0
Fork 0

more than two clients at the same time

This commit is contained in:
Øystein Ingmar Skartsæterhagen 2008-10-11 15:30:33 +00:00
parent 9a73ba8e77
commit eed9669db9
2 changed files with 296 additions and 119 deletions

View File

@ -4,98 +4,112 @@
#include <stdlib.h> #include <stdlib.h>
#include <assert.h> #include <assert.h>
#include <string.h> #include <string.h>
#include <ctype.h>
#include "server.h"
#include "net.h" #include "net.h"
#include "game.h" #include "game.h"
#include "asciiart.h" #include "asciiart.h"
#define MAX_MSG_LEN 50 typedef struct {
/* int players[2];
typedef enum { MSG_MOVE, MSG_ROTATE } message_type_t; game_t game;
} server_game_t;
server_game_t *server_games[MAX_GAMES];
int server_games_sz;
typedef struct { typedef struct {
message_type_t type; int connected;
union { char name[10];
struct { int game;
int row, col; int requested_game, requested_game_with;
dir_t dir; } server_client_t;
} move;
struct { server_client_t server_clients[MAX_CLIENTS];
int row, col;
rot_t dir; typedef int cmdfunc_t(int client, char **args);
} rotate; typedef struct {
} args; char *name;
} message_t; char *desc;
int argc;
cmdfunc_t *func;
} server_cmd_t;
int server_do_command(int clientid, char *cmd);
int int
read_message(int side, message_t *m) server_new_game(int silver, int red)
{
if (server_games_sz == MAX_GAMES)
return -1;
int game_id = server_games_sz++;
server_game_t *g = malloc(sizeof(server_game_t));
g->players[SILVER] = silver;
g->players[RED] = red;
server_clients[silver].game = game_id;
server_clients[red].game = game_id;
server_clients[silver].requested_game = 0;
server_clients[red].requested_game = 0;
init_game(&g->game);
setup_board(&g->game, classic_setup);
server_games[game_id] = g;
return game_id;
}
void
server_delete_game(int id)
{ {
char buf[MAX_MSG_LEN+1];
char c;
int i; int i;
for (i = 0; i < MAX_MSG_LEN+1; i++) { assert(id >= 0 && id < MAX_GAMES && server_games[id] != NULL);
c = net_getc(side); free(server_games[id]);
printf("input '%c'\n", c); server_games[id] = NULL;
if (c == '\n') for (i = id+1; i < server_games_sz; i++)
break; server_games[i-1] = server_games[i];
buf[i] = c; server_games_sz--;
}
buf[i] = '\0';
while (c != '\n') c = net_getc(side);
switch (buf[0]) {
case 'M': m->type = MSG_MOVE; break;
case 'R': m->type = MSG_ROTATE; break;
default: return E_UNKNOWN_COMMAND;
}
if (m->type == MSG_MOVE) {
m->args.move.row = buf[2]-'A';
m->args.move.col = buf[3]-'0';
switch (buf[5]) {
case 'N':
m->args.move.dir = (buf[6]=='W' ? D_NW : (buf[6]=='E' ? D_NE : D_N));
break;
case 'S':
m->args.move.dir = (buf[6]=='W' ? D_SW : (buf[6]=='E' ? D_SE : D_S));
break;
case 'E':
m->args.move.dir = D_E;
break;
case 'W':
m->args.move.dir = D_W;
break;
}
net_all_printf("msg: MOVE (%d,%d) %d\n", m->args.move.row, m->args.move.col,
m->args.move.dir);
} else if (m->type == MSG_ROTATE) {
m->args.rotate.row = buf[2]-'A';
m->args.rotate.col = buf[3]-'0';
m->args.rotate.dir = (buf[5]=='L' ? R_CCW : R_CW);
}
return HUGE_SUCCESS;
} }
int int
execute_message(game_t *game, message_t msg, int side) server_get_game_request(int client)
{ {
switch (msg.type) { int i;
case MSG_MOVE: server_client_t *c = server_clients;
return move(game, side, for (i = 0; i < MAX_CLIENTS; i++) {
msg.args.move.row, msg.args.move.col, if (c[i].connected &&
msg.args.move.dir, 0); c[i].requested_game &&
case MSG_ROTATE: (c[i].requested_game_with == client ||
return rotate(game, side, c[i].requested_game_with == -1))
msg.args.rotate.row, msg.args.rotate.col, return i;
msg.args.rotate.dir); }
default: return -1;
net_side_printf(side, "unknown command type %d\n", msg.type); }
return E_UNKNOWN_COMMAND;
int
server_request_game(int client, int opponent)
{
int match = 0;
if (server_clients[client].requested_game)
return -1;
if (opponent == -1) {
opponent = server_get_game_request(client);
if (opponent != -1) match = 1;
} else {
match =
server_clients[opponent].requested_game &&
(server_clients[opponent].requested_game_with == client ||
server_clients[opponent].requested_game_with == -1);
}
if (match) {
server_clients[opponent].requested_game = 0;
return server_new_game(client, opponent);
} else {
server_clients[client].requested_game = 1;
server_clients[client].requested_game_with = opponent;
return -1;
} }
} }
*/
void void
terminal_game(void) terminal_game(void)
@ -111,7 +125,7 @@ terminal_game(void)
printf("%s", aabuf); printf("%s", aabuf);
for (;;) { for (;;) {
printf("%s's move\n", sideinfo[game_turn(&game)].name); printf("move %d, %s\n", game.move, sideinfo[game_turn(&game)].name);
fgets(linebuf, 10, stdin); fgets(linebuf, 10, stdin);
if (parse_move(linebuf, &move) != HUGE_SUCCESS) { if (parse_move(linebuf, &move) != HUGE_SUCCESS) {
printf("not a valid move description: '%s'\n", linebuf); printf("not a valid move description: '%s'\n", linebuf);
@ -122,6 +136,9 @@ terminal_game(void)
continue; continue;
} }
asciiart_small_draw_board(aabuf, &game);
printf("%s", aabuf);
if (game.last_move.type == M_ROTATE) { if (game.last_move.type == M_ROTATE) {
printf("move: %c%c rotated %s\n", printf("move: %c%c rotated %s\n",
game.last_move.y+'A', game.last_move.y+'A',
@ -146,9 +163,6 @@ terminal_game(void)
game.laser_pos[1]+'A', game.laser_pos[0]+'0'); game.laser_pos[1]+'A', game.laser_pos[0]+'0');
} }
asciiart_small_draw_board(aabuf, &game);
printf("%s", aabuf);
switch (game.winner) { switch (game.winner) {
case SILVER: case SILVER:
printf("SILVER WINS!\n"); printf("SILVER WINS!\n");
@ -162,64 +176,109 @@ terminal_game(void)
} }
game_t game; void
server_report_game_state(int gameid)
{
server_game_t *g = server_games[gameid];
int i;
for (i = 0; i < 2; i++) {
int c = g->players[i];
if (g->game.last_move.type == M_ROTATE) {
net_client_printf(c, "move: %c%c rotated %s\n",
g->game.last_move.y+'A',
g->game.last_move.x+'0',
g->game.last_move.dir==R_CW ? "R" : "L");
} else {
int nx, ny;
move_dest(g->game.last_move, &nx, &ny);
net_client_printf(c, "move: %c%c moved to %c%c\n",
g->game.last_move.y+'A',
g->game.last_move.x+'0',
ny+'A', nx+'0');
}
if (g->game.last_hit.piece != NONE) {
net_client_printf(c, "laser hits %s %s at %c%c\n",
sideinfo[g->game.last_hit.side].name,
pieceinfo[g->game.last_hit.piece].name,
g->game.laser_pos[1]+'A', g->game.laser_pos[0]+'0');
} else {
net_client_printf(c, "laser hits wall at %c%c\n",
g->game.laser_pos[1]+'A', g->game.laser_pos[0]+'0');
}
char aabuf[ASCIIART_SMALL_BUFSZ];
asciiart_small_draw_board(aabuf, &g->game);
net_client_printf(c, "%s", aabuf);
switch (g->game.winner) {
case SILVER:
net_client_printf(c, "SILVER WINS!\n");
break;
case RED:
net_client_printf(c, "RED WINS!\n");
break;
default:
if (g->players[game_turn(&g->game)]==c)
net_client_printf(c, "your turn\n");
}
}
}
void void
parse_line(int clientid, char *line) { server_do_move(int clientid, move_t move)
move_t move; {
if (parse_move(line, &move) != HUGE_SUCCESS) { int gameid = server_clients[clientid].game;
net_client_printf(clientid, "not a valid move description: '%s'\n", line); server_game_t *g = server_games[gameid];
int side;
side = (g->players[1]==clientid);
switch (perform_move(&g->game, side, move)) {
case HUGE_SUCCESS:
break;
case E_NOT_YOUR_TURN:
net_client_printf(clientid, "not your turn\n");
return; return;
} default:
if (perform_move(&game, clientid, move) != HUGE_SUCCESS) {
net_client_printf(clientid, "invalid move\n"); net_client_printf(clientid, "invalid move\n");
return; return;
} }
server_report_game_state(gameid);
if (game.last_move.type == M_ROTATE) { switch (g->game.winner) {
net_all_printf("move: %c%c rotated %s\n",
game.last_move.y+'A',
game.last_move.x+'0',
game.last_move.dir==R_CW ? "R" : "L");
} else {
int nx, ny;
move_dest(game.last_move, &nx, &ny);
net_all_printf("move: %c%c moved to %c%c\n",
game.last_move.y+'A',
game.last_move.x+'0',
ny+'A', nx+'0');
}
if (game.last_hit.piece != NONE) {
net_all_printf("laser hits %s %s at %c%c\n",
sideinfo[game.last_hit.side].name,
pieceinfo[game.last_hit.piece].name,
game.laser_pos[1]+'A', game.laser_pos[0]+'0');
} else {
net_all_printf("laser hits wall at %c%c\n",
game.laser_pos[1]+'A', game.laser_pos[0]+'0');
}
char aabuf[ASCIIART_SMALL_BUFSZ];
asciiart_small_draw_board(aabuf, &game);
net_all_printf("%s", aabuf);
switch (game.winner) {
case SILVER: case SILVER:
net_all_printf("SILVER WINS!\n"); server_delete_game(gameid);
exit(0); break;
case RED: case RED:
net_all_printf("RED WINS!\n"); server_delete_game(server_clients[clientid].game);
exit(0); break;
} }
} }
void
parse_line(int clientid, char *line)
{
server_do_command(clientid, line);
}
int player[2]={0, 0}; int player[2]={0, 0};
void void
server_client_connect(int clientid) { server_client_connect(int clientid) {
server_client_t *c = &server_clients[clientid];
c->connected = 1;
sprintf(c->name, "client%03d", clientid);
c->game = -1;
c->requested_game = 0;
net_client_printf(clientid, "Welcome to the KHET server\n");
net_client_printf(clientid, "Say 'play' to play a game\n");
net_client_printf(clientid, "(you may have to wait for another player)\n");
/*
assert(clientid<2); assert(clientid<2);
player[clientid]=1; player[clientid]=1;
if (player[0] && player[1]) { if (player[0] && player[1]) {
@ -229,9 +288,122 @@ server_client_connect(int clientid) {
asciiart_small_draw_board(aabuf, &game); asciiart_small_draw_board(aabuf, &game);
net_all_printf("%s", aabuf); net_all_printf("%s", aabuf);
} }
*/
} }
void
server_init(void)
{
int i;
server_games_sz = 0;
for (i = 0; i < MAX_CLIENTS; i++)
server_clients[i].connected = 0;
}
int
server_cmd_play(int client, char **args)
{
int g = server_request_game(client, -1);
if (g == -1) {
net_client_printf(client, "requested game with anyone\n");
} else {
server_report_game_state(g);
}
return 1;
}
int
server_cmd_playwith(int client, char **args)
{
net_client_printf(client, "sorry, this is not implemented yet\n");
return 1;
}
int
server_cmd_nick(int client, char **args)
{
net_client_printf(client, "sorry, this is not implemented yet\n");
return 1;
}
int
server_cmd_ls(int client, char **args)
{
net_client_printf(client, "sorry, this is not implemented yet\n");
return 1;
}
server_cmd_t server_commands[] = {
{ .name = "PLAY",
.desc = "play a game with anyone",
.argc = 0,
.func = server_cmd_play },
{ .name = "PLAYWITH",
.desc = "play a game with a named opponent",
.argc = 1,
.func = server_cmd_playwith },
{ .name = "NICK",
.desc = "set your nickname",
.argc = 1,
.func = server_cmd_nick },
{ .name = "LS",
.desc = "list stuff",
.argc = 1,
.func = server_cmd_ls } };
int server_commands_sz = 4;
int
server_do_command(int clientid, char *cmd)
{
char *cmd_copy = strdup(cmd);
server_cmd_t *cmd_type = NULL;
char *args[10];
int argc;
char *c;
move_t move;
int i;
for (i = 0; i < strlen(cmd_copy); i++) {
cmd_copy[i] = toupper(cmd_copy[i]);
}
if (server_clients[clientid].game != -1 &&
parse_move(cmd_copy, &move) == HUGE_SUCCESS) {
server_do_move(clientid, move);
return 1;
}
for (argc = 0, c = cmd_copy; ; argc++) {
while (*c != ' ' && *c != '\n' && *c != '\0')
c++;
if (*c == ' ' || *c == '\n') *(c++) = '\0';
while (*c == ' ' || *c == '\n')
c++;
if (*c == '\n' || *c == '\0')
break;
args[argc] = c;
}
for (i = 0; i < server_commands_sz; i++) {
if (strcmp(cmd_copy, server_commands[i].name)==0)
cmd_type = &server_commands[i];
}
if (cmd_type == NULL) {
net_client_printf(clientid, "unknown command %s\n", cmd_copy);
return 0;
}
if (argc != cmd_type->argc) {
net_client_printf(clientid,
"wrong number of arguments for %s (wanted %d, got %d)\n",
cmd_type->name, cmd_type->argc, argc);
return 0;
}
return cmd_type->func(clientid, args);
}
int int
main(int argc, char **argv) { main(int argc, char **argv) {

View File

@ -1,4 +1,9 @@
#ifndef KHET_SERVER_H
#define KHET_SERVER_H
#define MAX_GAMES 10
void server_client_connect(int clientid); void server_client_connect(int clientid);
void parse_line(int clientid, char *line); void parse_line(int clientid, char *line);
#endif