diff options
-rw-r--r-- | include/chc.h | 41 | ||||
-rw-r--r-- | include/proto.h | 21 | ||||
-rw-r--r-- | mbbsd/chc.c | 1030 |
3 files changed, 1075 insertions, 17 deletions
diff --git a/include/chc.h b/include/chc.h new file mode 100644 index 00000000..9305ab0d --- /dev/null +++ b/include/chc.h @@ -0,0 +1,41 @@ +/* 象棋 + * 雙人對戰時,雙方都會有一個 chc_act_list 的 linked-list,紀錄著每下一步 + * 棋,必須將這個訊息丟給那些人(socket)。 + * 一開始當然就是對手一個,每當一個觀棋者加入(觀棋可以從紅方或黑方的觀點 + * 進行),其中一方的下棋者的 act_list 就會多一筆記錄,之後就會將下的或收 + * 到對方下的每一步棋傳給 act_list 中所有需要的人,達到觀棋的效果。 + */ + +#define SIDE_ROW 7 +#define TURN_ROW 8 +#define STEP_ROW 9 +#define TIME_ROW 10 +#define WARN_ROW 12 +#define MYWIN_ROW 17 +#define HISWIN_ROW 18 + +#define CHC_VERSUS 1 /* 雙人 */ +#define CHC_WATCH 2 /* 觀棋 */ +#define CHC_PERSONAL 4 /* 打譜 */ +#define CHC_WATCH_PERSONAL 8 /* 觀人打譜 */ + +#define BLACK_COLOR "\033[1;36m" +#define RED_COLOR "\033[1;31m" +#define BLACK_REVERSE "\033[1;37;46m" +#define RED_REVERSE "\033[1;37;41m" +#define TURN_COLOR "\033[1;33m" + +typedef struct chcusr_t{ + char userid[IDLEN + 1]; + int win; + int lose; + int tie; +} chcusr_t; + +#define CHC_ACT_BOARD 0x1 /* set if transfered board to this sock */ + +typedef struct chc_act_list{ + int sock; + struct chc_act_list *next; +} chc_act_list; + diff --git a/include/proto.h b/include/proto.h index bbb603df..5c287dd1 100644 --- a/include/proto.h +++ b/include/proto.h @@ -164,24 +164,11 @@ int card_99(); /* chat */ int t_chat(); -/* chc_draw */ -void chc_drawline(board_t board, chcusr_t *user1, chcusr_t *user2, int line); -void chc_movecur(int r, int c); -void chc_redraw(chcusr_t *user1, chcusr_t *user2, board_t board); - -/* chc_net */ -void chc_sendmove(int s); -int chc_recvmove(int s); - -/* chc_play */ +/* chc */ void chc(int s, int mode); - -/* chc_rule */ -void chc_movechess(board_t board); -int chc_canmove(board_t board, rc_t from, rc_t to); -int chc_iskfk(board_t board); -int chc_ischeck(board_t board, int turn); -void chc_init_board(board_t board); +int chc_main(void); +int chc_personal(void); +int chc_watch(void); /* chicken */ int show_file(char *filename, int y, int lines, int mode); diff --git a/mbbsd/chc.c b/mbbsd/chc.c new file mode 100644 index 00000000..fbd716a1 --- /dev/null +++ b/mbbsd/chc.c @@ -0,0 +1,1030 @@ +#include "bbs.h" + +#define CENTER(a, b) (((a) + (b)) >> 1) +#define CHC_TIMEOUT 300 +#define CHC_LOG "chc_log" /* log file name */ + +extern userinfo_t *uip; + +typedef int (*play_func_t) (int, chcusr_t *, chcusr_t *, board_t, board_t); + +typedef struct drc_t { + rc_t from, to; +} drc_t; + +static rc_t chc_from, chc_to, chc_select, chc_cursor; +static int chc_lefttime; +static int chc_my, chc_turn, chc_selected, chc_firststep; +static char chc_mode; +static char chc_warnmsg[64]; +static char chc_ipass = 0, chc_hepass = 0; +/* fp is for logging the step */ +static FILE *fp = NULL; +static board_t *chc_bp; +static chc_act_list *act_list = NULL; + + +/* some constant variable definition */ + +static const char *turn_str[2] = {"黑的", "紅的"}; + +static const char *num_str[10] = { + "", "一", "二", "三", "四", "五", "六", "七", "八", "九" +}; + +static const char *chess_str[2][8] = { + /* 0 1 2 3 4 5 6 7 */ + {" ", "將", "士", "象", "車", "馬", "包", "卒"}, + {" ", "帥", "仕", "相", "車", "傌", "炮", "兵"} +}; + +static const char *chess_brd[BRD_ROW * 2 - 1] = { + /* 0 1 2 3 4 5 6 7 8 */ + "┌─┬─┬─┬─┬─┬─┬─┬─┐", /* 0 */ + "│ │ │ │\│/│ │ │ │", + "├─┼─┼─┼─┼─┼─┼─┼─┤", /* 1 */ + "│ │ │ │/│\│ │ │ │", + "├─┼─┼─┼─┼─┼─┼─┼─┤", /* 2 */ + "│ │ │ │ │ │ │ │ │", + "├─┼─┼─┼─┼─┼─┼─┼─┤", /* 3 */ + "│ │ │ │ │ │ │ │ │", + "├─┴─┴─┴─┴─┴─┴─┴─┤", /* 4 */ + "│ 楚 河 漢 界 │", + "├─┬─┬─┬─┬─┬─┬─┬─┤", /* 5 */ + "│ │ │ │ │ │ │ │ │", + "├─┼─┼─┼─┼─┼─┼─┼─┤", /* 6 */ + "│ │ │ │ │ │ │ │ │", + "├─┼─┼─┼─┼─┼─┼─┼─┤", /* 7 */ + "│ │ │ │\│/│ │ │ │", + "├─┼─┼─┼─┼─┼─┼─┼─┤", /* 8 */ + "│ │ │ │/│\│ │ │ │", + "└─┴─┴─┴─┴─┴─┴─┴─┘" /* 9 */ +}; + +static char *hint_str[] = { + " q 認輸離開", + " p 要求和棋", + "方向鍵 移動遊標", + "Enter 選擇/移動" +}; + +/* + * Start of the network communication function. + */ +static int +chc_recvmove(int s) +{ + drc_t buf; + + if (read(s, &buf, sizeof(buf)) != sizeof(buf)) + return 0; + chc_from = buf.from, chc_to = buf.to; + return 1; +} + +static int +chc_sendmove(int s) +{ + drc_t buf; + + buf.from = chc_from, buf.to = chc_to; + if (write(s, &buf, sizeof(buf)) != sizeof(buf)) + return 0; + return 1; +} + +static void +chc_broadcast(chc_act_list *p, board_t board){ + while(p){ + if (chc_sendmove(p->sock) < 0) { + if (p->next->next == NULL) + p = NULL; + else { + chc_act_list *tmp = p->next->next; + p->next = tmp; + } + free(p->next); + } + p = p->next; + } +} + +static int +chc_broadcast_recv(chc_act_list *act_list, board_t board){ + if (!chc_recvmove(act_list->sock)) + return 0; + chc_broadcast(act_list->next, board); + return 1; +} + +static void +chc_broadcast_send(chc_act_list *act_list, board_t board){ + chc_broadcast(act_list, board); +} + +/* + * End of the network communication function. + */ + +/* + * Start of the drawing function. + */ +static void +chc_movecur(int r, int c) +{ + move(r * 2 + 3, c * 4 + 4); +} + +static char * +getstep(board_t board, rc_t *from, rc_t *to) +{ + int turn, fc, tc; + char *dir; + static char buf[80]; + + turn = CHE_O(board[from->r][from->c]); + fc = (turn == (chc_my ^ 1) ? from->c + 1 : 9 - from->c); + tc = (turn == (chc_my ^ 1) ? to->c + 1 : 9 - to->c); + if (from->r == to->r) + dir = "平"; + else { + if (from->c == to->c) + tc = from->r - to->r; + if (tc < 0) + tc = -tc; + + if ((turn == (chc_my ^ 1) && to->r > from->r) || + (turn == chc_my && to->r < from->r)) + dir = "進"; + else + dir = "退"; + } + sprintf(buf, "%s%s%s%s", + chess_str[turn][CHE_P(board[from->r][from->c])], + num_str[fc], dir, num_str[tc]); + return buf; +} + +static void +showstep(board_t board) +{ + int eatten; + + prints("%s%s", CHE_O(board[chc_from.r][chc_from.c]) == 0 ? BLACK_COLOR : RED_COLOR, getstep(board, &chc_from, &chc_to)); + + eatten = board[chc_to.r][chc_to.c]; + if (eatten) + prints(": %s%s", + CHE_O(eatten) == 0 ? BLACK_COLOR : RED_COLOR, + chess_str[CHE_O(eatten)][CHE_P(eatten)]); + prints("\033[m"); +} + +static void +chc_drawline(board_t board, chcusr_t *user1, chcusr_t *user2, int line) +{ + int i, j; + + move(line, 0); + clrtoeol(); + if (line == 0) { + prints("\033[1;46m 象棋對戰 \033[45m%30s VS %-20s%10s\033[m", + user1->userid, user2->userid, chc_mode & CHC_WATCH ? "[觀棋模式]" : ""); + } else if (line >= 3 && line <= 21) { + outs(" "); + for (i = 0; i < 9; i++) { + j = board[RTL(line)][i]; + if ((line & 1) == 1 && j) { + if (chc_selected && + chc_select.r == RTL(line) && chc_select.c == i) + prints("%s%s\033[m", + CHE_O(j) == 0 ? BLACK_REVERSE : RED_REVERSE, + chess_str[CHE_O(j)][CHE_P(j)]); + else + prints("%s%s\033[m", + CHE_O(j) == 0 ? BLACK_COLOR : RED_COLOR, + chess_str[CHE_O(j)][CHE_P(j)]); + } else + prints("%c%c", chess_brd[line - 3][i * 4], + chess_brd[line - 3][i * 4 + 1]); + if (i != 8) + prints("%c%c", chess_brd[line - 3][i * 4 + 2], + chess_brd[line - 3][i * 4 + 3]); + } + outs(" "); + + if (line >= 3 && line < 3 + (int)dim(hint_str)) { + outs(hint_str[line - 3]); + } else if (line == SIDE_ROW) { + prints("\033[1m你是%s%s\033[m", + chc_my == 0 ? BLACK_COLOR : RED_COLOR, + turn_str[chc_my]); + } else if (line == TURN_ROW) { + prints("%s%s\033[m", + TURN_COLOR, + chc_my == chc_turn ? "輪到你下棋了" : "等待對方下棋"); + } else if (line == STEP_ROW && !chc_firststep) { + showstep(board); + } else if (line == TIME_ROW) { + prints("剩餘時間 %d:%02d", chc_lefttime / 60, chc_lefttime % 60); + } else if (line == WARN_ROW) { + outs(chc_warnmsg); + } else if (line == MYWIN_ROW) { + prints("\033[1;33m%12.12s " + "\033[1;31m%2d\033[37m勝 " + "\033[34m%2d\033[37m敗 " + "\033[36m%2d\033[37m和\033[m", + user1->userid, + user1->win, user1->lose - 1, user1->tie); + } else if (line == HISWIN_ROW) { + prints("\033[1;33m%12.12s " + "\033[1;31m%2d\033[37m勝 " + "\033[34m%2d\033[37m敗 " + "\033[36m%2d\033[37m和\033[m", + user2->userid, + user2->win, user2->lose - 1, user2->tie); + } + } else if (line == 2 || line == 22) { + outs(" "); + if (line == 2) + for (i = 1; i <= 9; i++) + prints("%s ", num_str[i]); + else + for (i = 9; i >= 1; i--) + prints("%s ", num_str[i]); + } +} + +static void +chc_redraw(chcusr_t *user1, chcusr_t *user2, board_t board) +{ + int i; + for (i = 0; i <= 22; i++) + chc_drawline(board, user1, user2, i); +} +/* + * End of the drawing function. + */ + + +/* + * Start of the log function. + */ +int +chc_log_open(chcusr_t *user1, chcusr_t *user2, char *file) +{ + char buf[128]; + if ((fp = fopen(file, "w")) == NULL) + return -1; + sprintf(buf, "%s V.S. %s\n", user1->userid, user2->userid); + fputs(buf, fp); + return 0; +} + +void +chc_log_close(void) +{ + if (fp) + fclose(fp); +} + +int +chc_log(char *desc) +{ + if (fp) + return fputs(desc, fp); + return -1; +} + +int +chc_log_step(board_t board, rc_t *from, rc_t *to) +{ + char buf[80]; + sprintf(buf, " %s%s\033[m\n", CHE_O(board[from->r][from->c]) == 0 ? BLACK_COLOR : RED_COLOR, getstep(board, from, to)); + return chc_log(buf); +} + +static int +chc_filter(struct dirent *dir) +{ + if (strcmp(dir->d_name, ".") == 0 || strcmp(dir->d_name, "..") == 0 ) + return 0; + return strstr(dir->d_name, ".poem") != NULL; +} + +int +chc_log_poem(void) +{ + struct dirent **namelist; + int n; + + n = scandir(BBSHOME"/etc/chess", &namelist, chc_filter, alphasort); + if (n < 0) + perror("scandir"); + else { + char buf[80]; + FILE *fp; + sprintf(buf, BBSHOME"/etc/chess/%s", namelist[rand() % n]->d_name); + if ((fp = fopen(buf, "r")) == NULL) + return -1; + + while(fgets(buf, sizeof(buf), fp) != NULL) + chc_log(buf); + while(n--) + free(namelist[n]); + free(namelist); + fclose(fp); + } + return 0; +} +/* + * End of the log function. + */ + + +/* + * Start of the rule function. + */ + +static void +chc_init_board(board_t board) +{ + memset(board, 0, sizeof(board_t)); + board[0][4] = CHE(1, chc_my ^ 1); /* 將 */ + board[0][3] = board[0][5] = CHE(2, chc_my ^ 1); /* 士 */ + board[0][2] = board[0][6] = CHE(3, chc_my ^ 1); /* 象 */ + board[0][0] = board[0][8] = CHE(4, chc_my ^ 1); /* 車 */ + board[0][1] = board[0][7] = CHE(5, chc_my ^ 1); /* 馬 */ + board[2][1] = board[2][7] = CHE(6, chc_my ^ 1); /* 包 */ + board[3][0] = board[3][2] = board[3][4] = + board[3][6] = board[3][8] = CHE(7, chc_my ^ 1); /* 卒 */ + + board[9][4] = CHE(1, chc_my); /* 帥 */ + board[9][3] = board[9][5] = CHE(2, chc_my); /* 仕 */ + board[9][2] = board[9][6] = CHE(3, chc_my); /* 相 */ + board[9][0] = board[9][8] = CHE(4, chc_my); /* 車 */ + board[9][1] = board[9][7] = CHE(5, chc_my); /* 傌 */ + board[7][1] = board[7][7] = CHE(6, chc_my); /* 炮 */ + board[6][0] = board[6][2] = board[6][4] = + board[6][6] = board[6][8] = CHE(7, chc_my); /* 兵 */ +} + +static void +chc_movechess(board_t board) +{ + board[chc_to.r][chc_to.c] = board[chc_from.r][chc_from.c]; + board[chc_from.r][chc_from.c] = 0; +} + +static int +dist(rc_t from, rc_t to, int rowcol) +{ + int d; + + d = rowcol ? from.c - to.c : from.r - to.r; + return d > 0 ? d : -d; +} + +static int +between(board_t board, rc_t from, rc_t to, int rowcol) +{ + int i, rtv = 0; + + if (rowcol) { + if (from.c > to.c) + i = from.c, from.c = to.c, to.c = i; + for (i = from.c + 1; i < to.c; i++) + if (board[to.r][i]) + rtv++; + } else { + if (from.r > to.r) + i = from.r, from.r = to.r, to.r = i; + for (i = from.r + 1; i < to.r; i++) + if (board[i][to.c]) + rtv++; + } + return rtv; +} + +static int +chc_canmove(board_t board, rc_t from, rc_t to) +{ + int i; + int rd, cd, turn; + + rd = dist(from, to, 0); + cd = dist(from, to, 1); + turn = CHE_O(board[from.r][from.c]); + + /* general check */ + if (board[to.r][to.c] && CHE_O(board[to.r][to.c]) == turn) + return 0; + + /* individual check */ + switch (CHE_P(board[from.r][from.c])) { + case 1: /* 將 帥 */ + if (!(rd == 1 && cd == 0) && + !(rd == 0 && cd == 1)) + return 0; + if ((turn == (chc_my ^ 1) && to.r > 2) || + (turn == chc_my && to.r < 7) || + to.c < 3 || to.c > 5) + return 0; + break; + case 2: /* 士 仕 */ + if (!(rd == 1 && cd == 1)) + return 0; + if ((turn == (chc_my ^ 1) && to.r > 2) || + (turn == chc_my && to.r < 7) || + to.c < 3 || to.c > 5) + return 0; + break; + case 3: /* 象 相 */ + if (!(rd == 2 && cd == 2)) + return 0; + if ((turn == (chc_my ^ 1) && to.r > 4) || + (turn == chc_my && to.r < 5)) + return 0; + /* 拐象腿 */ + if (board[CENTER(from.r, to.r)][CENTER(from.c, to.c)]) + return 0; + break; + case 4: /* 車 */ + if (!(rd > 0 && cd == 0) && + !(rd == 0 && cd > 0)) + return 0; + if (between(board, from, to, rd == 0)) + return 0; + break; + case 5: /* 馬 傌 */ + if (!(rd == 2 && cd == 1) && + !(rd == 1 && cd == 2)) + return 0; + /* 拐馬腳 */ + if (rd == 2) { + if (board[CENTER(from.r, to.r)][from.c]) + return 0; + } else { + if (board[from.r][CENTER(from.c, to.c)]) + return 0; + } + break; + case 6: /* 包 炮 */ + if (!(rd > 0 && cd == 0) && + !(rd == 0 && cd > 0)) + return 0; + i = between(board, from, to, rd == 0); + if ((i > 1) || + (i == 1 && !board[to.r][to.c]) || + (i == 0 && board[to.r][to.c])) + return 0; + break; + case 7: /* 卒 兵 */ + if (!(rd == 1 && cd == 0) && + !(rd == 0 && cd == 1)) + return 0; + if (((turn == (chc_my ^ 1) && to.r < 5) || + (turn == chc_my && to.r > 4)) && + cd != 0) + return 0; + if ((turn == (chc_my ^ 1) && to.r < from.r) || + (turn == chc_my && to.r > from.r)) + return 0; + break; + } + return 1; +} + +static void +findking(board_t board, int turn, rc_t * buf) +{ + int i, r, c; + + r = (turn == (chc_my ^ 1)) ? 0 : 7; + for (i = 0; i < 3; r++, i++) + for (c = 3; c < 6; c++) + if (CHE_P(board[r][c]) == 1 && + CHE_O(board[r][c]) == turn) { + buf->r = r, buf->c = c; + return; + } +} + +static int +chc_iskfk(board_t board) +{ + rc_t from, to; + + findking(board, 0, &to); + findking(board, 1, &from); + if (from.c == to.c && between(board, from, to, 0) == 0) + return 1; + return 0; +} + +static int +chc_ischeck(board_t board, int turn) +{ + rc_t from, to; + + findking(board, turn, &to); + for (from.r = 0; from.r < BRD_ROW; from.r++) + for (from.c = 0; from.c < BRD_COL; from.c++) + if (board[from.r][from.c] && + CHE_O(board[from.r][from.c]) != turn) + if (chc_canmove(board, from, to)) + return 1; + return 0; +} + +/* + * End of the rule function. + */ + +static void +chcusr_put(userec_t *userec, chcusr_t *user) +{ + userec->chc_win = user->win; + userec->chc_lose = user->lose; + userec->chc_tie = user->tie; +} + +static void +chcusr_get(userec_t *userec, chcusr_t *user) +{ + strlcpy(user->userid, userec->userid, sizeof(user->userid)); + user->win = userec->chc_win; + user->lose = userec->chc_lose; + user->tie = userec->chc_tie; +} + +static int +hisplay(int s, chcusr_t *user1, chcusr_t *user2, board_t board, board_t tmpbrd) +{ + int start_time; + int endgame = 0, endturn = 0; + + start_time = now; + while (!endturn) { + chc_lefttime = CHC_TIMEOUT - (now - start_time); + if (chc_lefttime < 0) { + chc_lefttime = 0; + + /* to make him break out igetkey() */ + chc_from.r = -2; + chc_broadcast_send(act_list, board); + } + chc_drawline(board, user1, user2, TIME_ROW); + move(1, 0); + oflush(); + switch (igetkey()) { + case 'q': + endgame = 2; + endturn = 1; + break; + case 'p': + if (chc_hepass) { + chc_from.r = -1; + chc_broadcast_send(act_list, board); + endgame = 3; + endturn = 1; + } + break; + case I_OTHERDATA: + if (!chc_broadcast_recv(act_list, board)) { /* disconnect */ + endturn = 1; + endgame = 1; + } else { + if (chc_from.r == -1) { + chc_hepass = 1; + strlcpy(chc_warnmsg, "\033[1;33m要求和局!\033[m", sizeof(chc_warnmsg)); + chc_drawline(board, user1, user2, WARN_ROW); + } else { + /* 座標變換 + * (CHC_WATCH_PERSONAL 設定時 + * 表觀棋者看的棋局為單人打譜的棋局) + * 棋盤需倒置的清況才要轉換 + */ + /* 1.如果在觀棋 且棋局是別人在打譜 且輪到你 或*/ + if ( ((chc_mode & CHC_WATCH) && (chc_mode & CHC_WATCH_PERSONAL)) || + /* 2.自己在打譜 */ + (chc_mode & CHC_PERSONAL) || + ((chc_mode & CHC_WATCH) && !chc_turn) + ) + ; // do nothing + else { + chc_from.r = 9 - chc_from.r, chc_from.c = 8 - chc_from.c; + chc_to.r = 9 - chc_to.r, chc_to.c = 8 - chc_to.c; + } + chc_cursor = chc_to; + if (CHE_P(board[chc_to.r][chc_to.c]) == 1) + endgame = 2; + endturn = 1; + chc_hepass = 0; + chc_drawline(board, user1, user2, STEP_ROW); + chc_log_step(board, &chc_from, &chc_to); + chc_movechess(board); + chc_drawline(board, user1, user2, LTR(chc_from.r)); + chc_drawline(board, user1, user2, LTR(chc_to.r)); + } + } + break; + } + } + return endgame; +} + +static int +myplay(int s, chcusr_t *user1, chcusr_t *user2, board_t board, board_t tmpbrd) +{ + int ch, start_time; + int endgame = 0, endturn = 0; + + chc_ipass = 0, chc_selected = 0; + start_time = now; + chc_lefttime = CHC_TIMEOUT - (now - start_time); + bell(); + while (!endturn) { + chc_drawline(board, user1, user2, TIME_ROW); + chc_movecur(chc_cursor.r, chc_cursor.c); + oflush(); + ch = igetkey(); + chc_lefttime = CHC_TIMEOUT - (now - start_time); + if (chc_lefttime < 0) + ch = 'q'; + switch (ch) { + case I_OTHERDATA: + if (!chc_broadcast_recv(act_list, board)) { /* disconnect */ + endgame = 1; + endturn = 1; + } else if (chc_from.r == -1 && chc_ipass) { + endgame = 3; + endturn = 1; + } + break; + case KEY_UP: + chc_cursor.r--; + if (chc_cursor.r < 0) + chc_cursor.r = BRD_ROW - 1; + break; + case KEY_DOWN: + chc_cursor.r++; + if (chc_cursor.r >= BRD_ROW) + chc_cursor.r = 0; + break; + case KEY_LEFT: + chc_cursor.c--; + if (chc_cursor.c < 0) + chc_cursor.c = BRD_COL - 1; + break; + case KEY_RIGHT: + chc_cursor.c++; + if (chc_cursor.c >= BRD_COL) + chc_cursor.c = 0; + break; + case 'q': + endgame = 2; + endturn = 1; + break; + case 'p': + chc_ipass = 1; + chc_from.r = -1; + chc_broadcast_send(act_list, board); + strlcpy(chc_warnmsg, "\033[1;33m要求和棋!\033[m", sizeof(chc_warnmsg)); + chc_drawline(board, user1, user2, WARN_ROW); + bell(); + break; + case '\r': + case '\n': + case ' ': + if (chc_selected) { + if (chc_cursor.r == chc_select.r && + chc_cursor.c == chc_select.c) { + chc_selected = 0; + chc_drawline(board, user1, user2, LTR(chc_cursor.r)); + } else if (chc_canmove(board, chc_select, chc_cursor)) { + if (CHE_P(board[chc_cursor.r][chc_cursor.c]) == 1) + endgame = 1; + chc_from = chc_select; + chc_to = chc_cursor; + if (!endgame) { + memcpy(tmpbrd, board, sizeof(board_t)); + chc_movechess(tmpbrd); + } + if (endgame || !chc_iskfk(tmpbrd)) { + chc_drawline(board, user1, user2, STEP_ROW); + chc_log_step(board, &chc_from, &chc_to); + chc_movechess(board); + chc_broadcast_send(act_list, board); + chc_selected = 0; + chc_drawline(board, user1, user2, LTR(chc_from.r)); + chc_drawline(board, user1, user2, LTR(chc_to.r)); + endturn = 1; + } else { + strlcpy(chc_warnmsg, "\033[1;33m不可以王見王\033[m", sizeof(chc_warnmsg)); + bell(); + chc_drawline(board, user1, user2, WARN_ROW); + } + } + } else if (board[chc_cursor.r][chc_cursor.c] && + CHE_O(board[chc_cursor.r][chc_cursor.c]) == chc_turn) { + chc_selected = 1; + chc_select = chc_cursor; + chc_drawline(board, user1, user2, LTR(chc_cursor.r)); + } + break; + } + } + return endgame; +} + +static void +mainloop(int s, chcusr_t *user1, chcusr_t *user2, board_t board, play_func_t play_func[2]) +{ + int endgame; + char buf[80]; + board_t tmpbrd; + + if (!(chc_mode & CHC_WATCH)) + chc_turn = 1; + for (endgame = 0; !endgame; chc_turn ^= 1) { + chc_firststep = 0; + chc_drawline(board, user1, user2, TURN_ROW); + if (chc_ischeck(board, chc_turn)) { + strlcpy(chc_warnmsg, "\033[1;31m將軍!\033[m", sizeof(chc_warnmsg)); + bell(); + } else + chc_warnmsg[0] = 0; + chc_drawline(board, user1, user2, WARN_ROW); + endgame = play_func[chc_turn] (s, user1, user2, board, tmpbrd); + } + + if (chc_mode & CHC_VERSUS) { + if (endgame == 1) { + strlcpy(chc_warnmsg, "對方認輸了!", sizeof(chc_warnmsg)); + user1->win++; + currutmp->chc_win++; + } else if (endgame == 2) { + strlcpy(chc_warnmsg, "你認輸了!", sizeof(chc_warnmsg)); + user1->lose++; + currutmp->chc_lose++; + } else { + strlcpy(chc_warnmsg, "和棋", sizeof(chc_warnmsg)); + user1->tie++; + currutmp->chc_tie++; + } + user1->lose--; + chcusr_put(&cuser, user1); + passwd_update(usernum, &cuser); + } + else if (chc_mode & CHC_WATCH) { + strlcpy(chc_warnmsg, "結束觀棋", sizeof(chc_warnmsg)); + } + else { + strlcpy(chc_warnmsg, "結束打譜", sizeof(chc_warnmsg)); + } + + chc_log("=> "); + if (endgame == 3) + chc_log("和局"); + else{ + sprintf(buf, "%s勝\n", chc_my && endgame == 1 ? "紅" : "黑"); + chc_log(buf); + } + + chc_drawline(board, user1, user2, WARN_ROW); + bell(); + oflush(); +} + +static void +chc_init_play_func(chcusr_t *user1, chcusr_t *user2, play_func_t play_func[2]) +{ + char userid[2][IDLEN + 1]; + + if (chc_mode & CHC_PERSONAL) { + strlcpy(userid[0], cuser.userid, sizeof(userid[0])); + strlcpy(userid[1], cuser.userid, sizeof(userid[1])); + play_func[0] = play_func[1] = myplay; + } + else if (chc_mode & CHC_WATCH) { + userinfo_t *uinfo = search_ulist_userid(currutmp->mateid); + strlcpy(userid[0], uinfo->userid, sizeof(userid[0])); + strlcpy(userid[1], uinfo->mateid, sizeof(userid[1])); + play_func[0] = play_func[1] = hisplay; + } + else { + strlcpy(userid[0], cuser.userid, sizeof(userid[0])); + strlcpy(userid[1], currutmp->mateid, sizeof(userid[1])); + play_func[chc_my] = myplay; + play_func[chc_my ^ 1] = hisplay; + } + + getuser(userid[0]); + chcusr_get(&xuser, user1); + getuser(userid[1]); + chcusr_get(&xuser, user2); +} + +static void +chc_watch_request(int signo) +{ + if (!(currstat & CHC)) + return; + chc_act_list *tmp; + for(tmp = act_list; tmp->next != NULL; tmp = tmp->next); + tmp->next = (chc_act_list *)malloc(sizeof(chc_act_list)); + tmp = tmp->next; + tmp->sock = reply_connection_request(uip); + if (tmp->sock < 0) + return; + tmp->next = NULL; + write(tmp->sock, chc_bp, sizeof(board_t)); + write(tmp->sock, &chc_my, sizeof(chc_my)); + write(tmp->sock, &chc_turn, sizeof(chc_turn)); + write(tmp->sock, &currutmp->turn, sizeof(currutmp->turn)); + write(tmp->sock, &chc_firststep, sizeof(chc_firststep)); + write(tmp->sock, &chc_mode, sizeof(chc_mode)); +} + +static void +chc_init(int s, chcusr_t *user1, chcusr_t *user2, board_t board, play_func_t play_func[2]) +{ + userinfo_t *my = currutmp; + + setutmpmode(CHC); + clear(); + chc_warnmsg[0] = 0; + + /* 從不同來源初始化各個變數 */ + if (!(chc_mode & CHC_WATCH)) { + if (chc_mode & CHC_PERSONAL) + chc_my = 1; + else + chc_my = my->turn; + chc_firststep = 1; + chc_init_board(board); + chc_cursor.r = 9, chc_cursor.c = 0; + } + else { + char mode; + read(s, board, sizeof(board_t)); + read(s, &chc_my, sizeof(chc_my)); + read(s, &chc_turn, sizeof(chc_turn)); + read(s, &my->turn, sizeof(my->turn)); + read(s, &chc_firststep, sizeof(chc_firststep)); + read(s, &mode, sizeof(mode)); + if (mode & CHC_PERSONAL) + chc_mode |= CHC_WATCH_PERSONAL; + } + + act_list = (chc_act_list *)malloc(sizeof(*act_list)); + act_list->sock = s; + act_list->next = 0; + + chc_init_play_func(user1, user2, play_func); + + chc_redraw(user1, user2, board); + add_io(s, 0); + + signal(SIGUSR1, chc_watch_request); + + if (my->turn && !(chc_mode & CHC_WATCH)) + chc_broadcast_recv(act_list, board); + + user1->lose++; + + if (chc_mode & CHC_VERSUS) { + passwd_query(usernum, &xuser); + chcusr_put(&xuser, user1); + passwd_update(usernum, &xuser); + } + + if (!my->turn) { + if (!(chc_mode & CHC_WATCH)) + chc_broadcast_send(act_list, board); + user2->lose++; + } + chc_redraw(user1, user2, board); +} + +void +chc(int s, int mode) +{ + chcusr_t user1, user2; + play_func_t play_func[2]; + board_t board; + char mode0 = currutmp->mode; + char file[80]; + + signal(SIGUSR1, SIG_IGN); + + chc_mode = mode; + chc_bp = &board; + + chc_init(s, &user1, &user2, board, play_func); + + setuserfile(file, CHC_LOG); + if (chc_log_open(&user1, &user2, file) < 0) + vmsg("無法紀錄棋局"); + + mainloop(s, &user1, &user2, board, play_func); + + /* close these fd */ + if (chc_mode & CHC_PERSONAL) + act_list = act_list->next; + while(act_list){ + close(act_list->sock); + act_list = act_list->next; + } + + add_io(0, 0); + if (chc_my) + pressanykey(); + + currutmp->mode = mode0; + + if (getans("是否將棋譜寄回信箱?[N/y]") == 'y') { + char title[80]; + sprintf(title, "%s V.S. %s", user1.userid, user2.userid); + chc_log("\n--\n\n"); + chc_log_poem(); + chc_log_close(); + mail_id(cuser.userid, title, file, "[楚河漢界]"); + } + else + chc_log_close(); + signal(SIGUSR1, talk_request); +} + +static userinfo_t * +chc_init_utmp(void) +{ + char uident[16]; + userinfo_t *uin; + + stand_title("楚河漢界之爭"); + generalnamecomplete(msg_uid, uident, sizeof(uident), + SHM->UTMPnumber, + completeutmp_compar, + completeutmp_permission, + completeutmp_getname); + if (uident[0] == '\0') + return NULL; + + if ((uin = search_ulist_userid(uident)) == NULL) + return NULL; + + uin->sig = SIG_CHC; + return uin; +} + +int +chc_main(void) +{ + userinfo_t *uin; + + if ((uin = chc_init_utmp()) == NULL) + return -1; + uin->turn = 1; + currutmp->turn = 0; + strlcpy(uin->mateid, currutmp->userid, sizeof(uin->mateid)); + strlcpy(currutmp->mateid, uin->userid, sizeof(currutmp->mateid)); + + my_talk(uin, friend_stat(currutmp, uin), 'c'); + return 0; +} + +int +chc_personal(void) +{ + chc(0, CHC_PERSONAL); + return 0; +} + +int +chc_watch(void) +{ + int sock, msgsock; + userinfo_t *uin; + + if ((uin = chc_init_utmp()) == NULL) + return -1; + + if (uin->uid == currutmp->uid || uin->mode != CHC) + return -1; + + if ((sock = make_connection_to_somebody(uin, 10)) < 0) { + vmsg("無法建立連線"); + return -1; + } + msgsock = accept(sock, (struct sockaddr *) 0, (socklen_t *) 0); + close(sock); + if (msgsock < 0) + return -1; + + strlcpy(currutmp->mateid, uin->userid, sizeof(currutmp->mateid)); + chc(msgsock, CHC_WATCH); + close(msgsock); + return 0; +} |