diff options
author | scw <scw@63ad8ddf-47c3-0310-b6dd-a9e9d9715204> | 2005-08-15 14:26:17 +0800 |
---|---|---|
committer | scw <scw@63ad8ddf-47c3-0310-b6dd-a9e9d9715204> | 2005-08-15 14:26:17 +0800 |
commit | 98f0f5e0a45c6771ce43d69a13aa9b9ecce3faf9 (patch) | |
tree | 319ebe57c18b21b8f31c95cd92626163e472b7e2 | |
parent | 5936d5aa8dd56d023c8aa475ac0505406af88268 (diff) | |
download | pttbbs-98f0f5e0a45c6771ce43d69a13aa9b9ecce3faf9.tar pttbbs-98f0f5e0a45c6771ce43d69a13aa9b9ecce3faf9.tar.gz pttbbs-98f0f5e0a45c6771ce43d69a13aa9b9ecce3faf9.tar.bz2 pttbbs-98f0f5e0a45c6771ce43d69a13aa9b9ecce3faf9.tar.lz pttbbs-98f0f5e0a45c6771ce43d69a13aa9b9ecce3faf9.tar.xz pttbbs-98f0f5e0a45c6771ce43d69a13aa9b9ecce3faf9.tar.zst pttbbs-98f0f5e0a45c6771ce43d69a13aa9b9ecce3faf9.zip |
Gomoku convertion to chess.c framework
* versus, watching and personal playing
* undo function removed due to the restriction of
the framework currently
chess.c framework update
* resign confirm
* invited peer can be watched
!!!NOTE!!! Gomoku protocal not backward compatible
RESTART WHOLE system to ensure correctness
git-svn-id: http://opensvn.csie.org/pttbbs/trunk/pttbbs@3036 63ad8ddf-47c3-0310-b6dd-a9e9d9715204
-rw-r--r-- | include/chc.h | 15 | ||||
-rw-r--r-- | include/chess.h | 4 | ||||
-rw-r--r-- | include/gomo.h | 4 | ||||
-rw-r--r-- | include/proto.h | 5 | ||||
-rw-r--r-- | mbbsd/chc.c | 133 | ||||
-rw-r--r-- | mbbsd/chess.c | 242 | ||||
-rw-r--r-- | mbbsd/gomo.c | 917 | ||||
-rw-r--r-- | mbbsd/menu.c | 11 | ||||
-rw-r--r-- | mbbsd/talk.c | 21 | ||||
-rw-r--r-- | mbbsd/var.c | 4 |
10 files changed, 551 insertions, 805 deletions
diff --git a/include/chc.h b/include/chc.h index 900d4dd1..8b7fb23b 100644 --- a/include/chc.h +++ b/include/chc.h @@ -1,20 +1,6 @@ -#define SIDE_ROW 7 -#define REAL_TURN_ROW 8 -#define STEP_ROW 9 -#define REAL_TIME_ROW1 10 -#define REAL_TIME_ROW2 11 -#define REAL_WARN_ROW 13 -#define MYWIN_ROW 17 -#define HISWIN_ROW 18 - -#define PHOTO_TURN_ROW 19 -#define PHOTO_TIME_ROW1 20 -#define PHOTO_TIME_ROW2 21 -#define PHOTO_WARN_ROW 22 #define CHE_O(c) ((c) >> 3) #define CHE_P(c) ((c) & 7) -#define dim(x) (sizeof(x) / sizeof(x[0])) #define CHE(a, b) ((a) | ((b) << 3)) /* TODO let user flip chessboard */ #define REDDOWN(info) ((info)->myturn==RED) @@ -26,7 +12,6 @@ #define RED_COLOR ANSI_COLOR(1;31) #define BLACK_REVERSE ANSI_COLOR(1;37;46) #define RED_REVERSE ANSI_COLOR(1;37;41) -#define TURN_COLOR ANSI_COLOR(1;33) #define BRD_ROW 10 #define BRD_COL 9 diff --git a/include/chess.h b/include/chess.h index bf9443ce..a917efcc 100644 --- a/include/chess.h +++ b/include/chess.h @@ -143,6 +143,7 @@ typedef struct ChessConstants { int traditional_timeout; int board_height; int board_width; + const char *chess_name; const char *photo_file_name; const char *log_board; const char *turn_color[2]; @@ -180,4 +181,7 @@ void ChessEstablishRequest(int sock); void ChessAcceptingRequest(int sock); void ChessShowRequest(void); +void ChessDrawLine(const ChessInfo* info, int line); +void ChessDrawExtraInfo(const ChessInfo* info, int line); + #endif /* INCLUDE_CHESS_H */ diff --git a/include/gomo.h b/include/gomo.h index b1228ba8..b5e8d014 100644 --- a/include/gomo.h +++ b/include/gomo.h @@ -3,9 +3,9 @@ #ifndef _INCLUDE_GOMO_H #define _INCLUDE_GOMO_H -#define BBLANK (0) /* 空白 */ +#define BBLANK (-1) /* 空白 */ +#define BWHITE (0) /* 白子, 後手 */ #define BBLACK (1) /* 黑子, 先手 */ -#define BWHITE (2) /* 白子, 後手 */ #define MAX_TIME (300) /*最長idle秒數*/ #ifndef BRDSIZ #define BRDSIZ (15) /* 棋盤單邊大小 */ diff --git a/include/proto.h b/include/proto.h index c20be401..a39a65c7 100644 --- a/include/proto.h +++ b/include/proto.h @@ -293,7 +293,10 @@ int gochess(int fd); int GoBot(void); /* gomo */ -int gomoku(int fd); +void gomoku(int s, ChessGameMode mode); +int gomoku_main(void); +int gomoku_personal(void); +int gomoku_watch(void); /* guess */ int guess_main(void); diff --git a/mbbsd/chc.c b/mbbsd/chc.c index 40b190fa..f1339e14 100644 --- a/mbbsd/chc.c +++ b/mbbsd/chc.c @@ -116,6 +116,7 @@ static const ChessConstants chc_constants = { CHC_TIMEOUT, BRD_ROW, BRD_COL, + "楚河漢界", "photo_cchess", #ifdef GLOBAL_CCHESS_LOG GLOBAL_CCHESS_LOG, @@ -194,12 +195,6 @@ getstep(board_t board, const rc_t *from, const rc_t *to, char buf[]) return buf; } -static void -showstep(const ChessInfo* info) -{ - outs(info->last_movestr); -} - inline static const char* chc_timestr(int second) { @@ -215,22 +210,6 @@ chc_drawline(const ChessInfo* info, int line) 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) { - if(info->photo) { - chc_drawline(info, PHOTO_TIME_ROW1); - chc_drawline(info, PHOTO_TIME_ROW2); - } else { - chc_drawline(info, REAL_TIME_ROW1); - chc_drawline(info, REAL_TIME_ROW2); - } - return; - } 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) { @@ -271,100 +250,7 @@ chc_drawline(const ChessInfo* info, int line) prints("%s ", num_str[REDDOWN(info)?1:0][i]); } - if (info->photo) { - if (line >= 3 && line < 3 + CHESS_PHOTO_LINE) { - outs(" "); - 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, - info->myturn == info->turn ? "輪到你下棋了" : "等待對方下棋"); - else if (line == PHOTO_TIME_ROW1) { - 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("我方剩餘時間 %s", - chc_timestr(info->lefttime[0])); - } else if (line == PHOTO_TIME_ROW2) { - 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("對方剩餘時間 %s", - chc_timestr(info->lefttime[1])); - } else if (line == PHOTO_WARN_ROW) - outs(info->warnmsg); - } - } else if (line >= 3 && line <= HISWIN_ROW) { - outs(" "); - if (line >= 3 && line < 3 + (int)dim(hint_str)) { - outs(hint_str[line - 3]); - } else if (line == SIDE_ROW) { - prints(ANSI_COLOR(1) "你是%s%s" ANSI_RESET, - turn_color[(int) info->myturn], - turn_str[(int) info->myturn]); - } else if (line == REAL_TURN_ROW) { - prints("%s%s" ANSI_RESET, - TURN_COLOR, - info->myturn == info->turn ? "輪到你下棋了" : "等待對方下棋"); - } else if (line == STEP_ROW && info->last_movestr) { - showstep(info); - } else if (line == REAL_TIME_ROW1) { - if (info->lefthand[0]) - prints("我方剩餘時間 %s / %2d 步", - chc_timestr(info->lefttime[0]), - info->lefthand[0]); - else - prints("我方剩餘時間 %s", - chc_timestr(info->lefttime[0])); - } else if (line == REAL_TIME_ROW2) { - if (info->lefthand[1]) - prints("對方剩餘時間 %s / %2d 步", - chc_timestr(info->lefttime[1]), - info->lefthand[1]); - else - prints("對方剩餘時間 %s", - chc_timestr(info->lefttime[1])); - } else if (line == REAL_WARN_ROW) { - 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, - 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, - info->user2.userid, - info->user2.win, info->user2.lose, info->user2.tie); - } - } + ChessDrawExtraInfo(info, line); } /* * End of the drawing function. @@ -511,8 +397,8 @@ chc_movechess(board_t board, const drc_t* move) static void chc_drawstep(ChessInfo* info, const drc_t* move) { - info->actions->drawline(info, LTR(info, move->from.r)); - info->actions->drawline(info, LTR(info, move->to.r)); + ChessDrawLine(info, LTR(info, move->from.r)); + ChessDrawLine(info, LTR(info, move->to.r)); } /* 求兩座標行或列(rowcol)的距離 */ @@ -748,13 +634,13 @@ chc_select(ChessInfo* info, rc_t scrloc, ChessGameResult* result) /* they can pick up this */ tag->selected = 1; tag->select = loc; - chc_drawline(info, LTR(info, loc.r)); + ChessDrawLine(info, LTR(info, loc.r)); } return 0; } else if (tag->select.r == loc.r && tag->select.c == loc.c) { /* cancel selection */ tag->selected = 0; - chc_drawline(info, LTR(info, loc.r)); + ChessDrawLine(info, LTR(info, loc.r)); return 0; } else if (chc_canmove(board, tag->select, loc)) { /* moving the chess */ @@ -775,8 +661,8 @@ chc_select(ChessInfo* info, rc_t scrloc, ChessGameResult* result) getstep(board, &moving.from, &moving.to, info->last_movestr); chc_movechess(board, &moving); - chc_drawline(info, LTR(info, moving.from.r)); - chc_drawline(info, LTR(info, moving.to.r)); + ChessDrawLine(info, LTR(info, moving.from.r)); + ChessDrawLine(info, LTR(info, moving.to.r)); ChessHistoryAppend(info, &moving); ChessStepSend(info, &moving); @@ -789,7 +675,7 @@ chc_select(ChessInfo* info, rc_t scrloc, ChessGameResult* result) ANSI_COLOR(1;33) "不可以王見王" ANSI_RESET, sizeof(info->warnmsg)); bell(); - chc_drawline(info, REAL_WARN_ROW); + ChessDrawLine(info, CHESS_DRAWING_WARN_ROW); return 0; } } else @@ -876,6 +762,7 @@ chc(int s, ChessGameMode mode) setutmpmode(CHESSWATCHING); else setutmpmode(CHC); + currutmp->sig = SIG_CHC; ChessPlay(info); diff --git a/mbbsd/chess.c b/mbbsd/chess.c index 7453a78f..1b585f12 100644 --- a/mbbsd/chess.c +++ b/mbbsd/chess.c @@ -3,10 +3,33 @@ #include "chess.h" #define assert_not_reached() assert(!"Should never be here!!!") +#define dim(x) (sizeof(x) / sizeof(x[0])) #define CHESS_HISTORY_INITIAL_BUFFER_SIZE 300 #define CHESS_HISTORY_BUFFER_INCREMENT 50 +#define CHESS_DRAWING_SIDE_ROW 7 +#define CHESS_DRAWING_REAL_TURN_ROW 8 +#define CHESS_DRAWING_REAL_STEP_ROW 9 +#define CHESS_DRAWING_REAL_TIME_ROW1 10 +#define CHESS_DRAWING_REAL_TIME_ROW2 11 +#define CHESS_DRAWING_REAL_WARN_ROW 13 +#define CHESS_DRAWING_MYWIN_ROW 17 +#define CHESS_DRAWING_HISWIN_ROW 18 +#define CHESS_DRAWING_PHOTOED_TURN_ROW 19 +#define CHESS_DRAWING_PHOTOED_TIME_ROW1 20 +#define CHESS_DRAWING_PHOTOED_TIME_ROW2 21 +#define CHESS_DRAWING_PHOTOED_WARN_ROW 22 +#define CHESS_DRAWING_PHOTOED_STEP_ROW 23 + + +static const char * const ChessHintStr[] = { + " q 認輸離開", + " p 要求和棋", + "方向鍵 移動遊標", + "Enter 選擇/移動" +}; + static ChessInfo * CurrentPlayingGameInfo; /* XXX: This is a BAD way to pass information. @@ -115,6 +138,34 @@ ChessDrawHelpLine(const ChessInfo* info) mouts(b_lines, 0, HelpStr[info->mode]); } +void +ChessDrawLine(const ChessInfo* info, int line) +{ + if (line == b_lines) + ChessDrawHelpLine(info); + else if (line == CHESS_DRAWING_TURN_ROW) + line = info->photo ? + CHESS_DRAWING_PHOTOED_TURN_ROW : + CHESS_DRAWING_REAL_TURN_ROW; + else if (line == CHESS_DRAWING_TIME_ROW) { + if(info->photo) { + info->actions->drawline(info, CHESS_DRAWING_PHOTOED_TIME_ROW1); + info->actions->drawline(info, CHESS_DRAWING_PHOTOED_TIME_ROW2); + } else { + info->actions->drawline(info, CHESS_DRAWING_REAL_TIME_ROW1); + info->actions->drawline(info, CHESS_DRAWING_REAL_TIME_ROW2); + } + return; + } else if (line == CHESS_DRAWING_WARN_ROW) + line = info->photo ? + CHESS_DRAWING_PHOTOED_WARN_ROW : + CHESS_DRAWING_REAL_WARN_ROW; + else if (line == CHESS_DRAWING_STEP_ROW) + line = CHESS_DRAWING_REAL_STEP_ROW; + + info->actions->drawline(info, line); +} + static void ChessRedraw(const ChessInfo* info) { @@ -135,9 +186,10 @@ ChessTimeCountDownCalc(ChessInfo* info, int who, int length) if (info->lefttime[who] < 0) { /* only allowed when in free time */ if (info->lefthand[who]) return 1; - info->lefttime[who] = info->timelimit->limit_time; - info->lefthand[who] = info->timelimit->limit_hand; - return 0; + info->lefttime[who] += info->timelimit->limit_time; + info->lefthand[who] = info->timelimit->limit_hand; + + return (info->lefttime[who] < 0); } return 0; @@ -147,7 +199,7 @@ int ChessTimeCountDown(ChessInfo* info, int who, int length) { int result = ChessTimeCountDownCalc(info, who, length); - info->actions->drawline(info, CHESS_DRAWING_TIME_ROW); + ChessDrawLine(info, CHESS_DRAWING_TIME_ROW); return result; } @@ -290,13 +342,17 @@ ChessPlayFuncMy(ChessInfo* info) while (!endturn) { ChessStepType result; - info->actions->drawline(info, CHESS_DRAWING_TIME_ROW); + ChessDrawLine(info, CHESS_DRAWING_TIME_ROW); info->actions->movecur(info->cursor.r, info->cursor.c); oflush(); ch = igetch(); - if (ChessTimeCountDown(info, 0, now - last_time)) - ch = 'q'; + if (ChessTimeCountDown(info, 0, now - last_time)) { + /* ran out of time */ + game_result = CHESS_RESULT_LOST; + endturn = 1; + break; + } last_time = now; switch (ch) { @@ -338,8 +394,17 @@ ChessPlayFuncMy(ChessInfo* info) break; case 'q': - game_result = CHESS_RESULT_LOST; - endturn = 1; + { + char buf[4]; + getdata(b_lines, 0, "是否真的要認輸?(y/N)", + buf, sizeof(buf), DOECHO); + ChessDrawHelpLine(info); + + if (buf[0] == 'y' || buf[0] == 'Y') { + game_result = CHESS_RESULT_LOST; + endturn = 1; + } + } break; case 'p': @@ -355,7 +420,7 @@ ChessPlayFuncMy(ChessInfo* info) strlcpy(info->warnmsg, ANSI_COLOR(1;33) "要求和棋!" ANSI_RESET, sizeof(info->warnmsg)); - info->actions->drawline(info, CHESS_DRAWING_WARN_ROW); + ChessDrawLine(info, CHESS_DRAWING_WARN_ROW); bell(); } } @@ -370,8 +435,8 @@ ChessPlayFuncMy(ChessInfo* info) } ChessTimeCountDown(info, 0, now - last_time); ChessStepMade(info, 0); - info->actions->drawline(info, CHESS_DRAWING_TIME_ROW); - info->actions->drawline(info, CHESS_DRAWING_STEP_ROW); + ChessDrawLine(info, CHESS_DRAWING_TIME_ROW); + ChessDrawLine(info, CHESS_DRAWING_STEP_ROW); return game_result; } @@ -393,14 +458,23 @@ ChessPlayFuncHis(ChessInfo* info) } last_time = now; - info->actions->drawline(info, CHESS_DRAWING_TIME_ROW); + ChessDrawLine(info, CHESS_DRAWING_TIME_ROW); move(1, 0); oflush(); switch (igetch()) { case 'q': - game_result = CHESS_RESULT_LOST; - endturn = 1; + { + char buf[4]; + getdata(b_lines, 0, "是否真的要認輸?(y/N)", + buf, sizeof(buf), DOECHO); + ChessDrawHelpLine(info); + + if (buf[0] == 'y' || buf[0] == 'Y') { + game_result = CHESS_RESULT_LOST; + endturn = 1; + } + } break; case 'p': @@ -423,7 +497,7 @@ ChessPlayFuncHis(ChessInfo* info) strlcpy(info->warnmsg, ANSI_COLOR(1;33) "要求和局!" ANSI_RESET, sizeof(info->warnmsg)); - info->actions->drawline(info, CHESS_DRAWING_WARN_ROW); + ChessDrawLine(info, CHESS_DRAWING_WARN_ROW); } else { info->actions->prepare_step(info, &info->step_tmp); if (info->actions->apply_step(info->board, &info->step_tmp)) @@ -436,8 +510,8 @@ ChessPlayFuncHis(ChessInfo* info) } } ChessTimeCountDown(info, 1, now - last_time); - info->actions->drawline(info, CHESS_DRAWING_TIME_ROW); - info->actions->drawline(info, CHESS_DRAWING_STEP_ROW); + ChessDrawLine(info, CHESS_DRAWING_TIME_ROW); + ChessDrawLine(info, CHESS_DRAWING_STEP_ROW); return game_result; } @@ -452,7 +526,7 @@ ChessPlayFuncWatch(ChessInfo* info) strlcpy(info->warnmsg, ANSI_COLOR(1;33) "棋局已結束" ANSI_RESET, sizeof(info->warnmsg)); - info->actions->drawline(info, CHESS_DRAWING_WARN_ROW); + ChessDrawLine(info, CHESS_DRAWING_WARN_ROW); move(1, 0); switch (igetch()) { @@ -656,7 +730,8 @@ ChessGenLogUser(ChessInfo* info, ChessGameResult result) info->actions->genlog(info, fp, result); fclose(fp); - strlcpy(log_header.owner, "[楚河漢界]", sizeof(log_header.owner)); + snprintf(log_header.owner, sizeof(log_header.owner), "[%s]", + info->constants->chess_name); if(info->myturn == 0) sprintf(log_header.title, "%s V.S. %s", info->user1.userid, info->user2.userid); @@ -702,7 +777,15 @@ ChessPlay(ChessInfo* info) } CurrentPlayingGameInfo = info; - old_handler = Signal(SIGUSR1, &ChessWatchRequest); + + { + sigset_t sigset; + old_handler = Signal(SIGUSR1, &ChessWatchRequest); + + sigemptyset(&sigset); + sigaddset(&sigset, SIGUSR1); + sigprocmask(SIG_UNBLOCK, &sigset, NULL); + } if (info->mode == CHESS_MODE_WATCH) { int i; @@ -725,8 +808,8 @@ ChessPlay(ChessInfo* info) game_result == CHESS_RESULT_CONTINUE; info->turn ^= 1) { info->actions->prepare_play(info); - info->actions->drawline(info, CHESS_DRAWING_TURN_ROW); - info->actions->drawline(info, CHESS_DRAWING_WARN_ROW); + ChessDrawLine(info, CHESS_DRAWING_TURN_ROW); + ChessDrawLine(info, CHESS_DRAWING_WARN_ROW); game_result = info->play_func[(int) info->turn](info); } add_io(0, 0); @@ -761,12 +844,13 @@ ChessPlay(ChessInfo* info) if (game_result_str) { strlcpy(info->warnmsg, game_result_str, sizeof(info->warnmsg)); - info->actions->drawline(info, CHESS_DRAWING_WARN_ROW); + ChessDrawLine(info, CHESS_DRAWING_WARN_ROW); } info->actions->gameend(info, game_result); ChessGenLog(info, game_result); + currutmp->sig = -1; Signal(SIGUSR1, old_handler); CurrentPlayingGameInfo = NULL; } @@ -866,8 +950,10 @@ ChessWatchGame(void (*play)(int, ChessGameMode), int game, const char* title) if ((uin = ChessSearchUser(-1, title)) == NULL) return -1; - if (uin->uid == currutmp->uid || uin->mode != game) + if (uin->uid == currutmp->uid || uin->mode != game) { + vmsg("無法建立連線"); return -1; + } if (getans("是否進行觀棋? [N/y]") != 'y') return 0; @@ -1193,3 +1279,109 @@ ChessShowRequest(void) } } +inline static const char* +ChessTimeStr(int second) +{ + static char buf[10]; + snprintf(buf, sizeof(buf), "%d:%02d", second / 60, second % 60); + return buf; +} + +void +ChessDrawExtraInfo(const ChessInfo* info, int line) +{ + if (info->photo) { + if (line >= 3 && line < 3 + CHESS_PHOTO_LINE) { + outs(" "); + outs(info->photo + (line - 3) * CHESS_PHOTO_COLUMN); + } else if (line >= CHESS_DRAWING_PHOTOED_TURN_ROW && + line <= CHESS_DRAWING_PHOTOED_WARN_ROW) { + outs(" "); + if (line == CHESS_DRAWING_PHOTOED_TURN_ROW) + prints(ANSI_COLOR(1;33) "%s" ANSI_RESET, + info->myturn == info->turn ? "輪到你下棋了" : "等待對方下棋"); + else if (line == CHESS_DRAWING_PHOTOED_TIME_ROW1) { + if (info->mode == CHESS_MODE_WATCH) { + if (!info->timelimit) + prints("每手限時五分鐘"); + else + prints("局時: %5s", + ChessTimeStr(info->timelimit->free_time)); + } else if (info->lefthand[0]) + prints("我方剩餘時間 %s / %2d 步", + ChessTimeStr(info->lefttime[0]), + info->lefthand[0]); + else + prints("我方剩餘時間 %s", + ChessTimeStr(info->lefttime[0])); + } else if (line == CHESS_DRAWING_PHOTOED_TIME_ROW2) { + if (info->mode == CHESS_MODE_WATCH) { + if (info->timelimit) { + if (info->timelimit->time_mode == + CHESS_TIMEMODE_MULTIHAND) + prints("步時: %s / %2d 步", + ChessTimeStr(info->timelimit->limit_time), + info->timelimit->limit_hand); + else + prints("讀秒: %5d 秒", + info->timelimit->limit_time); + } + } else if (info->lefthand[1]) + prints("對方剩餘時間 %s / %2d 步", + ChessTimeStr(info->lefttime[1]), + info->lefthand[1]); + else + prints("對方剩餘時間 %s", + ChessTimeStr(info->lefttime[1])); + } else if (line == CHESS_DRAWING_PHOTOED_WARN_ROW) + outs(info->warnmsg); + } + } else if (line >= 3 && line <= CHESS_DRAWING_HISWIN_ROW) { + outs(" "); + if (line >= 3 && line < 3 + (int)dim(ChessHintStr)) { + outs(ChessHintStr[line - 3]); + } else if (line == CHESS_DRAWING_SIDE_ROW) { + prints(ANSI_COLOR(1) "你是%s%s" ANSI_RESET, + info->constants->turn_color[(int) info->myturn], + info->constants->turn_str[(int) info->myturn]); + } else if (line == CHESS_DRAWING_REAL_TURN_ROW) { + prints(ANSI_COLOR(1;33) "%s" ANSI_RESET, + info->myturn == info->turn ? + "輪到你下棋了" : "等待對方下棋"); + } else if (line == CHESS_DRAWING_REAL_STEP_ROW && info->last_movestr) { + outs(info->last_movestr); + } else if (line == CHESS_DRAWING_REAL_TIME_ROW1) { + if (info->lefthand[0]) + prints("我方剩餘時間 %s / %2d 步", + ChessTimeStr(info->lefttime[0]), + info->lefthand[0]); + else + prints("我方剩餘時間 %s", + ChessTimeStr(info->lefttime[0])); + } else if (line == CHESS_DRAWING_REAL_TIME_ROW2) { + if (info->lefthand[1]) + prints("對方剩餘時間 %s / %2d 步", + ChessTimeStr(info->lefttime[1]), + info->lefthand[1]); + else + prints("對方剩餘時間 %s", + ChessTimeStr(info->lefttime[1])); + } else if (line == CHESS_DRAWING_REAL_WARN_ROW) { + outs(info->warnmsg); + } else if (line == CHESS_DRAWING_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, + info->user1.userid, + info->user1.win, info->user1.lose - 1, info->user1.tie); + } else if (line == CHESS_DRAWING_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, + info->user2.userid, + info->user2.win, info->user2.lose, info->user2.tie); + } + } +} diff --git a/mbbsd/gomo.c b/mbbsd/gomo.c index 196fa933..561c4003 100644 --- a/mbbsd/gomo.c +++ b/mbbsd/gomo.c @@ -3,15 +3,71 @@ #include "gomo.h" #define QCAST int (*)(const void *, const void *) +#define BOARD_LINE_ON_SCREEN(X) ((X) + 2) -static int tick, lastcount, mylasttick, hislasttick; -//static char ku[BRDSIZ][BRDSIZ]; +static const char* turn_color[] = { ANSI_COLOR(30;43), ANSI_COLOR(37;43) }; -static Horder_t *v; -static int draw_photo; +enum Turn { + WHT = 0, + BLK +}; +typedef struct { + ChessStepType type; /* necessary one */ + int color; + rc_t loc; +} gomo_step_t; + +typedef char board_t[BRDSIZ][BRDSIZ]; +typedef char (*board_p)[BRDSIZ]; + +#if 0 #define move(y,x) move(y, (x) + ((y) < 2 || (y) > 16 ? 0 : \ (x) > 35 ? 11 : 8)) +#endif + +static void gomo_init_user(const userinfo_t* uinfo, ChessUser* user); +static void gomo_init_board(board_t board); +static void gomo_drawline(const ChessInfo* info, int line); +static void gomo_movecur(int r, int c); +static void gomo_prepare_play(ChessInfo* info); +static int gomo_select(ChessInfo* info, rc_t location, + ChessGameResult* result); +static void gomo_prepare_step(ChessInfo* info, const gomo_step_t* step); +static int gomo_apply_step(board_t board, const gomo_step_t* step); +static void gomo_drawstep(ChessInfo* info, const gomo_step_t* step); +static void gomo_gameend(ChessInfo* info, ChessGameResult result); +static void gomo_genlog(ChessInfo* info, FILE* fp, ChessGameResult result); + +ChessActions gomo_actions = { + &gomo_init_user, + (void (*)(void*)) &gomo_init_board, + &gomo_drawline, + &gomo_movecur, + &gomo_prepare_play, + &gomo_select, + (void (*)(ChessInfo*, const void*)) &gomo_prepare_step, + (int (*)(void*, const void*)) &gomo_apply_step, + (void (*)(ChessInfo*, const void*)) &gomo_drawstep, + &gomo_gameend, + &gomo_genlog +}; + +ChessConstants gomo_constants = { + sizeof(gomo_step_t), + MAX_TIME, + BRDSIZ, + BRDSIZ, + "五子棋", + "photo_fivechess", +#ifdef GLOBAL_FIVECHESS_LOG + GLOBAL_FIVECHESS_LOG, +#else + NULL, +#endif + { ANSI_COLOR(37;43), ANSI_COLOR(30;43) }, + { "白棋", "黑棋, 有禁手" }, +}; /* pattern and advance map */ @@ -26,7 +82,7 @@ intrevcmp(const void *a, const void *b) // 最高位 1 表示對方的子, 或是牆 /* x,y: 0..BRDSIZ-1 ; color: CBLACK,CWHITE ; dx,dy: -1,0,+1 */ static int -gomo_getindex(char ku[][BRDSIZ], int x, int y, int color, int dx, int dy) +gomo_getindex(board_t ku, int x, int y, int color, int dx, int dy) { int i, k, n; for (n = -1, i = 0, k = 1; i < 5; i++, k*=2) { @@ -49,25 +105,25 @@ gomo_getindex(char ku[][BRDSIZ], int x, int y, int color, int dx, int dy) return n; } -int +ChessGameResult chkwin(int style, int limit) { if (style == 0x0c) - return 1 /* style */ ; + return CHESS_RESULT_WIN; else if (limit == 0) { if (style == 0x0b) - return 1 /* style */ ; - return 0; + return CHESS_RESULT_WIN; + return CHESS_RESULT_CONTINUE; } if ((style < 0x0c) && (style > 0x07)) - return -1 /* -style */ ; - return 0; + return CHESS_RESULT_LOST; + return CHESS_RESULT_CONTINUE; } -static int getstyle(char ku[][BRDSIZ], int x, int y, int color, int limit); +static int getstyle(board_t ku, int x, int y, int color, int limit); /* x,y: 0..BRDSIZ-1 ; color: CBLACK,CWHITE ; limit:1,0 ; dx,dy: 0,1 */ static int -dirchk(char ku[][BRDSIZ], int x, int y, int color, int limit, int dx, int dy) +dirchk(board_t ku, int x, int y, int color, int limit, int dx, int dy) { int le, ri, loc, style = 0; @@ -77,7 +133,7 @@ dirchk(char ku[][BRDSIZ], int x, int y, int color, int limit, int dx, int dy) loc = (le > ri) ? (((le * (le + 1)) >> 1) + ri) : (((ri * (ri + 1)) >> 1) + le); - style = pat[loc]; + style = pat_gomoku[loc]; if (limit == 0) return (style & 0x0f); @@ -87,7 +143,7 @@ dirchk(char ku[][BRDSIZ], int x, int y, int color, int limit, int dx, int dy) if ((style == 3) || (style == 2)) { int i, n = 0, tmp, nx, ny; - n = adv[loc / 2]; + n = adv_gomoku[loc / 2]; if(loc%2==0) n/=16; @@ -118,7 +174,7 @@ dirchk(char ku[][BRDSIZ], int x, int y, int color, int limit, int dx, int dy) /* x,y: 0..BRDSIZ-1 ; color: CBLACK,CWHITE ; limit: 1,0 */ static int -getstyle(char ku[][BRDSIZ], int x, int y, int color, int limit) +getstyle(board_t ku, int x, int y, int color, int limit) { int i, j, dir[4], style; @@ -148,673 +204,280 @@ getstyle(char ku[][BRDSIZ], int x, int y, int color, int limit) return style; } -static void -HO_init(char ku[][BRDSIZ], Horder_t *pool) +static char* +gomo_move_warn(int style, char buf[]) { - memset(pool, 0, sizeof(Horder_t)*BRDSIZ*BRDSIZ); - v = pool; - pat = pat_gomoku; - adv = adv_gomoku; - memset(ku, 0, (BRDSIZ*BRDSIZ)); + char *xtype[] = { + ANSI_COLOR(1;31) "跳三" ANSI_RESET, + ANSI_COLOR(1;31) "活三" ANSI_RESET, + ANSI_COLOR(1;31) "死四" ANSI_RESET, + ANSI_COLOR(1;31) "跳四" ANSI_RESET, + ANSI_COLOR(1;31) "活四" ANSI_RESET, + ANSI_COLOR(1;31) "四三" ANSI_RESET, + ANSI_COLOR(1;31) "雙三" ANSI_RESET, + ANSI_COLOR(1;31) "雙四" ANSI_RESET, + ANSI_COLOR(1;31) "雙四" ANSI_RESET, + ANSI_COLOR(1;31) "連六" ANSI_RESET, + ANSI_COLOR(1;31) "連五" ANSI_RESET + }; + if (style > 1 && style < 13) + return strcpy(buf, xtype[style - 2]); + else + return NULL; } static void -HO_add(Horder_t * mv) +gomoku_usr_put(userec_t* userec, const ChessUser* user) { - *v++ = *mv; + userec->five_win = user->win; + userec->five_lose = user->lose; + userec->five_tie = user->tie; } -static void -HO_undo(char ku[][BRDSIZ], Horder_t * mv) +static char* +gomo_getstep(const gomo_step_t* step, char buf[]) { - char *str = "┌┬┐├┼┤└┴┘"; - int n1, n2, loc; - - *mv = *(--v); - ku[(int)mv->x][(int)mv->y] = BBLANK; - BGOTO(mv->x, mv->y); - n1 = (mv->x == 0) ? 0 : (mv->x == 14) ? 2 : 1; - n2 = (mv->y == 14) ? 0 : (mv->y == 0) ? 2 : 1; - loc = 2 * (n2 * 3 + n1); - prints("%.2s", str + loc); - redoln(); + const static char* const ColName = "ABCDEFGHIJKLMN"; + const static char* const RawName = "123456789101112131415"; + const static int ansi_length = sizeof(ANSI_COLOR(30;43)); + + strcpy(buf, turn_color[step->color]); + buf[ansi_length ] = ColName[step->loc.c * 2]; + buf[ansi_length + 1] = ColName[step->loc.c * 2 + 1]; + buf[ansi_length + 2] = RawName[step->loc.r * 2]; + buf[ansi_length + 3] = RawName[step->loc.r * 2 + 1]; + strcpy(buf + ansi_length + 4, ANSI_RESET); + + return buf; } static void -HO_log(Horder_t *pool, FILE* fp, char *mate) +gomo_init_user(const userinfo_t* uinfo, ChessUser* user) { - int i; - Horder_t *ptr = pool; - - for (i = 1; i < 18; i++) - fprintf(fp, "%.*s\n", big_picture[i].len, big_picture[i].data); - - if (mate != NULL) - fprintf(fp, "<gomokulog>\nblack:%s\nwhite:%s\n", cuser.userid, mate); - - i = 0; - do { - fprintf(fp, "[%2d]%s ==> %c%-5d", i + 1, bw_chess[i % 2], - 'A' + ptr->x, ptr->y + 1); - if (i % 2) - fputc('\n', fp); - i++; - } while (++ptr < v); - - if (mate != NULL) - fputs("\n</gomokulog>\n", fp); + strlcpy(user->userid, uinfo->userid, sizeof(user->userid)); + user->win = uinfo->five_win; + user->lose = uinfo->five_lose; + user->tie = uinfo->five_tie; } static void -HO_log_user(Horder_t* pool, char *mate) +gomo_init_board(board_t board) { - char buf[200]; - fileheader_t mail_header; - FILE* fp; + memset(board, 0xff, sizeof(board_t)); +} - sethomepath(buf, cuser.userid); - stampfile(buf, &mail_header); +static void +gomo_drawline(const ChessInfo* info, int line) +{ + const static char* const BoardPic[] = { + "┌", "┬", "┐", + "├", "┼", "┤", + "└", "┴", "┘" + }; + const static int BoardPicIndex[] = + { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2 }; + + board_p board = (board_p) info->board; + + move(line, 0); + clrtoeol(); + if (line == 0) { + 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 == 1) { + outs(" A B C D E F G H I J K L M N"); + } else if (line >= 2 && line <= 16) { + const int board_line = line - 2; + const char* const* const pics = + board_line == 0 ? &BoardPic[0] : + board_line == 14 ? &BoardPic[6] : &BoardPic[3]; + int i; + + prints("%3d" ANSI_COLOR(30;43), 17 - line); + + for (i = 0; i < 15; ++i) + if (board[board_line][i] == -1) + outs(pics[BoardPicIndex[i]]); + else + outs(bw_chess[(int) board[board_line][i]]); - fp = fopen(buf, "w"); - if (fp != NULL) { - HO_log(pool, fp, NULL); - fclose(fp); + outs(ANSI_RESET); + } else if (line >= 17 && line <= 23) + prints("%33s", ""); - mail_header.filemode = FILE_READ; - strlcpy(mail_header.owner, "[備.忘.錄]", sizeof(mail_header.owner)); - snprintf(mail_header.title, sizeof(mail_header.title), - ANSI_COLOR(37;41) "棋譜" ANSI_RESET " %s VS %s", cuser.userid, mate); + ChessDrawExtraInfo(info, line); +} - sethomedir(buf, cuser.userid); - append_record(buf, &mail_header, sizeof(mail_header)); - } +static void +gomo_movecur(int r, int c) +{ + move(r + 2, c * 2 + 3); } -#ifdef GLOBAL_FIVECHESS_LOG static void -HO_log_board(Horder_t* pool, char *mate) +gomo_prepare_play(ChessInfo* info) +{ + if (!gomo_move_warn(*(int*) info->tag, info->warnmsg)) + info->warnmsg[0] = 0; +} + +static int +gomo_select(ChessInfo* info, rc_t location, ChessGameResult* result) { - char buf[200]; - fileheader_t log_header; - FILE* fp; - int bid; + board_p board = (board_p) info->board; + gomo_step_t step; + + if(board[location.r][location.c] != BBLANK) + return 0; - if ((bid = getbnum(GLOBAL_FIVECHESS_LOG)) == 0) - return; + *(int*) info->tag = getstyle(board, location.r, location.c, + info->turn, info->turn == BLK); + *result = chkwin(*(int*) info->tag, info->turn == BLK); - setbpath(buf, GLOBAL_FIVECHESS_LOG); - stampfile(buf, &log_header); + board[location.r][location.c] = info->turn; - fp = fopen(buf, "w"); - if (fp != NULL) { - HO_log(pool, fp, mate); - fclose(fp); + step.type = CHESS_STEP_NORMAL; + step.color = info->turn; + step.loc = location; + gomo_getstep(&step, info->last_movestr); - strlcpy(log_header.owner, "[棋譜機器人]", sizeof(log_header.owner)); - snprintf(log_header.title, sizeof(log_header.title), - "[棋譜] %s VS %s", cuser.userid, mate); + ChessHistoryAppend(info, &step); + ChessStepSend(info, &step); + gomo_drawstep(info, &step); - setbdir(buf, GLOBAL_FIVECHESS_LOG); - append_record(buf, &log_header, sizeof(log_header)); + return 1; +} - setbtotal(bid); +static void +gomo_prepare_step(ChessInfo* info, const gomo_step_t* step) +{ + if (step->type == CHESS_STEP_NORMAL) { + gomo_getstep(step, info->last_movestr); + *(int*) info->tag = getstyle(info->board, step->loc.r, step->loc.c, + step->color, step->color == BLK); } } -#endif static int -countgomo(Horder_t *pool) +gomo_apply_step(board_t board, const gomo_step_t* step) { - return v-pool; + int style; + + style = getstyle(board, step->loc.r, step->loc.c, + step->color, step->color == BLK); + board[step->loc.r][step->loc.c] = step->color; + return (chkwin(style, step->color == BLK) != CHESS_RESULT_CONTINUE); } -static int -chkmv(char ku[][BRDSIZ], Horder_t * mv, int color, int limit) +static void +gomo_drawstep(ChessInfo* info, const gomo_step_t* step) { - char *xtype[] = {ANSI_COLOR(1;31) "跳三" ANSI_RESET, ANSI_COLOR(1;31) "活三" ANSI_RESET, - ANSI_COLOR(1;31) "死四" ANSI_RESET, ANSI_COLOR(1;31) "跳四" ANSI_RESET, - ANSI_COLOR(1;31) "活四" ANSI_RESET, ANSI_COLOR(1;31) "四三" ANSI_RESET, - ANSI_COLOR(1;31) "雙三" ANSI_RESET, ANSI_COLOR(1;31) "雙四" ANSI_RESET, - ANSI_COLOR(1;31) "雙四" ANSI_RESET, ANSI_COLOR(1;31) "連六" ANSI_RESET, - ANSI_COLOR(1;31) "連五" ANSI_RESET}; - int rule = getstyle(ku, mv->x, mv->y, color, limit); - if (rule > 1 && rule < 13) { - move(draw_photo ? 19 : 15, 40); - outs(xtype[rule - 2]); - bell(); - } - return chkwin(rule, limit); + ChessDrawLine(info, BOARD_LINE_ON_SCREEN(step->loc.r)); } -static int -gomo_key(char ku[][BRDSIZ], int fd, int ch, Horder_t * mv) +static void +gomo_gameend(ChessInfo* info, ChessGameResult result) { - if (ch >= 'a' && ch <= 'o') { - char pbuf[4], vx, vy; - - pbuf[0] = ch; - pbuf[1] = '\0'; - - if (fd) - add_io(0, 0); - oldgetdata(17, 0, "直接指定位置 :", pbuf, sizeof(pbuf), DOECHO); - if (fd) - add_io(fd, 0); - vx = pbuf[0] - 'a'; - vy = atoi(pbuf + 1) - 1; - if (vx >= 0 && vx < 15 && vy >= 0 && vy < 15 && - ku[(int)vx][(int)vy] == BBLANK) { - mv->x = vx; - mv->y = vy; - return 1; - } - } else { - switch (ch) { - case KEY_RIGHT: - if(mv->x<BRDSIZ-1) - mv->x++; - break; - case KEY_LEFT: - if(mv->x>0) - mv->x--; - break; - case KEY_UP: - if(mv->y<BRDSIZ-1) - mv->y++; - break; - case KEY_DOWN: - if(mv->y>0) - mv->y--; - break; - case ' ': - case '\r': - if (ku[(int)mv->x][(int)mv->y] == BBLANK) - return 1; + if (info->mode == CHESS_MODE_VERSUS) { + ChessUser* const user1 = &info->user1; + /* ChessUser* const user2 = &info->user2; */ + + user1->lose--; + if (result == CHESS_RESULT_WIN) { + user1->win++; + currutmp->five_win++; + } else if (result == CHESS_RESULT_LOST) { + user1->lose++; + currutmp->five_lose++; + } else { + user1->tie++; + currutmp->five_tie++; } - } - return 0; -} -#define PASS_REQUEST -2 -#define PASS_REJECT -3 -#define UNDO_REQUEST -1 -#define UNDO_REJECT -4 + cuser.five_win = user1->win; + cuser.five_lose = user1->lose; + cuser.five_tie = user1->tie; -int -gomoku(int fd) -{ - Horder_t mv; - int me, he, ch; - char hewantpass, iwantpass, passrejected; - char hewantundo, iwantundo, undorejected; - userinfo_t *my = currutmp; - Horder_t pool[BRDSIZ*BRDSIZ]; - int scr_need_redraw; - char ku[BRDSIZ][BRDSIZ]; - char genbuf[200]; - userec_t xuser; - - HO_init(ku, pool); - me = !(my->turn) + 1; - he = my->turn + 1; - tick = now + MAX_TIME; - lastcount = MAX_TIME; - setutmpmode(M_FIVE); - clear(); - - prints(ANSI_COLOR(1;46) " 五子棋對戰 " ANSI_COLOR(45) "%30s VS %-30s" ANSI_RESET, - cuser.userid, my->mateid); - //show_file("etc/@five", 1, -1, ONLY_COLOR); - move(1, 0); - outs( - " A B C D E F G H I J K L M N\n" - " 15" ANSI_COLOR(30;43) "┌┬┬┬┬┬┬┬┬┬┬┬┬┬┐" ANSI_RESET "\n" - " 14" ANSI_COLOR(30;43) "├┼┼┼┼┼┼┼┼┼┼┼┼┼┤" ANSI_RESET "\n" - " 13" ANSI_COLOR(30;43) "├┼┼┼┼┼┼┼┼┼┼┼┼┼┤" ANSI_RESET "\n" - " 12" ANSI_COLOR(30;43) "├┼┼┼┼┼┼┼┼┼┼┼┼┼┤" ANSI_RESET "\n" - " 11" ANSI_COLOR(30;43) "├┼┼┼┼┼┼┼┼┼┼┼┼┼┤" ANSI_RESET "\n" - " 10" ANSI_COLOR(30;43) "├┼┼┼┼┼┼┼┼┼┼┼┼┼┤" ANSI_RESET "\n" - " 9" ANSI_COLOR(30;43) "├┼┼┼┼┼┼┼┼┼┼┼┼┼┤" ANSI_RESET "\n" - " 8" ANSI_COLOR(30;43) "├┼┼┼┼┼┼┼┼┼┼┼┼┼┤" ANSI_RESET "\n" - " 7" ANSI_COLOR(30;43) "├┼┼┼┼┼┼┼┼┼┼┼┼┼┤" ANSI_RESET "\n" - " 6" ANSI_COLOR(30;43) "├┼┼┼┼┼┼┼┼┼┼┼┼┼┤" ANSI_RESET "\n" - " 5" ANSI_COLOR(30;43) "├┼┼┼┼┼┼┼┼┼┼┼┼┼┤" ANSI_RESET "\n" - " 4" ANSI_COLOR(30;43) "├┼┼┼┼┼┼┼┼┼┼┼┼┼┤" ANSI_RESET "\n" - " 3" ANSI_COLOR(30;43) "├┼┼┼┼┼┼┼┼┼┼┼┼┼┤" ANSI_RESET "\n" - " 2" ANSI_COLOR(30;43) "├┼┼┼┼┼┼┼┼┼┼┼┼┼┤" ANSI_RESET "\n" - " 1" ANSI_COLOR(30;43) "└┴┴┴┴┴┴┴┴┴┴┴┴┴┘" ANSI_RESET "\n" - ); - - draw_photo = 0; - setuserfile(genbuf, "photo_fivechess"); - if (dashf(genbuf)) - draw_photo = 1; - else { - sethomefile(genbuf, my->mateid, "photo_fivechess"); - if (dashf(genbuf)) - draw_photo = 1; + passwd_update(usernum, &cuser); } +} - getuser(my->mateid, &xuser); - if (draw_photo) { - int line; - FILE* fp; - static const char * const blank_photo[6] = { - "┌──────┐", - "│ 空 │", - "│ 白 │", - "│ 照 │", - "│ 片│", - "└──────┘" - }; - char country[5], level[11]; - - setuserfile(genbuf, "photo_fivechess"); - fp = fopen(genbuf, "r"); - - if (fp == NULL) { - strcpy(country, "無"); - level[0] = 0; - } else { - int i, j; - for (line = 1; line < 8; ++line) - fgets(genbuf, 200, fp); - - fgets(genbuf, 200, 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, 200, fp); - chomp(genbuf); - strlcpy(level, genbuf + 11, 11); /* five chinese words*/ - rewind(fp); - } +static void +gomo_genlog(ChessInfo* info, FILE* fp, ChessGameResult result) +{ + const int nStep = info->history.used; + int i; - for (line = 2; line < 8; ++line) { - move(line, 37); - if (fp != NULL) { - if (fgets(genbuf, 200, fp)) { - chomp(genbuf); - prints("%s ", genbuf); - } else - outs(" "); - } else - outs(blank_photo[line - 2]); - - switch (line - 2) { - case 0: prints("<代號> %s", cuser.userid); break; - case 1: prints("<暱稱> %.16s", cuser.nickname); break; - case 2: prints("<上站> %d", cuser.numlogins); break; - case 3: prints("<文章> %d", cuser.numposts); break; - case 4: prints("<職位> %-4s %s", country, level); break; - case 5: prints("<來源> %.16s", cuser.lasthost); break; - } - } - if (fp != NULL) - fclose(fp); - - move(8, 43); - prints(ANSI_COLOR(7) "%s" ANSI_RESET, me == BBLACK ? "黑棋" : "白棋"); - move(9, 43); - outs(" V.S "); - move(10, 68); - prints(ANSI_COLOR(7) "%s" ANSI_RESET, me == BBLACK ? "白棋" : "黑棋"); - - sethomefile(genbuf, my->mateid, "photo_fivechess"); - fp = fopen(genbuf, "r"); - - if (fp == NULL) { - strcpy(country, "無"); - level[0] = 0; - } else { - int i, j; - for (line = 1; line < 8; ++line) - fgets(genbuf, 200, fp); - - fgets(genbuf, 200, 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, 200, fp); - chomp(genbuf); - strlcpy(level, genbuf + 11, 11); /* five chinese words*/ - rewind(fp); - } + for (i = 1; i < 18; i++) + fprintf(fp, "%.*s\n", big_picture[i].len, big_picture[i].data); - for (line = 11; line < 17; ++line) { - move(line, 37); - switch (line - 11) { - case 0: prints("<代號> %-16.16s ", xuser.userid); break; - case 1: prints("<暱稱> %-16.16s ", xuser.nickname); break; - case 2: prints("<上站> %-16d ", xuser.numlogins); break; - case 3: prints("<文章> %-16d ", xuser.numposts); break; - case 4: prints("<職位> %-4s %-10s ", country, level); break; - case 5: prints("<來源> %-16.16s ", xuser.lasthost); break; - } + fprintf(fp, "<gomokulog>\nblack:%s\nwhite:%s\n", + info->myturn ? info->user1.userid : info->user2.userid, + info->myturn ? info->user2.userid : info->user1.userid); - if (fp != NULL) { - if (fgets(genbuf, 200, fp)) { - chomp(genbuf); - outs(genbuf); - } else - outs(" "); - } else - outs(blank_photo[line - 11]); - } - if (fp != NULL) - fclose(fp); - - move(18, 4); - prints("我是 %s", me == BBLACK ? "先手 ●,有禁手" : "後手 ○"); - } else { - move(3, 40); outs("[q] 認輸離開"); - move(4, 40); outs("[u] 悔棋"); - move(5, 40); outs("[p] 要求和棋"); - move(9, 39); outs("[歡迎到five_chess討論五子棋喔]"); - - move(11, 40); - prints("我是 %s", me == BBLACK ? "先手 ●, 有禁手" : "後手 ○"); - move(16, 40); - prints(ANSI_COLOR(1;33) "%s", cuser.userid); - move(17, 40); - prints(ANSI_COLOR(1;33) "%s", my->mateid); - - move(16, 60); - prints(ANSI_COLOR(1;31) "%d" ANSI_COLOR(37) "勝 " ANSI_COLOR(34) "%d" ANSI_COLOR(37) "敗 " ANSI_COLOR(36) "%d" ANSI_COLOR(37) "和" - ANSI_RESET, cuser.five_win, cuser.five_lose, cuser.five_tie); - - move(17, 60); - prints(ANSI_COLOR(1;31) "%d" ANSI_COLOR(37) "勝 " ANSI_COLOR(34) "%d" ANSI_COLOR(37) "敗 " ANSI_COLOR(36) "%d" ANSI_COLOR(37) "" - "和" ANSI_RESET, xuser.five_win, xuser.five_lose, xuser.five_tie); - - move(18, 40); - prints("%s時間還剩%d:%02d\n", my->turn ? "你的" : "對方", - MAX_TIME / 60, MAX_TIME % 60); + for (i = 0; i < nStep; ++i) { + const gomo_step_t* const step = + (const gomo_step_t*) ChessHistoryRetrieve(info, i); + fprintf(fp, "[%2d]%s ==> %c%-5d", i + 1, bw_chess[i % 2], + 'A' + step->loc.c, step->loc.r + 1); + if (i % 2) + fputc('\n', fp); } - cuser.five_lose++; - /* 一進來先加一場敗場, 贏了後再扣回去, 避免快輸了惡意斷線 */ - passwd_update(usernum, &cuser); + if (i % 2) + fputc('\n', fp); + fputs("</gomokulog>\n", fp); +} - add_io(fd, 0); +void +gomoku(int s, ChessGameMode mode) +{ + ChessInfo* info = NewChessInfo(&gomo_actions, &gomo_constants, s, mode); + board_t board; + int tag; + + gomo_init_board(board); + tag = 0; + + info->board = board; + info->tag = &tag; + + if (info->mode == CHESS_MODE_VERSUS) { + /* Assume that info->user1 is me. */ + info->user1.lose++; + passwd_query(usernum, &cuser); + gomoku_usr_put(&cuser, &info->user1); + passwd_update(usernum, &cuser); + } - hewantpass = iwantpass = passrejected = 0; - hewantundo = iwantundo = undorejected = 0; - mv.x = mv.y = 7; - scr_need_redraw = 1; - for (;;) { - if (scr_need_redraw){ - if (draw_photo) - move(19, 4); - else - move(13, 40); - outs(my->turn ? "輪到自己下了!" : "等待對方下子.."); - redoln(); + if (mode == CHESS_MODE_WATCH) + setutmpmode(CHESSWATCHING); + else + setutmpmode(M_FIVE); + currutmp->sig = SIG_GOMO; - outmsg(ANSI_COLOR(1;33;42) " 下五子棋 " ANSI_COLOR(;31;47) " (←↑↓→)" ANSI_COLOR(30) "移動 " ANSI_COLOR(31) "(空白鍵/ENTER)" ANSI_COLOR(30) "下子 " ANSI_COLOR(31) "(q)" ANSI_COLOR(30) "投降 " ANSI_COLOR(31) "(p)" ANSI_COLOR(30) "和棋 " ANSI_COLOR(31) "(u)" ANSI_COLOR(30) "悔棋 " ANSI_RESET); - scr_need_redraw = 0; - } - if (lastcount != tick - now) { - lastcount = tick - now; - move(18, 40); - prints("%s時間還剩%d:%02d\n", my->turn ? "你的" : "對方", - lastcount / 60, lastcount % 60); - if (lastcount <= 0 && my->turn) { - move(19, 40); - outs("時間已到, 你輸了"); - my->five_lose++; - send(fd, '\0', 1, 0); - break; - } - if (lastcount <= -5 && !my->turn) { - move(19, 40); - outs("對手太久沒下, 你贏了!"); - cuser.five_lose--; - cuser.five_win++; - my->five_win++; - passwd_update(usernum, &cuser); - mv.x = mv.y = -2; - send(fd, &mv, sizeof(Horder_t), 0); - mv = *(v - 1); - break; - } - } - move(draw_photo ? 20 : 14, 40); - clrtoeol(); - if (hewantpass) { - outs(ANSI_COLOR(1;32) "和棋要求!" ANSI_RESET); - bell(); - } else if (iwantpass) - outs(ANSI_COLOR(1;32) "提出和棋要求!" ANSI_RESET); - else if (passrejected) { - outs(ANSI_COLOR(1;32) "要求被拒!" ANSI_RESET); - passrejected = 0; - } else if (hewantundo) { - outs(ANSI_COLOR(1;33) "悔棋要求! (按 u 接受, 任意鍵拒絕)" ANSI_RESET); - bell(); - } else if (iwantundo) - outs(ANSI_COLOR(1;33) "提出悔棋要求!" ANSI_RESET); - else if (undorejected) { - outs(ANSI_COLOR(1;33) "要求被拒!" ANSI_RESET); - undorejected = 0; - } - BGOTOCUR(mv.x, mv.y); - ch = igetch(); - if ((iwantpass || hewantpass) && ch != 'p' && ch != I_OTHERDATA) { - mv.x = mv.y = PASS_REJECT; - send(fd , &mv, sizeof(Horder_t), 0); - mv = *(v - 1); - iwantpass = 0; - hewantpass = 0; - continue; - } - if ((iwantundo || hewantundo) && ch != 'u' && ch != I_OTHERDATA) { - mv.x = mv.y = UNDO_REJECT; - send(fd , &mv, sizeof(Horder_t), 0); - mv = *(v - 1); - iwantundo = 0; - hewantundo = 0; - continue; - } - if (ch == 'q') { - if (countgomo(pool) < 10) { - cuser.five_lose--; - passwd_update(usernum, &cuser); - } - send(fd, "", 1, 0); - break; - } else if (ch == 'u') { - if (my->turn) { - if (hewantundo) { - mv.x = mv.y = UNDO_REQUEST; - ch = send(fd, &mv, sizeof(Horder_t), 0); - tick = hislasttick; - HO_undo(ku, &mv); - my->turn = 0; - hewantundo = 0; - scr_need_redraw = 1; - } - continue; - } - else if (v > pool) { - mv.x = mv.y = UNDO_REQUEST; - ch = send(fd, &mv, sizeof(Horder_t), 0); - if (ch == sizeof(Horder_t)) { - iwantundo = 1; - continue; - } else - break; - } - } - if (ch == 'p') { - if (my->turn) { - if (iwantpass == 0) { - iwantpass = 1; - mv.x = mv.y = PASS_REQUEST; - send(fd, &mv, sizeof(Horder_t), 0); - mv = *(v - 1); - } - continue; - } else if (hewantpass) { - cuser.five_lose--; - cuser.five_tie++; - my->five_tie++; - passwd_update(usernum, &cuser); - mv.x = mv.y = PASS_REQUEST; - send(fd, &mv, sizeof(Horder_t), 0); - mv = *(v - 1); - break; - } - } - if (ch == I_OTHERDATA) { - ch = recv(fd, &mv, sizeof(Horder_t), 0); - if (ch != sizeof(Horder_t)) { - lastcount = tick - now; - if (lastcount >= 0) { - cuser.five_lose--; - if (countgomo(pool) >= 10) { - cuser.five_win++; - my->five_win++; - } - passwd_update(usernum, &cuser); - outmsg("對方認輸了!!"); - break; - } else { - outmsg("你超過時間未下子, 輸了!"); - my->five_lose++; - break; - } - } else if (mv.x == PASS_REQUEST && mv.y == PASS_REQUEST) { - if (iwantpass == 1) { - cuser.five_lose--; - cuser.five_tie++; - my->five_tie++; - passwd_update(usernum, &cuser); - break; - } else { - hewantpass = 1; - mv = *(v - 1); - continue; - } - } else if (mv.x == PASS_REJECT && mv.y == PASS_REJECT) { - if (iwantpass) - passrejected = 1; - iwantpass = 0; - hewantpass = 0; - mv = *(v - 1); - continue; - } else if (mv.x == UNDO_REJECT && mv.y == UNDO_REJECT) { - if (iwantundo) - undorejected = 1; - iwantundo = 0; - hewantundo = 0; - mv = *(v - 1); - continue; - } else if (mv.x == UNDO_REQUEST && mv.y == UNDO_REQUEST) { - if (!my->turn) { - if (iwantundo) { - HO_undo(ku, &mv); - tick = mylasttick; - my->turn = 1; - iwantundo = hewantundo = 0; - scr_need_redraw = 1; - } - /* else shouldn't happend */ - } else { - hewantundo = 1; - mv = *(v - 1); - } - continue; - } - if (!my->turn) { - int win; - win = chkmv(ku, &mv, he, he == BBLACK); - HO_add(&mv); - hislasttick = tick; - tick = now + MAX_TIME; - ku[(int)mv.x][(int)mv.y] = he; - bell(); - BGOTO(mv.x, mv.y); - outs(bw_chess[he - 1]); - redoln(); - - if (win) { - outmsg(win == 1 ? "對方贏了!" : "對方禁手"); - if (win != 1) { - cuser.five_lose--; - cuser.five_win++; - my->five_win++; - passwd_update(usernum, &cuser); - } else - my->five_lose++; - break; - } - my->turn = 1; - } - scr_need_redraw = 1; - continue; - } - if (my->turn) { - if (gomo_key(ku, fd, ch, &mv)) - my->turn = 0; - else - continue; - - if (!my->turn) { - int win; - HO_add(&mv); - BGOTO(mv.x, mv.y); - outs(bw_chess[me - 1]); - redoln(); - win = chkmv(ku, &mv, me, me == BBLACK); - ku[(int)mv.x][(int)mv.y] = me; - mylasttick = tick; - tick = now + MAX_TIME; /* 倒數 */ - lastcount = MAX_TIME; - if (send(fd, &mv, sizeof(Horder_t), 0) != sizeof(Horder_t)) - break; - if (win) { - outmsg(win == 1 ? "我贏囉~~" : "禁手輸了"); - if (win == 1) { - cuser.five_lose--; - cuser.five_win++; - my->five_win++; - passwd_update(usernum, &cuser); - } else - my->five_lose++; - break; - } - move(draw_photo ? 19 : 15, 40); - clrtoeol(); - } - scr_need_redraw = 1; - } - } - add_io(0, 0); - close(fd); + ChessPlay(info); - igetch(); - if (v > pool) { - char ans[4]; + DeleteChessInfo(info); +} - getdata(19, 0, "要保留本局成棋譜嗎?(y/N)", ans, sizeof(ans), LCECHO); - if (*ans == 'y') - HO_log_user(pool, my->mateid); +int +gomoku_main(void) +{ + return ChessStartGame('f', SIG_GOMO, "五子棋"); +} -#ifdef GLOBAL_FIVECHESS_LOG - if (me == BBLACK) - HO_log_board(pool, my->mateid); -#endif - } +int +gomoku_personal(void) +{ + gomoku(0, CHESS_MODE_PERSONAL); return 0; } + +int +gomoku_watch(void) +{ + return ChessWatchGame(&gomoku, M_FIVE, "五子棋"); +} diff --git a/mbbsd/menu.c b/mbbsd/menu.c index 770cf71a..a613de8d 100644 --- a/mbbsd/menu.c +++ b/mbbsd/menu.c @@ -583,10 +583,13 @@ static const commands_t playlist[] = { }; static const commands_t chesslist[] = { - {chc_main, PERM_LOGINOK, "11ChessFight 【" ANSI_COLOR(1;33) " 象棋邀局 " ANSI_RESET "】"}, - {chc_personal, PERM_LOGINOK, "22SelfPlay 【" ANSI_COLOR(1;34) " 象棋打譜 " ANSI_RESET "】"}, - {chc_watch, PERM_LOGINOK, "33ChessWatch 【" ANSI_COLOR(1;35) " 象棋觀棋 " ANSI_RESET "】"}, - {GoBot, PERM_LOGINOK, "44GoBot 【" ANSI_COLOR(1;36) " 圍棋打譜 " ANSI_RESET "】"}, + {chc_main, PERM_LOGINOK, "11CChessFight 【" ANSI_COLOR(1;33) " 象棋邀局 " ANSI_RESET "】"}, + {chc_personal, PERM_LOGINOK, "22CChessSelf 【" ANSI_COLOR(1;34) " 象棋打譜 " ANSI_RESET "】"}, + {chc_watch, PERM_LOGINOK, "33CChessWatch 【" ANSI_COLOR(1;35) " 象棋觀棋 " ANSI_RESET "】"}, + {gomoku_main, PERM_LOGINOK, "44GomokuFight 【" ANSI_COLOR(1;33) "五子棋邀局" ANSI_RESET "】"}, + {gomoku_personal, PERM_LOGINOK, "55GomokuSelf 【" ANSI_COLOR(1;34) "五子棋打譜" ANSI_RESET "】"}, + {gomoku_watch, PERM_LOGINOK, "66GomokuWatch 【" ANSI_COLOR(1;35) "五子棋觀棋" ANSI_RESET "】"}, + {GoBot, PERM_LOGINOK, "77GoBot 【" ANSI_COLOR(1;36) " 圍棋打譜 " ANSI_RESET "】"}, {NULL, 0, NULL} }; diff --git a/mbbsd/talk.c b/mbbsd/talk.c index bcf16cf0..920035e8 100644 --- a/mbbsd/talk.c +++ b/mbbsd/talk.c @@ -1429,7 +1429,7 @@ my_talk(userinfo_t * uin, int fri_stat, char defact) ch == DARK || ch == GO || ch == CHESSWATCHING || (!ch && (uin->chatid[0] == 1 || uin->chatid[0] == 3)) || uin->lockmode == M_FIVE || uin->lockmode == CHC) { - if (ch == CHC) { + if (ch == CHC || ch == M_FIVE || ch == CHESSWATCHING) { kill(uin->pid, SIGUSR1); sock = make_connection_to_somebody(uin, 20); if (sock < 0) @@ -1446,7 +1446,16 @@ my_talk(userinfo_t * uin, int fri_stat, char defact) return; } strlcpy(currutmp->mateid, uin->userid, sizeof(currutmp->mateid)); - chc(msgsock, CHESS_MODE_WATCH); + + switch (uin->sig) { + case SIG_CHC: + chc(msgsock, CHESS_MODE_WATCH); + break; + + case SIG_GOMO: + gomoku(msgsock, CHESS_MODE_WATCH); + break; + } } } else @@ -1547,7 +1556,7 @@ my_talk(userinfo_t * uin, int fri_stat, char defact) close(sock); currutmp->sockactive = NA; - if (uin->sig == SIG_CHC) + if (uin->sig == SIG_CHC || uin->sig == SIG_GOMO) ChessEstablishRequest(msgsock); add_io(msgsock, 0); @@ -1576,7 +1585,7 @@ my_talk(userinfo_t * uin, int fri_stat, char defact) chickenpk(msgsock); break; case SIG_GOMO: - gomoku(msgsock); + gomoku(msgsock, CHESS_MODE_VERSUS); break; case SIG_CHC: chc(msgsock, CHESS_MODE_VERSUS); @@ -2971,7 +2980,7 @@ talkreply(void) currutmp->destuid = uip->uid; currstat = REPLY; /* 避免出現動畫 */ - is_chess = (sig == SIG_CHC); + is_chess = (sig == SIG_CHC || sig == SIG_GOMO); a = reply_connection_request(uip); if (a < 0) { @@ -3051,7 +3060,7 @@ talkreply(void) chickenpk(a); break; case SIG_GOMO: - gomoku(a); + gomoku(a, CHESS_MODE_VERSUS); break; case SIG_CHC: chc(a, CHESS_MODE_VERSUS); diff --git a/mbbsd/var.c b/mbbsd/var.c index b6e50000..83ea9924 100644 --- a/mbbsd/var.c +++ b/mbbsd/var.c @@ -267,7 +267,7 @@ char * const ModeTypeTable[MAX_MODES] = { "Ptt查榜系統", /* JCEE */ "重編文章", /* REEDIT */ "部落格", /* BLOGGING */ - "看象棋", /* CHESSWATCHING */ + "看棋", /* CHESSWATCHING */ "下圍棋", /* GO */ "", /* for future usage */ "", @@ -408,7 +408,7 @@ char roll = 0; char msg_occupied = 0; /* gomo.c */ -const char * const bw_chess[] = {"●", "○"}; +const char * const bw_chess[] = {"○", "●"}; unsigned char *pat, *adv; unsigned char * const pat_gomoku /* [1954] */ = /* 0 */ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" |