diff --git a/src/server.c b/src/server.c index e6cf151..e0e1911 100644 --- a/src/server.c +++ b/src/server.c @@ -2,6 +2,8 @@ #include #include +#include +#include #define NONE 0 #define PHARAO 1 @@ -12,12 +14,44 @@ #define N_PIECE_TYPES 6 +#define SILVER 0 +#define RED 1 + #define F_ROTATE 1 #define F_SPLIT 2 #define BOARD_WIDTH 10 #define BOARD_HEIGHT 8 +#define E_ILLEGAL_MOVE -1 +#define E_UNKNOWN_COMMAND -2 +#define HUGE_SUCCESS 1 + +// return values for laser(): +#define L_WALL 0 +#define L_PIECE 1 +#define SILVER_WINS 2 +#define RED_WINS 3 + +#define MAX_MSG_LEN 50 +typedef enum { MSG_MOVE, MSG_ROTATE } move_t; +typedef enum { R_CW, R_CCW } rot_t; +typedef enum { D_NW=0, D_N, D_NE, D_E, D_SE, D_S, D_SW, D_W } dir_t; + +typedef struct { + move_t type; + union { + struct { + int row, col; + dir_t dir; + } move; + struct { + int row, col; + rot_t dir; + } rotate; + } args; +} message_t; + struct pieceinfo { int num; } pieceinfo[] = { @@ -41,11 +75,19 @@ struct square { unsigned int dir : 2; } board[BOARD_WIDTH][BOARD_HEIGHT]; +int laser_pos[2]; + +struct sideinfo { + char ch; + char *name; +} sideinfo[] = { + { .ch = 'o', .name = "silver" }, + { .ch = 'x', .name = "red" } }; char classic_setup[] = "H40" // PHARAO "E40E51" // DJHED - "H20G71E20D23E93D90C30" // PYRAMID + "H22G73E22D21E91D92C32" // PYRAMID "H30H30H50H50" // OBELISK ; @@ -54,12 +96,13 @@ char asciiart_small_pieces[] = " " // NONE "OOOOOOOOXXXXXXXX" // PHARAO ".''..''..**..**." // DJHED - "/oo\\o/\\o/xx\\x/\\x" // PYRAMID + "o/\\o/oo\\x/\\x/xx\\" // PYRAMID "o o o o x x x x " // OBELISK "ooooooooxxxxxxxx" // OBELISK2 ; -void print_piece_small(int piece, int side, int dir) +void +print_piece_small(int piece, int side, int dir) { int index = (piece*4*2 + side*4 + dir) * 2; printf("%c%c", @@ -67,136 +110,207 @@ void print_piece_small(int piece, int side, int dir) asciiart_small_pieces[index+1]); } -void print_board_small() +int +laser_at(int x, int y) { - int i, j; - - char vline, hline, xline; - vline = '|', hline = '-', xline = '+'; - - printf(" %c", vline); - for (j = 0; j < BOARD_WIDTH; j++) - printf(" %d%c", j, vline); - printf("\n"); - for (j = 0; j < BOARD_WIDTH+1; j++) - printf("%c%c%c", hline, hline, xline); - printf("\n"); - - for (i = 0; i < BOARD_HEIGHT; i++) { - printf(" %c%c", 'A'+i, vline); - for (j = 0; j < BOARD_WIDTH; j++) { - print_piece_small(board[j][i].piece, - board[j][i].side, - board[j][i].dir); - printf("%c", vline); - } - printf("\n"); - for (j = 0; j < BOARD_WIDTH+1; j++) - printf("%c%c%c", hline, hline, xline); - printf("\n"); - } + return laser_pos[0] == x && laser_pos[1] == y; } +void +print_board_small() +{ + int x, y; + + char vline, hline, xline, lline; + char dead_piece[] = "##"; + vline = '|', hline = '-', xline = '+'; + lline = '#'; + + printf("%s(%c)\n", sideinfo[RED].name, sideinfo[RED].ch); + + // column numbers + printf(" %c", vline); + for (x = 0; x < BOARD_WIDTH; x++) { + printf(" %d%c", x, vline); + } + printf("\n"); + + // line + printf("%c%c%c", hline, hline, xline); + for (x = 0; x < BOARD_WIDTH; x++) + printf("%c%c%c", + laser_at(x, -1) ? lline : hline, + laser_at(x, -1) ? lline : hline, + xline); + printf("%c%c\n", hline, hline); + + for (y = 0; y < BOARD_HEIGHT; y++) { + // row name + printf(" %c%c", 'A'+y, laser_at(-1,y) ? lline : vline); + // row + for (x = 0; x < BOARD_WIDTH; x++) { + if (laser_at(x, y)) + printf("%s", dead_piece); + else + print_piece_small(board[x][y].piece, + board[x][y].side, + board[x][y].dir); + printf("%c", (x==BOARD_WIDTH-1 && laser_at(x+1, y)) ? lline : vline); + } + // row name + printf("%c\n", 'A'+y); + + // line + printf("%c%c%c", hline, hline, xline); + for (x = 0; x < BOARD_WIDTH; x++) + printf("%c%c%c", + (y==BOARD_HEIGHT-1 && laser_at(x, y+1)) ? lline : hline, + (y==BOARD_HEIGHT-1 && laser_at(x, y+1)) ? lline : hline, + xline); + printf("%c%c\n", hline, hline); + } + + // column numbers + printf(" %c", vline); + for (x = 0; x < BOARD_WIDTH; x++) + printf(" %d%c", x, vline); + printf("\n"); + + for (x = 0; x < (BOARD_WIDTH+2)*3-1-strlen(sideinfo[SILVER].name)-3; x++) + printf(" "); + printf("%s(%c)\n", sideinfo[SILVER].name, sideinfo[SILVER].ch); +} + + int laser(int side) { +#define lreturn(v) do { retval=(v); goto ret; } while (0); int x, y, dir; int ddir; + int retval; + + /* + dir: + 0 + 3 X 1 + 2 + */ + + printf("LASER (%s)\n", sideinfo[side].name); + + assert(side == 0 || side == 1); switch (side) { case 0: - x=9; y=0; dir=0; + x=9; y=7; dir=0; break; case 1: - x=0; y=7; dir=2; + x=0; y=0; dir=2; break; - default: - return 0; } for (;;) { + printf("pos: (%d,%d)\n", y, x); switch (board[x][y].piece) { case NONE: break; case PHARAO: - return 2 + board[x][y].side; /* GAME OVER */ + lreturn(SILVER_WINS + 1-board[x][y].side); /* GAME OVER */ case OBELISK2: board[x][y].piece = OBELISK; - return 1; + lreturn(L_PIECE); case OBELISK: board[x][y].piece = NONE; - return 1; + lreturn(L_PIECE); case DJHED: - ddir = board[x][y].dir - dir; + ddir = (board[x][y].dir - dir) & 3; dir=(dir + 1 - 2*(ddir & 1)) & 3; break; case PYRAMID: - ddir = board[x][y].dir - dir; + ddir = (board[x][y].dir - dir) & 3; if (ddir & 2) { board[x][y].piece = NONE; - return 1; + lreturn(L_PIECE); } dir=(dir + 1 - 2*(ddir & 1)) & 3; break; } switch (dir & 3) { - case 0: y++; if (y>7) return 0; break; - case 1: x++; if (x>9) return 0; break; - case 2: y--; if (y<0) return 0; break; - case 3: x--; if (x<0) return 0; break; + case 0: y--; if (y<0) lreturn(L_WALL); break; + case 1: x++; if (x>BOARD_WIDTH-1) lreturn(L_WALL); break; + case 2: y++; if (y>BOARD_HEIGHT-1) lreturn(L_WALL); break; + case 3: x--; if (x<0) lreturn(L_WALL); break; } } + +ret: + laser_pos[0] = x; + laser_pos[1] = y; + return retval; } int -move(int side, int x, int y, int dir, int flags) { - if ((x<0) || (x>9) || (y<0) || (y>7)) - return 0; - if (!board[x][y].piece) - return 0; - if ((board[x][y].side != side)) - return 0; +movable(int row, int col, int side) +{ + return + row>=0 && row=0 && col7)) - return 0; - int ny = y - (dir<3) + ((dir>3) && (dir<7)); - int nx = x + ((dir>1) && (dir<5)) - ((dir<1) || (dir>5)); - if ((nx<0) || (nx>9) || (ny<0) || (ny>7)) - return 0; + assert((dir>=0) || (dir<=7)); + int nrow = row - (dir<3) + ((dir>3) && (dir<7)); + int ncol = col + ((dir>1) && (dir<5)) - ((dir<1) || (dir>5)); + if ((ncol<0) || (ncol>9) || (nrow<0) || (nrow>7)) + return E_ILLEGAL_MOVE; - if (flags & F_SPLIT) { - if (board[nx][ny].piece || (board[x][y].piece != OBELISK2)) - return 0; - board[x][y].piece = OBELISK; - board[nx][ny].piece = OBELISK; - board[nx][ny].side = board[x][y].side; - return 1; + if (board[ncol][nrow].piece || (board[col][row].piece != OBELISK2)) + return E_ILLEGAL_MOVE; + board[col][row].piece = OBELISK; + board[ncol][nrow].piece = OBELISK; + board[ncol][nrow].side = board[col][row].side; + return HUGE_SUCCESS; } - if (board[nx][ny].piece && - !((board[x][y].piece == DJHED) && - ((board[nx][ny].piece != DJHED) && - (board[nx][ny].piece != PHARAO)))) - return 0; + if (board[ncol][nrow].piece && + !((board[col][row].piece == DJHED) && + ((board[ncol][nrow].piece != DJHED) && + (board[ncol][nrow].piece != PHARAO)))) + return E_ILLEGAL_MOVE; struct square tmp; - tmp = board[nx][ny]; - board[nx][ny] = board[x][y]; - board[x][y] = tmp; + tmp = board[ncol][nrow]; + board[ncol][nrow] = board[col][row]; + board[col][row] = tmp; - return 1; + return HUGE_SUCCESS; } void @@ -224,6 +338,7 @@ clear_board() for (i = 0; i < BOARD_HEIGHT; i++) for (j = 0; j < BOARD_WIDTH; j++) place(i, j, 0, 0, 0); + laser_pos[0] = laser_pos[1] = -1; } void @@ -263,9 +378,130 @@ setup_board(char *desc) } } +int +read_message(message_t *m) +{ + char buf[MAX_MSG_LEN+1]; + char c; + int i; + for (i = 0; i < MAX_MSG_LEN+1; i++) { + c = getchar(); + if (c == '\n') + break; + buf[i] = c; + } + buf[i] = '\0'; + while (c != '\n') c = getchar(); + + 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; + } + + 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 +execute_message(message_t msg, int side) +{ + switch (msg.type) { + case MSG_MOVE: + return move(side, msg.args.move.row, msg.args.move.col, + msg.args.move.dir, 0); + case MSG_ROTATE: + return rotate(side, msg.args.rotate.row, msg.args.rotate.col, + msg.args.rotate.dir); + default: + printf("unknown command type %d\n", msg.type); + return E_UNKNOWN_COMMAND; + } +} + +void +simple_game() +{ + int side = 0; + + setup_board(classic_setup); + print_board_small(); + + for (;;) { + message_t msg; + int r; + + printf("%s's move\n", sideinfo[side].name); + + r = read_message(&msg); + switch (r) { + case HUGE_SUCCESS: break; + case E_UNKNOWN_COMMAND: + printf("unknown command\n"); + continue; + default: + printf("uh oh (strange return value from read_message: %d)\n", r); + continue; + } + + r = execute_message(msg, side); + switch (r) { + case HUGE_SUCCESS: + print_board_small(); + r = laser(side); + print_board_small(); + switch (r) { + case SILVER_WINS: + printf("SILVER WINS\n"); + return; + case RED_WINS: + printf("RED WINS\n"); + return; + case L_WALL: + case L_PIECE: + printf("laser hits %s at %c%c\n", + r==L_WALL ? "wall" : "piece", + laser_pos[1]+'A', laser_pos[0]+'0'); + break; + } + side = 1-side; + break; + case E_ILLEGAL_MOVE: + printf("illegal move\n"); + continue; + default: + printf("uh oh (strange return value from execute_message: %d)\n", r); + continue; + } + } +} int main() { - setup_board(classic_setup); - print_board_small(); + simple_game(); }