diff options
author | scw <scw@63ad8ddf-47c3-0310-b6dd-a9e9d9715204> | 2005-08-08 04:21:12 +0800 |
---|---|---|
committer | scw <scw@63ad8ddf-47c3-0310-b6dd-a9e9d9715204> | 2005-08-08 04:21:12 +0800 |
commit | f9f4c71a8beec3d7c2931a266d3df20d00abaeba (patch) | |
tree | e4ca0bb95cc1a5bbd1dd0724ba73348112c7b604 /mbbsd/chc.c | |
parent | b3bb4b2108f3c2d60bb005fd63dafc5e8a72045a (diff) | |
download | pttbbs-f9f4c71a8beec3d7c2931a266d3df20d00abaeba.tar pttbbs-f9f4c71a8beec3d7c2931a266d3df20d00abaeba.tar.gz pttbbs-f9f4c71a8beec3d7c2931a266d3df20d00abaeba.tar.bz2 pttbbs-f9f4c71a8beec3d7c2931a266d3df20d00abaeba.tar.lz pttbbs-f9f4c71a8beec3d7c2931a266d3df20d00abaeba.tar.xz pttbbs-f9f4c71a8beec3d7c2931a266d3df20d00abaeba.tar.zst pttbbs-f9f4c71a8beec3d7c2931a266d3df20d00abaeba.zip |
New chess framework
* Provides common parts of all chess games
* Chinese chess fully ported
* Improved watching
* Leaving possibility to implement replaying
!!!NOTE!!! Protocal not backward compatible,
STOP ALL clients before upgrade.
git-svn-id: http://opensvn.csie.org/pttbbs/trunk/pttbbs@3002 63ad8ddf-47c3-0310-b6dd-a9e9d9715204
Diffstat (limited to 'mbbsd/chc.c')
-rw-r--r-- | mbbsd/chc.c | 1397 |
1 files changed, 374 insertions, 1023 deletions
diff --git a/mbbsd/chc.c b/mbbsd/chc.c index 20173251..21f536f5 100644 --- a/mbbsd/chc.c +++ b/mbbsd/chc.c @@ -1,12 +1,16 @@ /* $Id$ */ #include "bbs.h" +#include "chess.h" + +#define assert_not_reached() assert(!"Should never be here!!!") extern const double elo_exp_tab[1000]; enum Turn { - BLK, + BLK = 0, RED }; + enum Kind { KIND_K=1, KIND_A, @@ -18,52 +22,36 @@ enum Kind { }; #define CENTER(a, b) (((a) + (b)) >> 1) #define CHC_TIMEOUT 300 -#define CHC_LOG "chc_log" /* log file name */ #define PHOTO_LINE 15 #define PHOTO_COLUMN (256 + 25) -typedef int (*play_func_t) (int, const chcusr_t *, const chcusr_t *, board_t, board_t); - typedef struct drc_t { + ChessStepType type; /* necessary one */ rc_t from, to; } drc_t; -struct CHCData { - rc_t from, to, select, cursor; - - /* 計時用, [0] = mine, [1] = his */ - int lefttime[2]; - int lefthand[2]; /* 限時限步時用, = 0 表為自由時間或非限時限步模式 */ - - int my; /* 我方執紅或黑, 0 黑, 1 紅. 觀棋=1 */ - int turn, selected, firststep; - char mode; - char warnmsg[64]; - /* color(7)+step(4*2)+normal(3)+color(7)+eat(2*2)+normal(3)+1=33 */ - char last_movestr[36]; - char ipass, hepass; - /* chessfp is for logging the step */ - FILE *chessfp; - board_t *bp; - chc_act_list *act_list; - char *photo; -}; typedef struct { - int limit_hand; - int limit_time; - int free_time; - enum { - CHCTIME_ORIGINAL, CHCTIME_FREE, CHCTIME_LIMIT - } time_mode; -} CHCTimeLimit; + rc_t select; + char selected; +} chc_tag_data_t; + +/* chess framework action functions */ +static void chc_init_user(const userec_t *userec, ChessUser *user); +static void chc_init_board(const ChessInfo* info, board_t board); +static void chc_drawline(const ChessInfo* info, int line); +static void chc_movecur(int r, int c); +static void chc_prepare_play(ChessInfo* info); +static int chc_select(ChessInfo* info, rc_t location, ChessGameResult* result); +static void chc_prepare_step(ChessInfo* info, const void* step); +static int chc_movechess(board_t board, const drc_t* move); +static void chc_drawstep(ChessInfo* info, const drc_t* move); +static void chc_gameend(ChessInfo* info, ChessGameResult result); +static void chc_genlog(ChessInfo* info, FILE* fp, ChessGameResult result); -static struct CHCData *chcd; -static CHCTimeLimit *timelimit; static const char * const turn_color[2]={BLACK_COLOR, RED_COLOR}; - /* some constant variable definition */ static const char * const turn_str[2] = {"黑的", "紅的"}; @@ -109,76 +97,34 @@ static char * const hint_str[] = { "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; - chcd->from = buf.from, chcd->to = buf.to; - return 1; -} - -static int -chc_sendmove(int s) -{ - drc_t buf; - - buf.from = chcd->from, buf.to = chcd->to; - if (write(s, &buf, sizeof(buf)) != sizeof(buf)) - return 0; - return 1; -} - -// XXX return value -// XXX die because of SIGPIPE !? - -/* return false if your adversary is off-line */ -static void -chc_broadcast(chc_act_list **head, board_t board){ - chc_act_list *p = *head; - void (*orig_handler)(int); - - if (!p) - return; - - orig_handler = Signal(SIGPIPE, SIG_IGN); - if (!chc_sendmove(p->sock)) { - /* do nothing */ - } - - while(p->next){ - if (!chc_sendmove(p->next->sock)) { - chc_act_list *tmp = p->next->next; - free(p->next); - p->next = tmp; - } else - p = p->next; - } - Signal(SIGPIPE, orig_handler); -} - -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 int -chc_broadcast_send(chc_act_list *act_list, board_t board){ - chc_broadcast(&act_list, board); - return 1; -} +static const ChessActions chc_actions = { + &chc_init_user, + (void (*) (const ChessInfo*, void*)) &chc_init_board, + &chc_drawline, + &chc_movecur, + &chc_prepare_play, + &chc_select, + &chc_prepare_step, + (int (*) (void*, const void*)) &chc_movechess, + (void (*)(ChessInfo*, const void*)) &chc_drawstep, + &chc_gameend, + &chc_genlog +}; -/* - * End of the network communication function. - */ +static const ChessConstants chc_constants = { + sizeof(drc_t), + CHC_TIMEOUT, + BRD_ROW, + BRD_COL, + "photo_cchess", +#ifdef GLOBAL_CCHESS_LOG + GLOBAL_CCHESS_LOG, +#else + NULL, +#endif + { BLACK_COLOR, RED_COLOR }, + {"黑的", "紅的"} +}; /* * Start of the drawing function. @@ -190,7 +136,7 @@ chc_movecur(int r, int c) } static char * -getstep(board_t board, const rc_t *from, const rc_t *to, char buf[]) +getstep(board_t board, int my, const rc_t *from, const rc_t *to, char buf[]) { int turn, fc, tc; char *dir; @@ -208,8 +154,8 @@ getstep(board_t board, const rc_t *from, const rc_t *to, char buf[]) } } } - fc = (turn == (chcd->my ^ 1) ? from->c + 1 : 9 - from->c); - tc = (turn == (chcd->my ^ 1) ? to->c + 1 : 9 - to->c); + fc = (turn == (my ^ 1) ? from->c + 1 : 9 - from->c); + tc = (turn == (my ^ 1) ? to->c + 1 : 9 - to->c); if (from->r == to->r) dir = "平"; else { @@ -218,8 +164,8 @@ getstep(board_t board, const rc_t *from, const rc_t *to, char buf[]) if (tc < 0) tc = -tc; - if ((turn == (chcd->my ^ 1) && to->r > from->r) || - (turn == chcd->my && to->r < from->r)) + if ((turn == (my ^ 1) && to->r > from->r) || + (turn == my && to->r < from->r)) dir = "進"; else dir = "退"; @@ -230,7 +176,7 @@ getstep(board_t board, const rc_t *from, const rc_t *to, char buf[]) /* 傌二|前傌 */ if(twin) { len+=sprintf(buf+len, "%s%s", - ((from->r>twin_r)==(turn==(chcd->my^1)))?"前":"後", + ((from->r>twin_r)==(turn==(my^1)))?"前":"後", chess_str[turn][CHE_P(board[from->r][from->c])]); } else { len+=sprintf(buf+len, "%s%s", @@ -249,38 +195,50 @@ getstep(board_t board, const rc_t *from, const rc_t *to, char buf[]) } static void -showstep(board_t board) +showstep(const ChessInfo* info) { - outs(chcd->last_movestr); + outs(info->last_movestr); +} + +inline static const char* +chc_timestr(int second) +{ + static char str[10]; + snprintf(str, sizeof(str), "%d:%02d", second / 60, second % 60); + return str; } static void -chc_drawline(board_t board, const chcusr_t *user1, const chcusr_t *user2, int line) +chc_drawline(const ChessInfo* info, int line) { int i, j; - - if (line == TURN_ROW) - line = chcd->photo ? PHOTO_TURN_ROW : REAL_TURN_ROW; - else if (line == TIME_ROW) { - chc_drawline(board, user1, user2, - chcd->photo ? PHOTO_TIME_ROW1 : REAL_TIME_ROW1); - line = chcd->photo ? PHOTO_TIME_ROW2 : REAL_TIME_ROW2; - } else if (line == WARN_ROW) { - line = chcd->photo ? PHOTO_WARN_ROW : REAL_WARN_ROW; - } + board_p board = (board_p) info->board; + chc_tag_data_t *tag = info->tag; + + if (line == CHESS_DRAWING_TURN_ROW) + line = info->photo ? PHOTO_TURN_ROW : REAL_TURN_ROW; + else if (line == CHESS_DRAWING_TIME_ROW) { + chc_drawline(info, info->photo ? PHOTO_TIME_ROW1 : REAL_TIME_ROW1); + line = info->photo ? PHOTO_TIME_ROW2 : REAL_TIME_ROW2; + } else if (line == CHESS_DRAWING_WARN_ROW) + line = info->photo ? PHOTO_WARN_ROW : REAL_WARN_ROW; + else if (line == CHESS_DRAWING_STEP_ROW) + line = STEP_ROW; move(line, 0); clrtoeol(); if (line == 0) { - prints(ANSI_COLOR(1;46) " 象棋對戰 " ANSI_COLOR(45) "%30s VS %-20s%10s" ANSI_RESET, - user1->userid, user2->userid, chcd->mode & CHC_WATCH ? "[觀棋模式]" : ""); + prints(ANSI_COLOR(1;46) " 象棋對戰 " ANSI_COLOR(45) + "%30s VS %-20s%10s" ANSI_RESET, + info->user1.userid, info->user2.userid, + info->mode == CHESS_MODE_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 (chcd->selected && - chcd->select.r == RTL(line) && chcd->select.c == i) { + if (tag->selected && + tag->select.r == RTL(line) && tag->select.c == i) { prints("%s%s" ANSI_RESET, CHE_O(j) == BLK ? BLACK_REVERSE : RED_REVERSE, chess_str[CHE_O(j)][CHE_P(j)]); @@ -307,34 +265,51 @@ chc_drawline(board_t board, const chcusr_t *user1, const chcusr_t *user2, int li prints("%s ", num_str[1][i]); } - if (chcd->photo) { - if (line >= 3 && line < 3 + PHOTO_LINE) { + if (info->photo) { + if (line >= 3 && line < 3 + CHESS_PHOTO_LINE) { outs(" "); - outs(chcd->photo + (line - 3) * PHOTO_COLUMN); + outs(info->photo + (line - 3) * CHESS_PHOTO_COLUMN); } else if (line >= PHOTO_TURN_ROW && line <= PHOTO_WARN_ROW) { outs(" "); if (line == PHOTO_TURN_ROW) prints("%s%s" ANSI_RESET, TURN_COLOR, - chcd->my == chcd->turn ? "輪到你下棋了" : "等待對方下棋"); + info->my == info->turn ? "輪到你下棋了" : "等待對方下棋"); else if (line == PHOTO_TIME_ROW1) { - if (chcd->lefthand[0]) - prints("我方剩餘時間 %d:%02d / %2d 步", - chcd->lefttime[0] / 60, chcd->lefttime[0] % 60, - chcd->lefthand[0]); + if (info->mode == CHESS_MODE_WATCH) { + if (!info->timelimit) + prints("每手限時五分鐘"); + else + prints("局時: %5s", + chc_timestr(info->timelimit->free_time)); + } else if (info->lefthand[0]) + prints("我方剩餘時間 %s / %2d 步", + chc_timestr(info->lefttime[0]), + info->lefthand[0]); else - prints("我方剩餘時間 %d:%02d", - chcd->lefttime[0] / 60, chcd->lefttime[0] % 60); + prints("我方剩餘時間 %s", + chc_timestr(info->lefttime[0])); } else if (line == PHOTO_TIME_ROW2) { - if (chcd->lefthand[1]) - prints("對方剩餘時間 %d:%02d / %2d 步", - chcd->lefttime[1] / 60, chcd->lefttime[1] % 60, - chcd->lefthand[1]); + if (info->mode == CHESS_MODE_WATCH) { + if (info->timelimit) { + if (info->timelimit->time_mode == + CHESS_TIMEMODE_MULTIHAND) + prints("步時: %s / %2d 步", + chc_timestr(info->timelimit->limit_time), + info->timelimit->limit_hand); + else + prints("讀秒: %5d 秒", + info->timelimit->limit_time); + } + } else if (info->lefthand[1]) + prints("對方剩餘時間 %s / %2d 步", + chc_timestr(info->lefttime[1]), + info->lefthand[1]); else - prints("對方剩餘時間 %d:%02d", - chcd->lefttime[1] / 60, chcd->lefttime[1] % 60); + prints("對方剩餘時間 %s", + chc_timestr(info->lefttime[1])); } else if (line == PHOTO_WARN_ROW) - outs(chcd->warnmsg); + outs(info->warnmsg); } } else if (line >= 3 && line <= HISWIN_ROW) { outs(" "); @@ -342,57 +317,49 @@ chc_drawline(board_t board, const chcusr_t *user1, const chcusr_t *user2, int li outs(hint_str[line - 3]); } else if (line == SIDE_ROW) { prints(ANSI_COLOR(1) "你是%s%s" ANSI_RESET, - turn_color[chcd->my], - turn_str[chcd->my]); + turn_color[(int) info->my], + turn_str[(int) info->my]); } else if (line == REAL_TURN_ROW) { prints("%s%s" ANSI_RESET, TURN_COLOR, - chcd->my == chcd->turn ? "輪到你下棋了" : "等待對方下棋"); - } else if (line == STEP_ROW && !chcd->firststep) { - showstep(board); + info->my == info->turn ? "輪到你下棋了" : "等待對方下棋"); + } else if (line == STEP_ROW && info->last_movestr) { + showstep(info); } else if (line == REAL_TIME_ROW1) { - if (chcd->lefthand[0]) - prints("我方剩餘時間 %d:%02d / %2d 步", - chcd->lefttime[0] / 60, chcd->lefttime[0] % 60, - chcd->lefthand[0]); + if (info->lefthand[0]) + prints("我方剩餘時間 %s / %2d 步", + chc_timestr(info->lefttime[0]), + info->lefthand[0]); else - prints("我方剩餘時間 %d:%02d", - chcd->lefttime[0] / 60, chcd->lefttime[0] % 60); + prints("我方剩餘時間 %s", + chc_timestr(info->lefttime[0])); } else if (line == REAL_TIME_ROW2) { - if (chcd->lefthand[1]) - prints("對方剩餘時間 %d:%02d / %2d 步", - chcd->lefttime[1] / 60, chcd->lefttime[1] % 60, - chcd->lefthand[1]); + if (info->lefthand[1]) + prints("對方剩餘時間 %s / %2d 步", + chc_timestr(info->lefttime[1]), + info->lefthand[1]); else - prints("對方剩餘時間 %d:%02d", - chcd->lefttime[1] / 60, chcd->lefttime[1] % 60); + prints("對方剩餘時間 %s", + chc_timestr(info->lefttime[1])); } else if (line == REAL_WARN_ROW) { - outs(chcd->warnmsg); + outs(info->warnmsg); } else if (line == MYWIN_ROW) { prints(ANSI_COLOR(1;33) "%12.12s " ANSI_COLOR(1;31) "%2d" ANSI_COLOR(37) "勝 " ANSI_COLOR(34) "%2d" ANSI_COLOR(37) "敗 " ANSI_COLOR(36) "%2d" ANSI_COLOR(37) "和" ANSI_RESET, - user1->userid, - user1->win, user1->lose - 1, user1->tie); + info->user1.userid, + info->user1.win, info->user1.lose - 1, info->user1.tie); } else if (line == HISWIN_ROW) { prints(ANSI_COLOR(1;33) "%12.12s " ANSI_COLOR(1;31) "%2d" ANSI_COLOR(37) "勝 " ANSI_COLOR(34) "%2d" ANSI_COLOR(37) "敗 " ANSI_COLOR(36) "%2d" ANSI_COLOR(37) "和" ANSI_RESET, - user2->userid, - user2->win, user2->lose - 1, user2->tie); + info->user2.userid, + info->user2.win, info->user2.lose - 1, info->user2.tie); } } } - -static void -chc_redraw(const chcusr_t *user1, const 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. */ @@ -401,43 +368,14 @@ chc_redraw(const chcusr_t *user1, const chcusr_t *user2, board_t board) /* * Start of the log function. */ -int -chc_log_open(const chcusr_t *user1, const chcusr_t *user2, const char *file) -{ - char buf[128]; - if ((chcd->chessfp = fopen(file, "w")) == NULL) - return -1; - if(chcd->my == RED) - sprintf(buf, "%s V.S. %s\n", user1->userid, user2->userid); - else - sprintf(buf, "%s V.S. %s\n", user2->userid, user1->userid); - fputs(buf, chcd->chessfp); - return 0; -} - void -chc_log_close(void) -{ - if (chcd->chessfp) { - fclose(chcd->chessfp); - chcd->chessfp=NULL; - } -} - -int -chc_log(const char *desc) -{ - if (chcd->chessfp) - return fputs(desc, chcd->chessfp); - return -1; -} - -int -chc_log_step(board_t board, const rc_t *from, const rc_t *to) +chc_log_step(FILE* fp, board_t board, int my, const drc_t *step) { char buf[80]; - sprintf(buf, " %s\n", chcd->last_movestr); - return chc_log(buf); + buf[0] = buf[1] = ' '; + getstep(board, my, &step->from, &step->to, buf + 2); + fputs(buf, fp); + fputc('\n', fp); } static int @@ -452,8 +390,8 @@ chc_filter(struct dirent *dir) return strstr(dir->d_name, ".poem") != NULL; } -int -chc_log_poem(void) +static int +chc_log_poem(FILE* outfp) { struct dirent **namelist; int n; @@ -470,7 +408,7 @@ chc_log_poem(void) return -1; while(fgets(buf, sizeof(buf), fp) != NULL) - chc_log(buf); + fputs(buf, outfp); while(n--) free(namelist[n]); free(namelist); @@ -478,6 +416,37 @@ chc_log_poem(void) } return 0; } + +static void +chc_genlog(ChessInfo* info, FILE* fp, ChessGameResult result) +{ + const int nStep = info->history.used; + board_t board; + int i; + + if (info->my == RED) + fprintf(fp, "%s V.S. %s\n", info->user1.userid, info->user2.userid); + else + fprintf(fp, "%s V.S. %s\n", info->user2.userid, info->user1.userid); + + chc_init_board(info, board); + for (i = 0; i < nStep; ++i) { + const drc_t *move = (const drc_t*) ChessHistoryRetrieve(info, i); + chc_log_step(fp, board, info->my, move); + chc_movechess(board, move); + } + + if (result == CHESS_RESULT_TIE) + fprintf(fp, "=> 和局\n"); + else if (result == CHESS_RESULT_WIN || result == CHESS_RESULT_LOST) + fprintf(fp, "=> %s 勝\n", + (info->my == RED) == (result== CHESS_RESULT_WIN) ? + "紅" : "黑"); + + fputs("\n--\n\n", fp); + + chc_log_poem(fp); +} /* * End of the log function. */ @@ -486,35 +455,55 @@ chc_log_poem(void) /* * Start of the rule function. */ - static void -chc_init_board(board_t board) +chc_init_board(const ChessInfo* info, board_t board) { + const int my = info->my; + memset(board, 0, sizeof(board_t)); - board[0][4] = CHE(KIND_K, chcd->my ^ 1); /* 將 */ - board[0][3] = board[0][5] = CHE(KIND_A, chcd->my ^ 1); /* 士 */ - board[0][2] = board[0][6] = CHE(KIND_E, chcd->my ^ 1); /* 象 */ - board[0][0] = board[0][8] = CHE(KIND_R, chcd->my ^ 1); /* 車 */ - board[0][1] = board[0][7] = CHE(KIND_H, chcd->my ^ 1); /* 馬 */ - board[2][1] = board[2][7] = CHE(KIND_C, chcd->my ^ 1); /* 包 */ + board[0][4] = CHE(KIND_K, my ^ 1); /* 將 */ + board[0][3] = board[0][5] = CHE(KIND_A, my ^ 1); /* 士 */ + board[0][2] = board[0][6] = CHE(KIND_E, my ^ 1); /* 象 */ + board[0][0] = board[0][8] = CHE(KIND_R, my ^ 1); /* 車 */ + board[0][1] = board[0][7] = CHE(KIND_H, my ^ 1); /* 馬 */ + board[2][1] = board[2][7] = CHE(KIND_C, my ^ 1); /* 包 */ board[3][0] = board[3][2] = board[3][4] = - board[3][6] = board[3][8] = CHE(KIND_P, chcd->my ^ 1); /* 卒 */ - - board[9][4] = CHE(KIND_K, chcd->my); /* 帥 */ - board[9][3] = board[9][5] = CHE(KIND_A, chcd->my); /* 仕 */ - board[9][2] = board[9][6] = CHE(KIND_E, chcd->my); /* 相 */ - board[9][0] = board[9][8] = CHE(KIND_R, chcd->my); /* 車 */ - board[9][1] = board[9][7] = CHE(KIND_H, chcd->my); /* 傌 */ - board[7][1] = board[7][7] = CHE(KIND_C, chcd->my); /* 炮 */ + board[3][6] = board[3][8] = CHE(KIND_P, my ^ 1); /* 卒 */ + + board[9][4] = CHE(KIND_K, my); /* 帥 */ + board[9][3] = board[9][5] = CHE(KIND_A, my); /* 仕 */ + board[9][2] = board[9][6] = CHE(KIND_E, my); /* 相 */ + board[9][0] = board[9][8] = CHE(KIND_R, my); /* 車 */ + board[9][1] = board[9][7] = CHE(KIND_H, my); /* 傌 */ + board[7][1] = board[7][7] = CHE(KIND_C, my); /* 炮 */ board[6][0] = board[6][2] = board[6][4] = - board[6][6] = board[6][8] = CHE(KIND_P, chcd->my); /* 兵 */ + board[6][6] = board[6][8] = CHE(KIND_P, my); /* 兵 */ } static void -chc_movechess(board_t board) +chc_prepare_step(ChessInfo* info, const void* step) { - board[chcd->to.r][chcd->to.c] = board[chcd->from.r][chcd->from.c]; - board[chcd->from.r][chcd->from.c] = 0; + const drc_t* move = (const drc_t*) step; + getstep((board_p) info->board, info->my, + &move->from, &move->to, info->last_movestr); +} + +static int +chc_movechess(board_t board, const drc_t* move) +{ + int end = (CHE_P(board[move->to.r][move->to.c]) == KIND_K); + + board[move->to.r][move->to.c] = board[move->from.r][move->from.c]; + board[move->from.r][move->from.c] = 0; + + return end; +} + +static void +chc_drawstep(ChessInfo* info, const drc_t* move) +{ + info->actions->drawline(info, LTR(move->from.r)); + info->actions->drawline(info, LTR(move->to.r)); } /* 求兩座標行或列(rowcol)的距離 */ @@ -550,7 +539,7 @@ between(board_t board, rc_t from, rc_t to, int rowcol) } static int -chc_canmove(board_t board, rc_t from, rc_t to) +chc_canmove(board_t board, int my, rc_t from, rc_t to) { int i; int rd, cd, turn; @@ -569,24 +558,24 @@ chc_canmove(board_t board, rc_t from, rc_t to) if (!(rd == 1 && cd == 0) && !(rd == 0 && cd == 1)) return 0; - if ((turn == (chcd->my ^ 1) && to.r > 2) || - (turn == chcd->my && to.r < 7) || + if ((turn == (my ^ 1) && to.r > 2) || + (turn == my && to.r < 7) || to.c < 3 || to.c > 5) return 0; break; case KIND_A: /* 士 仕 */ if (!(rd == 1 && cd == 1)) return 0; - if ((turn == (chcd->my ^ 1) && to.r > 2) || - (turn == chcd->my && to.r < 7) || + if ((turn == (my ^ 1) && to.r > 2) || + (turn == my && to.r < 7) || to.c < 3 || to.c > 5) return 0; break; case KIND_E: /* 象 相 */ if (!(rd == 2 && cd == 2)) return 0; - if ((turn == (chcd->my ^ 1) && to.r > 4) || - (turn == chcd->my && to.r < 5)) + if ((turn == (my ^ 1) && to.r > 4) || + (turn == my && to.r < 5)) return 0; /* 拐象腿 */ if (board[CENTER(from.r, to.r)][CENTER(from.c, to.c)]) @@ -626,12 +615,12 @@ chc_canmove(board_t board, rc_t from, rc_t to) if (!(rd == 1 && cd == 0) && !(rd == 0 && cd == 1)) return 0; - if (((turn == (chcd->my ^ 1) && to.r < 5) || - (turn == chcd->my && to.r > 4)) && + if (((turn == (my ^ 1) && to.r < 5) || + (turn == my && to.r > 4)) && cd != 0) return 0; - if ((turn == (chcd->my ^ 1) && to.r < from.r) || - (turn == chcd->my && to.r > from.r)) + if ((turn == (my ^ 1) && to.r < from.r) || + (turn == my && to.r > from.r)) return 0; break; } @@ -640,11 +629,11 @@ chc_canmove(board_t board, rc_t from, rc_t to) /* 找 turn's king 的座標 */ static void -findking(board_t board, int turn, rc_t * buf) +findking(board_t board, int my, int turn, rc_t * buf) { int i, r, c; - r = (turn == (chcd->my ^ 1)) ? 0 : 7; + r = (turn == (my ^ 1) ? 0 : 7); for (i = 0; i < 3; r++, i++) for (c = 3; c < 6; c++) if (CHE_P(board[r][c]) == KIND_K && @@ -652,75 +641,42 @@ findking(board_t board, int turn, rc_t * buf) buf->r = r, buf->c = c; return; } + assert_not_reached(); } static int -chc_iskfk(board_t board) +chc_iskfk(board_t board, int my) { rc_t from, to; - findking(board, BLK, &to); - findking(board, RED, &from); + /* the `my' here doesn't matter */ + findking(board, my, BLK, &to); + findking(board, my, RED, &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) +chc_ischeck(board_t board, int my, int turn) { rc_t from, to; - findking(board, turn, &to); + findking(board, my, 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)) + if (chc_canmove(board, my, from, to)) return 1; return 0; } - -static int -time_countdown(int who, int length) -{ - chcd->lefttime[who] -= length; - - if (!timelimit) /* traditional mode, only left time is considered */ - return chcd->lefttime[who] < 0; - - if (chcd->lefttime[who] < 0) { /* only allowed when in free time */ - if (chcd->lefthand[who]) - return 1; - chcd->lefttime[who] = timelimit->limit_time; - chcd->lefthand[who] = timelimit->limit_hand; - return 0; - } - - return 0; -} - -static void -step_made(int who) -{ - if (!timelimit) - chcd->lefttime[who] = CHC_TIMEOUT; - else if ( - (chcd->lefthand[who] && (--(chcd->lefthand[who]) == 0)) - || - (chcd->lefthand[who] == 0 && chcd->lefttime[who] <= 0) - ) { - chcd->lefthand[who] = timelimit->limit_hand; - chcd->lefttime[who] = timelimit->limit_time; - } -} - /* * End of the rule function. */ static void -chcusr_put(userec_t *userec, const chcusr_t *user) +chcusr_put(userec_t* userec, const ChessUser* user) { userec->chc_win = user->win; userec->chc_lose = user->lose; @@ -729,7 +685,7 @@ chcusr_put(userec_t *userec, const chcusr_t *user) } static void -chcusr_get(const userec_t *userec, chcusr_t *user) +chc_init_user(const userec_t *userec, ChessUser *user) { strlcpy(user->userid, userec->userid, sizeof(user->userid)); user->win = userec->chc_win; @@ -741,189 +697,91 @@ chcusr_get(const userec_t *userec, chcusr_t *user) user->orig_rating = user->rating; } + +static void +chc_prepare_play(ChessInfo* info) +{ + if (chc_ischeck((board_p) info->board, info->my, info->turn)) { + strlcpy(info->warnmsg, ANSI_COLOR(1;31) "將軍!" ANSI_RESET, + sizeof(info->warnmsg)); + bell(); + } else + info->warnmsg[0] = 0; +} + +inline static void +chc_reverse(rc_t* coor) +{ + coor->r = BRD_ROW - 1 - coor->r; + coor->c = BRD_COL - 1 - coor->c; +} + static int -hisplay(int s, const chcusr_t *user1, const chcusr_t *user2, board_t board, board_t tmpbrd) +chc_select(ChessInfo* info, rc_t location, ChessGameResult* result) { - int last_time; - int endgame = 0, endturn = 0; + chc_tag_data_t* tag = (chc_tag_data_t*) info->tag; + board_p board = (board_p) info->board; - last_time = now; - while (!endturn) { - if (time_countdown(1, now - last_time)) { - chcd->lefttime[1] = 0; + assert(tag); - /* to make him break out igetch() */ - chcd->from.r = -2; - chc_broadcast_send(chcd->act_list, board); + if (!tag->selected) { + /* trying to pick something */ + if (board[location.r][location.c] && + CHE_O(board[location.r][location.c]) == info->turn) { + /* they can pick up this */ + tag->selected = 1; + tag->select = location; + chc_drawline(info, LTR(location.r)); } - last_time = now; - chc_drawline(board, user1, user2, TIME_ROW); - move(1, 0); - oflush(); - switch (igetch()) { - case 'q': - endgame = 2; - endturn = 1; - break; - case 'p': - if (chcd->hepass) { - chcd->from.r = -1; - chc_broadcast_send(chcd->act_list, board); - endgame = 3; - endturn = 1; - } - break; - case I_OTHERDATA: - if (!chc_broadcast_recv(chcd->act_list, board)) { /* disconnect */ - endturn = 1; - endgame = 1; - } else { - if (chcd->from.r == -1) { - chcd->hepass = 1; - strlcpy(chcd->warnmsg, ANSI_COLOR(1;33) "要求和局!" ANSI_RESET, sizeof(chcd->warnmsg)); - chc_drawline(board, user1, user2, WARN_ROW); - } else { - /* 座標變換 - * (CHC_WATCH_PERSONAL 設定時 - * 表觀棋者看的棋局為單人打譜的棋局) - * 棋盤需倒置的清況才要轉換 - */ - /* 1.如果在觀棋 且棋局是別人在打譜 且輪到你 或*/ - if ( ((chcd->mode & CHC_WATCH) && (chcd->mode & CHC_WATCH_PERSONAL)) || - /* 2.自己在打譜 */ - (chcd->mode & CHC_PERSONAL) || - ((chcd->mode & CHC_WATCH) && !chcd->turn) - ) - ; // do nothing - else { - chcd->from.r = 9 - chcd->from.r, chcd->from.c = 8 - chcd->from.c; - chcd->to.r = 9 - chcd->to.r, chcd->to.c = 8 - chcd->to.c; - } - chcd->cursor = chcd->to; - if (CHE_P(board[chcd->to.r][chcd->to.c]) == KIND_K) - endgame = 2; - endturn = 1; - chcd->hepass = 0; - getstep(board, &chcd->from, &chcd->to, chcd->last_movestr); - chc_drawline(board, user1, user2, STEP_ROW); - chc_log_step(board, &chcd->from, &chcd->to); - chc_movechess(board); - step_made(1); - chc_drawline(board, user1, user2, LTR(chcd->from.r)); - chc_drawline(board, user1, user2, LTR(chcd->to.r)); - } - } - break; + return 0; + } else if (tag->select.r == location.r && tag->select.c == location.c) { + /* cancel selection */ + tag->selected = 0; + chc_drawline(info, LTR(location.r)); + return 0; + } else if (chc_canmove(board, info->my, tag->select, location)) { + /* moving the chess */ + drc_t moving = { CHESS_STEP_NORMAL, tag->select, location }; + board_t tmpbrd; + int valid_step = 1; + + if (CHE_P(board[location.r][location.c]) == KIND_K) + /* 移到對方將帥 */ + *result = CHESS_RESULT_WIN; + else { + memcpy(tmpbrd, board, sizeof(board_t)); + chc_movechess(tmpbrd, &moving); + valid_step = !chc_iskfk(tmpbrd, info->my); } - } - time_countdown(1, now - last_time); - return endgame; -} -static int -myplay(int s, const chcusr_t *user1, const chcusr_t *user2, board_t board, board_t tmpbrd) -{ - int ch, last_time; - int endgame = 0, endturn = 0; - - chcd->ipass = 0, chcd->selected = 0; - last_time = now; - bell(); - while (!endturn) { - chc_drawline(board, user1, user2, TIME_ROW); - chc_movecur(chcd->cursor.r, chcd->cursor.c); - oflush(); - ch = igetch(); - if (time_countdown(0, now - last_time)) - ch = 'q'; - last_time = now; - switch (ch) { - case I_OTHERDATA: - if (!chc_broadcast_recv(chcd->act_list, board)) { /* disconnect */ - endgame = 1; - endturn = 1; - } else if (chcd->from.r == -1 && chcd->ipass) { - endgame = 3; - endturn = 1; - } - break; - case KEY_UP: - chcd->cursor.r--; - if (chcd->cursor.r < 0) - chcd->cursor.r = BRD_ROW - 1; - break; - case KEY_DOWN: - chcd->cursor.r++; - if (chcd->cursor.r >= BRD_ROW) - chcd->cursor.r = 0; - break; - case KEY_LEFT: - chcd->cursor.c--; - if (chcd->cursor.c < 0) - chcd->cursor.c = BRD_COL - 1; - break; - case KEY_RIGHT: - chcd->cursor.c++; - if (chcd->cursor.c >= BRD_COL) - chcd->cursor.c = 0; - break; - case 'q': - endgame = 2; - endturn = 1; - break; - case 'p': - chcd->ipass = 1; - chcd->from.r = -1; - chc_broadcast_send(chcd->act_list, board); - strlcpy(chcd->warnmsg, ANSI_COLOR(1;33) "要求和棋!" ANSI_RESET, sizeof(chcd->warnmsg)); - chc_drawline(board, user1, user2, WARN_ROW); + if (valid_step) { + getstep(board, info->my, &moving.from, &moving.to, info->last_movestr); + + chc_movechess(board, &moving); + chc_drawline(info, LTR(moving.from.r)); + chc_drawline(info, LTR(moving.to.r)); + + ChessHistoryAppend(info, &moving); + ChessStepBroadcast(info, &moving); + + chc_reverse(&moving.from); + chc_reverse(&moving.to); + ChessStepSendOpposite(info, &moving); + + tag->selected = 0; + return 1; + } else { + /* 王見王 */ + strlcpy(info->warnmsg, + ANSI_COLOR(1;33) "不可以王見王" ANSI_RESET, + sizeof(info->warnmsg)); bell(); - break; - case '\r': - case '\n': - case ' ': - if (chcd->selected) { - if (chcd->cursor.r == chcd->select.r && - chcd->cursor.c == chcd->select.c) { - chcd->selected = 0; - chc_drawline(board, user1, user2, LTR(chcd->cursor.r)); - } else if (chc_canmove(board, chcd->select, chcd->cursor)) { - if (CHE_P(board[chcd->cursor.r][chcd->cursor.c]) == KIND_K) - endgame = 1; - chcd->from = chcd->select; - chcd->to = chcd->cursor; - if (!endgame) { - memcpy(tmpbrd, board, sizeof(board_t)); - chc_movechess(tmpbrd); - } - if (endgame || !chc_iskfk(tmpbrd)) { - getstep(board, &chcd->from, &chcd->to, chcd->last_movestr); - chc_drawline(board, user1, user2, STEP_ROW); - chc_log_step(board, &chcd->from, &chcd->to); - chc_movechess(board); - step_made(0); - chc_broadcast_send(chcd->act_list, board); - chcd->selected = 0; - chc_drawline(board, user1, user2, LTR(chcd->from.r)); - chc_drawline(board, user1, user2, LTR(chcd->to.r)); - endturn = 1; - } else { - strlcpy(chcd->warnmsg, ANSI_COLOR(1;33) "不可以王見王" ANSI_RESET, sizeof(chcd->warnmsg)); - bell(); - chc_drawline(board, user1, user2, WARN_ROW); - } - } - } else if (board[chcd->cursor.r][chcd->cursor.c] && - CHE_O(board[chcd->cursor.r][chcd->cursor.c]) == chcd->turn) { - chcd->selected = 1; - chcd->select = chcd->cursor; - chc_drawline(board, user1, user2, LTR(chcd->cursor.r)); - } - break; + chc_drawline(info, WARN_ROW); + return 0; } - } - time_countdown(0, now - last_time); - return endgame; + } else + /* nothing happened */ + return 0; } int round_to_int(double x) @@ -933,13 +791,13 @@ int round_to_int(double x) return (int)(x+0.5); return (int)(x-0.5); } - + /* * ELO rating system * see http://www.wordiq.com/definition/ELO_rating_system */ static void -count_chess_elo_rating(chcusr_t *user1, const chcusr_t *user2, double myres) +count_chess_elo_rating(ChessUser* user1, const ChessUser* user2, double myres) { double k; double exp_res; @@ -972,54 +830,71 @@ count_chess_elo_rating(chcusr_t *user1, const chcusr_t *user2, double myres) user1->rating = newrating; } + +/* 象棋功能進入點: + * chc_main: 對奕 + * chc_personal: 打譜 + * chc_watch: 觀棋 + * talk.c: 對奕 + */ +void +chc(int s, ChessGameMode mode) +{ + ChessInfo* info = NewChessInfo(&chc_actions, &chc_constants, s, mode); + board_t board; + chc_tag_data_t tag; + + chc_init_board(info, board); + tag.selected = 0; + + info->board = board; + info->tag = &tag; + + if (mode == CHESS_MODE_WATCH) + setutmpmode(CHESSWATCHING); + else + setutmpmode(CHC); + + ChessPlay(info); + + DeleteChessInfo(info); +} + static void -mainloop(int s, chcusr_t *user1, chcusr_t *user2, board_t board, play_func_t play_func[2]) +chc_gameend(ChessInfo* info, ChessGameResult result) { - int endgame; - char buf[80]; - board_t tmpbrd; - - if (!(chcd->mode & CHC_WATCH)) - chcd->turn = 1; - for (endgame = 0; !endgame; chcd->turn ^= 1) { - chcd->firststep = 0; - chc_drawline(board, user1, user2, TURN_ROW); - if (chc_ischeck(board, chcd->turn)) { - strlcpy(chcd->warnmsg, ANSI_COLOR(1;31) "將軍!" ANSI_RESET, sizeof(chcd->warnmsg)); - bell(); - } else - chcd->warnmsg[0] = 0; - chc_drawline(board, user1, user2, WARN_ROW); - endgame = play_func[chcd->turn] (s, user1, user2, board, tmpbrd); - } + ChessUser* const user1 = &info->user1; + ChessUser* const user2 = &info->user2; - if (chcd->mode & CHC_VERSUS) { - user1->rating = user1->orig_rating; - user1->lose--; - if(chcd->my==RED) { + if (info->mode == CHESS_MODE_VERSUS) { + if (info->my == RED) { /* 由紅方作 log. 記的是下棋前的原始分數 */ /* NOTE, 若紅方斷線則無 log */ - time_t t=time(NULL); + time_t t = time(NULL); char buf[100]; - sprintf(buf, "%s %s(%d,W%d/D%d/L%d) %s %s(%d,W%d/D%d/L%d)\n", ctime(&t), - user1->userid, user1->rating, user1->win, user1->tie, user1->lose, - (endgame==3?"和":endgame==1?"勝":"負"), - user2->userid, user2->rating, user2->win, user2->tie, user2->lose); - buf[24]=' '; // replace '\n' - log_file(BBSHOME"/log/chc.log", LOG_CREAT, buf); + sprintf(buf, "%s %s(%d,W%d/D%d/L%d) %s %s(%d,W%d/D%d/L%d)\n", + ctime(&t), + user1->userid, user1->rating, user1->win, + user1->tie, user1->lose, + (result == CHESS_RESULT_TIE ? "和" : + result == CHESS_RESULT_WIN ? "勝" : "負"), + user2->userid, user2->rating, user2->win, + user2->tie, user2->lose); + buf[24] = ' '; // replace '\n' + log_file(BBSHOME "/log/chc.log", LOG_CREAT, buf); } - if (endgame == 1) { - strlcpy(chcd->warnmsg, "對方認輸了!", sizeof(chcd->warnmsg)); + + user1->rating = user1->orig_rating; + user1->lose--; + if (result == CHESS_RESULT_WIN) { count_chess_elo_rating(user1, user2, 1.0); user1->win++; currutmp->chc_win++; - } else if (endgame == 2) { - strlcpy(chcd->warnmsg, "你認輸了!", sizeof(chcd->warnmsg)); + } else if (result == CHESS_RESULT_LOST) { count_chess_elo_rating(user1, user2, 0.0); user1->lose++; currutmp->chc_lose++; } else { - strlcpy(chcd->warnmsg, "和棋", sizeof(chcd->warnmsg)); count_chess_elo_rating(user1, user2, 0.5); user1->tie++; currutmp->chc_tie++; @@ -1028,547 +903,23 @@ mainloop(int s, chcusr_t *user1, chcusr_t *user2, board_t board, play_func_t pla chcusr_put(&cuser, user1); passwd_update(usernum, &cuser); } - else if (chcd->mode & CHC_WATCH) { - strlcpy(chcd->warnmsg, "結束觀棋", sizeof(chcd->warnmsg)); - } - else { - strlcpy(chcd->warnmsg, "結束打譜", sizeof(chcd->warnmsg)); - } - - chc_log("=> "); - if (endgame == 3) - chc_log("和局"); - else{ - sprintf(buf, "%s勝\n", (chcd->my==RED) == (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]; - userec_t xuser; - - if (chcd->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 (chcd->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[chcd->my] = myplay; - play_func[chcd->my ^ 1] = hisplay; - } - - getuser(userid[0], &xuser); - chcusr_get(&xuser, user1); - getuser(userid[1], &xuser); - chcusr_get(&xuser, user2); -} - -static void -chc_init_photo(void) -{ - char genbuf[256]; - int line; - FILE* fp; - static const char * const blank_photo[6] = { - "┌──────┐", - "│ 空 │", - "│ 白 │", - "│ 照 │", - "│ 片│", - "└──────┘" - }; - char country[5], level[11]; - userec_t xuser; - - chcd->photo = NULL; - if (!(chcd->mode & CHC_VERSUS)) - return; - - setuserfile(genbuf, "photo_cchess"); - if (!dashf(genbuf)) { - sethomefile(genbuf, currutmp->mateid, "photo_cchess"); - if (!dashf(genbuf)) - return; - } - - chcd->photo = (char*) calloc(PHOTO_LINE * PHOTO_COLUMN, sizeof(char)); - - /* yack, but I copied these from gomo.c (scw) */ - setuserfile(genbuf, "photo_cchess"); - fp = fopen(genbuf, "r"); - - if (fp == NULL) { - strcpy(country, "無"); - level[0] = 0; - } else { - int i, j; - for (line = 1; line < 8; ++line) - fgets(genbuf, sizeof(genbuf), fp); - - fgets(genbuf, sizeof(genbuf), fp); - chomp(genbuf); - strip_ansi(genbuf + 11, genbuf + 11, - STRIP_ALL); /* country name may have color */ - for (i = 11, j = 0; genbuf[i] && j < 4; ++i) - if (genbuf[i] != ' ') /* and spaces */ - country[j++] = genbuf[i]; - country[j] = 0; /* two chinese words */ - - fgets(genbuf, sizeof(genbuf), fp); - chomp(genbuf); - strlcpy(level, genbuf + 11, 11); /* five chinese words*/ - rewind(fp); - } - - /* simulate chcd->photo as two dimensional array */ -#define PHOTO(X) (chcd->photo + (X) * PHOTO_COLUMN) - for (line = 0; line < 6; ++line) { - if (fp != NULL) { - if (fgets(genbuf, sizeof(genbuf), fp)) { - chomp(genbuf); - sprintf(PHOTO(line), "%s ", genbuf); - } else - strcpy(PHOTO(line), " "); - } else - strcpy(PHOTO(line), blank_photo[line]); - - switch (line) { - case 0: sprintf(genbuf, "<代號> %s", cuser.userid); break; - case 1: sprintf(genbuf, "<暱稱> %.16s", cuser.nickname); break; - case 2: sprintf(genbuf, "<上站> %d", cuser.numlogins); break; - case 3: sprintf(genbuf, "<文章> %d", cuser.numposts); break; - case 4: sprintf(genbuf, "<職位> %-4s %s", country, level); break; - case 5: sprintf(genbuf, "<來源> %.16s", cuser.lasthost); break; - default: genbuf[0] = 0; - } - strcat(PHOTO(line), genbuf); - } - if (fp != NULL) - fclose(fp); - - sprintf(PHOTO(6), " %s%2.2s棋" ANSI_RESET, - turn_color[chcd->my], turn_str[chcd->my]); - strcpy(PHOTO(7), " V.S "); - sprintf(PHOTO(8), " %s%2.2s棋" ANSI_RESET, - turn_color[chcd->my ^ 1], turn_str[chcd->my ^ 1]); - - getuser(currutmp->mateid, &xuser); - sethomefile(genbuf, currutmp->mateid, "photo_cchess"); - fp = fopen(genbuf, "r"); - - if (fp == NULL) { - strcpy(country, "無"); - level[0] = 0; - } else { - int i, j; - for (line = 1; line < 8; ++line) - fgets(genbuf, sizeof(genbuf), fp); - - fgets(genbuf, sizeof(genbuf), fp); - chomp(genbuf); - strip_ansi(genbuf + 11, genbuf + 11, - STRIP_ALL); /* country name may have color */ - for (i = 11, j = 0; genbuf[i] && j < 4; ++i) - if (genbuf[i] != ' ') /* and spaces */ - country[j++] = genbuf[i]; - country[j] = 0; /* two chinese words */ - - fgets(genbuf, sizeof(genbuf), fp); - chomp(genbuf); - strlcpy(level, genbuf + 11, 11); /* five chinese words*/ - rewind(fp); - } - - for (line = 9; line < 15; ++line) { - move(line, 37); - switch (line - 9) { - case 0: sprintf(PHOTO(line), "<代號> %-16.16s ", xuser.userid); break; - case 1: sprintf(PHOTO(line), "<暱稱> %-16.16s ", xuser.nickname); break; - case 2: sprintf(PHOTO(line), "<上站> %-16d ", xuser.numlogins); break; - case 3: sprintf(PHOTO(line), "<文章> %-16d ", xuser.numposts); break; - case 4: sprintf(PHOTO(line), "<職位> %-4s %-10s ", country, level); break; - case 5: sprintf(PHOTO(line), "<來源> %-16.16s ", xuser.lasthost); break; - } - - if (fp != NULL) { - if (fgets(genbuf, 200, fp)) { - chomp(genbuf); - strcat(PHOTO(line), genbuf); - } else - strcat(PHOTO(line), " "); - } else - strcat(PHOTO(line), blank_photo[line - 9]); - } - if (fp != NULL) - fclose(fp); - -#undef PHOTO -} - -static void -chc_watch_request(int signo) -{ - chc_act_list *tmp; -#if _TO_SYNC_ - sigset_t mask; -#endif - - if (!(currstat & CHC)) - return; - if(chcd == NULL) return; - for(tmp = chcd->act_list; tmp->next != NULL; tmp = tmp->next); // XXX 一定要接在最後嗎? - tmp->next = (chc_act_list *)malloc(sizeof(chc_act_list)); - tmp->next->sock = establish_talk_connection(&SHM->uinfo[currutmp->destuip]); - if (tmp->next->sock < 0) { - free(tmp->next); - tmp->next = NULL; - return; - } - - tmp = tmp->next; - tmp->next = NULL; - -#if _TO_SYNC_ - /* 借用 SIGALRM */ - sigfillset(&mask); - sigdelset(&mask, SIGALRM); - sigsuspend(&mask); -#endif - - /* what if the spectator get off-line intentionally !? (SIGPIPE) */ - write(tmp->sock, chcd->bp, sizeof(board_t)); - write(tmp->sock, &chcd->my, sizeof(chcd->my)); - write(tmp->sock, &chcd->turn, sizeof(chcd->turn)); - write(tmp->sock, &currutmp->turn, sizeof(currutmp->turn)); - write(tmp->sock, &chcd->firststep, sizeof(chcd->firststep)); - write(tmp->sock, &chcd->mode, sizeof(chcd->mode)); -} - -static int -chc_init(int s, chcusr_t *user1, chcusr_t *user2, board_t board, play_func_t play_func[2]) -{ - userinfo_t *my = currutmp; - userec_t xuser; - - if (chcd->mode & CHC_WATCH) - setutmpmode(CHESSWATCHING); - else - setutmpmode(CHC); - clear(); - chcd->warnmsg[0] = 0; - - /* 從不同來源初始化各個變數 */ - if (!(chcd->mode & CHC_WATCH)) { - if (chcd->mode & CHC_PERSONAL) - chcd->my = RED; - else - chcd->my = my->turn; - chcd->firststep = 1; - chc_init_board(board); - chcd->cursor.r = 9, chcd->cursor.c = 0; - } - else { - char mode; - userinfo_t *uin = &SHM->uinfo[currutmp->destuip]; - if (uin == NULL) - return -1; -#if _TO_SYNC_ - // choose one signal execpt SIGUSR1 - kill(uin->pid, SIGALRM); -#endif - if(read(s, board, sizeof(board_t)) != sizeof(board_t) || - read(s, &chcd->my, sizeof(chcd->my)) != sizeof(chcd->my) || - read(s, &chcd->turn, sizeof(chcd->turn)) != sizeof(chcd->turn) || - read(s, &my->turn, sizeof(my->turn)) != sizeof(my->turn) || - read(s, &chcd->firststep, sizeof(chcd->firststep)) - != sizeof(chcd->firststep) || - read(s, &mode, sizeof(mode)) != sizeof(mode)){ - add_io(0, 0); - close(s); - return -1; - } - if (mode & CHC_PERSONAL) - chcd->mode |= CHC_WATCH_PERSONAL; - } - - chc_init_photo(); - - chcd->act_list = (chc_act_list *)malloc(sizeof(*chcd->act_list)); - chcd->act_list->sock = s; - chcd->act_list->next = 0; - - chc_init_play_func(user1, user2, play_func); - - chc_redraw(user1, user2, board); - add_io(s, 0); - - if (!(chcd->mode & CHC_WATCH)) { - Signal(SIGUSR1, chc_watch_request); - } - -// if (my->turn && !(chcd->mode & CHC_WATCH)) -// chc_broadcast_recv(chcd->act_list, board); - - if (chcd->mode & CHC_VERSUS) { - user1->lose++; - count_chess_elo_rating(user1, user2, 0.0); - passwd_query(usernum, &xuser); - chcusr_put(&xuser, user1); - passwd_update(usernum, &xuser); - - /* exchanging timing information */ - if (my->turn) { - char mode; - read(s, &mode, 1); - if (mode == 'L') { - timelimit = (CHCTimeLimit*) malloc(sizeof(CHCTimeLimit)); - read(s, timelimit, sizeof(CHCTimeLimit)); - } else - timelimit = NULL; - } else { - if (!timelimit) - write(s, "T", 1); /* traditional */ - else { - write(s, "L", 1); /* limited */ - write(s, timelimit, sizeof(CHCTimeLimit)); - } - } - } - - if (!my->turn) { - if (!(chcd->mode & CHC_WATCH)) - chc_broadcast_send(chcd->act_list, board); - if (chcd->mode & CHC_VERSUS) - user2->lose++; - } - - chcd->lefthand[0] = chcd->lefthand[1] = 0; - chcd->lefttime[0] = chcd->lefttime[1] = - timelimit ? timelimit->free_time : CHC_TIMEOUT; - - chc_redraw(user1, user2, board); - - return 0; -} - -/* 象棋功能進入點: - * chc_main: 對奕 - * chc_personal: 打譜 - * chc_watch: 觀棋 - * talk.c: 對奕 - */ -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]; - - if(chcd != NULL) { - vmsg("象棋功\能異常"); - return; - } - chcd = (struct CHCData*)malloc(sizeof(struct CHCData)); - if(chcd == NULL) { - vmsg("執行象棋功\能失敗"); - return; - } - memset(chcd, 0, sizeof(struct CHCData)); - chcd->mode = mode; - - if (!(chcd->mode & CHC_WATCH)) - Signal(SIGUSR1, SIG_IGN); - - chcd->bp = &board; - if (chc_init(s, &user1, &user2, board, play_func) < 0) { - free(chcd); - chcd = NULL; - return; - } - - setuserfile(file, CHC_LOG); - if (chc_log_open(&user1, &user2, file) < 0) - vmsg("無法紀錄棋局"); - - mainloop(s, &user1, &user2, board, play_func); - - /* close these fd */ - if (chcd->mode & CHC_PERSONAL) - chcd->act_list = chcd->act_list->next; - while(chcd->act_list){ - close(chcd->act_list->sock); - chcd->act_list = chcd->act_list->next; - } - - add_io(0, 0); - if (chcd->my == RED) - pressanykey(); - - currutmp->mode = mode0; - - if (getans("是否將棋譜寄回信箱?[N/y]") == 'y') { - char title[80]; - if(chcd->my == RED) - sprintf(title, "%s V.S. %s", user1.userid, user2.userid); - else - sprintf(title, "%s V.S. %s", user2.userid, user1.userid); - chc_log("\n--\n\n"); - chc_log_poem(); - chc_log_close(); - mail_id(cuser.userid, title, file, "[楚河漢界]"); - } - else - chc_log_close(); - - if (!(chcd->mode & CHC_WATCH)) - Signal(SIGUSR1, talk_request); - - if (timelimit) - free(timelimit); - if (chcd->photo) - free(chcd->photo); - free(chcd); - chcd = NULL; - timelimit = NULL; -} - -static userinfo_t * -chc_init_utmp(void) -{ - char uident[16]; - userinfo_t *uin; - - stand_title("楚河漢界之爭"); - CompleteOnlineUser(msg_uid, uident); - 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; - char buf[4]; - - 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)); - - stand_title("象棋邀局"); - buf[0] = 0; - getdata(2, 0, "使用傳統模式 (T), 限時限步模式 (L) 或是 讀秒模式 (C)? (T/l/c)", - buf, 3, DOECHO); - if (buf[0] == 'l' || buf[0] == 'L') { - char display_buf[128]; - - timelimit = (CHCTimeLimit*) malloc(sizeof(CHCTimeLimit)); - do { - getdata_str(3, 0, "請設定局時 (自由時間) 以分鐘為單位:", - buf, 3, DOECHO, "30"); - timelimit->free_time = atoi(buf); - } while (timelimit->free_time < 0 || timelimit->free_time > 90); - timelimit->free_time *= 60; /* minute -> second */ - - do { - getdata_str(4, 0, "請設定步時, 以分鐘為單位:", - buf, 3, DOECHO, "5"); - timelimit->limit_time = atoi(buf); - } while (timelimit->limit_time < 0 || timelimit->limit_time > 30); - timelimit->limit_time *= 60; /* minute -> second */ - - snprintf(display_buf, sizeof(display_buf), - "請設定限步 (每 %d 分鐘需走幾步):", - timelimit->limit_time / 60); - do { - getdata_str(5, 0, display_buf, buf, 3, DOECHO, "10"); - timelimit->limit_hand = atoi(buf); - } while (timelimit->limit_hand < 1); - } else if (buf[0] == 'c' || buf[0] == 'C') { - timelimit = (CHCTimeLimit*) malloc(sizeof(CHCTimeLimit)); - do { - getdata_str(3, 0, "請設定局時 (自由時間) 以分鐘為單位:", - buf, 3, DOECHO, "30"); - timelimit->free_time = atoi(buf); - } while (timelimit->free_time < 0 || timelimit->free_time > 90); - timelimit->free_time *= 60; /* minute -> second */ - - timelimit->limit_hand = 1; - - do { - getdata_str(4, 0, "請設定讀秒, 以秒為單位", - buf, 3, DOECHO, "60"); - timelimit->limit_time = atoi(buf); - } while (timelimit->limit_time < 0); - } else - timelimit = NULL; - - my_talk(uin, friend_stat(currutmp, uin), 'c'); - return 0; + return ChessStartGame('c', SIG_CHC, "楚河漢界之爭"); } int chc_personal(void) { - chc(0, CHC_PERSONAL); + chc(0, CHESS_MODE_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 (getans("是否進行觀棋? [N/y]") != 'y') - return 0; - - if ((sock = make_connection_to_somebody(uin, 10)) < 0) { - vmsg("無法建立連線"); - return -1; - } -#if defined(Solaris) && __OS_MAJOR_VERSION__ == 5 && __OS_MINOR_VERSION__ < 7 - msgsock = accept(sock, (struct sockaddr *) 0, 0); -#else - msgsock = accept(sock, (struct sockaddr *) 0, (socklen_t *) 0); -#endif - close(sock); - if (msgsock < 0) - return -1; - - strlcpy(currutmp->mateid, uin->userid, sizeof(currutmp->mateid)); - chc(msgsock, CHC_WATCH); - close(msgsock); - return 0; + return ChessWatchGame(&chc, CHC, "楚河漢界之爭"); } |