diff options
Diffstat (limited to 'mbbsd')
-rw-r--r-- | mbbsd/chc.c | 7 | ||||
-rw-r--r-- | mbbsd/chess.c | 244 | ||||
-rw-r--r-- | mbbsd/go.c | 2001 | ||||
-rw-r--r-- | mbbsd/gomo.c | 24 | ||||
-rw-r--r-- | mbbsd/menu.c | 16 | ||||
-rw-r--r-- | mbbsd/talk.c | 14 | ||||
-rw-r--r-- | mbbsd/var.c | 2 |
7 files changed, 912 insertions, 1396 deletions
diff --git a/mbbsd/chc.c b/mbbsd/chc.c index a6b59da3..77b12c41 100644 --- a/mbbsd/chc.c +++ b/mbbsd/chc.c @@ -105,10 +105,12 @@ static const ChessActions chc_actions = { &chc_drawline, &chc_movecur, &chc_prepare_play, + NULL, &chc_select, &chc_prepare_step, (ChessGameResult (*) (void*, const void*)) &chc_movechess, (void (*)(ChessInfo*, const void*)) &chc_drawstep, + NULL, /* post_game */ &chc_gameend, &chc_genlog }; @@ -118,6 +120,7 @@ static const ChessConstants chc_constants = { CHC_TIMEOUT, BRD_ROW, BRD_COL, + 0, "楚河漢界", "photo_cchess", #ifdef GLOBAL_CCHESS_LOG @@ -212,8 +215,6 @@ chc_drawline(const ChessInfo* info, int line) board_p board = (board_p) info->board; chc_tag_data_t *tag = info->tag; - move(line, 0); - clrtoeol(); if (line == 0) { prints(ANSI_COLOR(1;46) " 象棋對戰 " ANSI_COLOR(45) "%30s VS %-20s%10s" ANSI_RESET, @@ -252,7 +253,7 @@ chc_drawline(const ChessInfo* info, int line) prints("%s ", num_str[REDDOWN(info)?1:0][i]); } - ChessDrawExtraInfo(info, line); + ChessDrawExtraInfo(info, line, 8); } /* * End of the drawing function. diff --git a/mbbsd/chess.c b/mbbsd/chess.c index b50ade04..1c5b44d1 100644 --- a/mbbsd/chess.c +++ b/mbbsd/chess.c @@ -16,11 +16,11 @@ #define CHESS_DRAWING_REAL_WARN_ROW 13 #define CHESS_DRAWING_MYWIN_ROW 17 #define CHESS_DRAWING_HISWIN_ROW 18 +#define CHESS_DRAWING_PHOTOED_STEP_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 #define CONNECT_PEER() add_io(info->sock, 0) #define IGNORE_PEER() add_io(0, 0) @@ -39,6 +39,7 @@ static const struct { } ChessReplayMap[] = { { "gomoku", 6, &gomoku_replay }, { "chc", 3, &chc_replay }, + { "go", 2, &gochess_replay }, { NULL } }; @@ -117,11 +118,11 @@ ChessDrawHelpLine(const ChessInfo* info) { /* CHESS_MODE_VERSUS, 對奕 */ ANSI_COLOR(1;33;42) " 下棋 " - ANSI_COLOR(;31;47) " (←↑↓→)" ANSI_COLOR(30) " 移動 " + 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_COLOR(31) "(q)" ANSI_COLOR(30) "認輸 " + ANSI_COLOR(31) "(p)" ANSI_COLOR(30) "虛手/和棋 " + ANSI_COLOR(31) "(u)" ANSI_COLOR(30) "悔棋 " ANSI_RESET, /* CHESS_MODE_WATCH, 觀棋 */ @@ -129,45 +130,54 @@ ChessDrawHelpLine(const ChessInfo* info) ANSI_COLOR(;31;47) " (←→)" ANSI_COLOR(30) " 前後一步 " ANSI_COLOR(31) "(↑↓)" ANSI_COLOR(30) " 前後十步 " ANSI_COLOR(31) "(PGUP/PGDN)" ANSI_COLOR(30) " 最初/目前盤面 " - ANSI_COLOR(31) "(q)" ANSI_COLOR(30) " 離開 " + ANSI_COLOR(31) "(q)" ANSI_COLOR(30) "離開 " ANSI_RESET, /* CHESS_MODE_PERSONAL, 打譜 */ ANSI_COLOR(1;33;42) " 打譜 " - ANSI_COLOR(;31;47) " (←↑↓→)" ANSI_COLOR(30) " 移動 " + ANSI_COLOR(;31;47) " (←↑↓→)" ANSI_COLOR(30) " 移動 " ANSI_COLOR(31) "(空白鍵/ENTER)" ANSI_COLOR(30) " 下子 " - ANSI_COLOR(31) "(q)" ANSI_COLOR(30) " 離開 " - ANSI_COLOR(31) "(u)" ANSI_COLOR(30) " 悔棋 " + ANSI_COLOR(31) "(q)" ANSI_COLOR(30) "離開 " + ANSI_COLOR(31) "(u)" ANSI_COLOR(30) "悔棋 " ANSI_RESET, /* CHESS_MODE_REPLAY, 看譜 */ ANSI_COLOR(1;33;42) " 看譜 " - ANSI_COLOR(;31;47) " (←→)" ANSI_COLOR(30) " 前後一步 " + ANSI_COLOR(;31;47) " (←→)" ANSI_COLOR(30) " 前後一步 " ANSI_COLOR(31) "(↑↓)" ANSI_COLOR(30) " 前後十步 " ANSI_COLOR(31) "(PGUP/PGDN)" ANSI_COLOR(30) " 最初/目前盤面 " - ANSI_COLOR(31) "(q)" ANSI_COLOR(30) " 離開 " + ANSI_COLOR(31) "(q)" ANSI_COLOR(30) "離開 " ANSI_RESET, }; mouts(b_lines, 0, HelpStr[info->mode]); + info->actions->drawline(info, b_lines); } void ChessDrawLine(const ChessInfo* info, int line) { - if (line == b_lines) +#define DRAWLINE(LINE) \ + do { \ + move((LINE), 0); \ + clrtoeol(); \ + info->actions->drawline(info, (LINE)); \ + } while (0) + + if (line == b_lines) { ChessDrawHelpLine(info); - else if (line == CHESS_DRAWING_TURN_ROW) + return; + } 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); + DRAWLINE(CHESS_DRAWING_PHOTOED_TIME_ROW1); + DRAWLINE(CHESS_DRAWING_PHOTOED_TIME_ROW2); } else { - info->actions->drawline(info, CHESS_DRAWING_REAL_TIME_ROW1); - info->actions->drawline(info, CHESS_DRAWING_REAL_TIME_ROW2); + DRAWLINE(CHESS_DRAWING_REAL_TIME_ROW1); + DRAWLINE(CHESS_DRAWING_REAL_TIME_ROW2); } return; } else if (line == CHESS_DRAWING_WARN_ROW) @@ -175,19 +185,22 @@ ChessDrawLine(const ChessInfo* info, int line) CHESS_DRAWING_PHOTOED_WARN_ROW : CHESS_DRAWING_REAL_WARN_ROW; else if (line == CHESS_DRAWING_STEP_ROW) - line = CHESS_DRAWING_REAL_STEP_ROW; + line = info->photo ? + CHESS_DRAWING_PHOTOED_STEP_ROW : + CHESS_DRAWING_REAL_STEP_ROW; - info->actions->drawline(info, line); + DRAWLINE(line); + +#undef DRAWLINE } -static void +void ChessRedraw(const ChessInfo* info) { int i; clear(); - for (i = 0; i < b_lines; ++i) - info->actions->drawline(info, i); - ChessDrawHelpLine(info); + for (i = 0; i <= b_lines; ++i) + ChessDrawLine(info, i); } inline static int @@ -332,7 +345,7 @@ ChessStepReceive(ChessInfo* info, void* step) ChessStepBroadcast(info, step); /* and logging */ - if (result == CHESS_STEP_NORMAL) + if (result == CHESS_STEP_NORMAL || result == CHESS_STEP_PASS) ChessHistoryAppend(info, step); return result; @@ -359,7 +372,34 @@ ChessReplayUntil(ChessInfo* info, int n) info->current_step++; } -static ChessGameResult +static int +ChessAnswerRequest(ChessInfo* info, const char* req_name) +{ + char buf[4]; + char msg[64]; + + snprintf(info->warnmsg, sizeof(info->warnmsg), + ANSI_COLOR(1;31) "要求%s!" ANSI_RESET, req_name); + ChessDrawLine(info, CHESS_DRAWING_WARN_ROW); + bell(); + + snprintf(msg, sizeof(msg), + "對方要求%s,是否接受?(y/N)", req_name); + IGNORE_PEER(); + getdata(b_lines, 0, msg, buf, sizeof(buf), DOECHO); + CONNECT_PEER(); + ChessDrawHelpLine(info); + + info->warnmsg[0] = 0; + ChessDrawLine(info, CHESS_DRAWING_WARN_ROW); + + if (buf[0] == 'y' || buf[0] == 'Y') + return 1; + else + return 0; +} + +ChessGameResult ChessPlayFuncMy(ChessInfo* info) { int last_time = now; @@ -370,7 +410,7 @@ ChessPlayFuncMy(ChessInfo* info) int move_count = 0; #endif - info->ipass = 0; + info->pass[(int) info->turn] = 0; bell(); while (!endturn) { @@ -397,23 +437,14 @@ ChessPlayFuncMy(ChessInfo* info) result == CHESS_STEP_DROP) { game_result = CHESS_RESULT_WIN; endturn = 1; - } else if (result == CHESS_STEP_PASS && info->ipass) { + } else if (result == CHESS_STEP_TIE_ACC) { game_result = CHESS_RESULT_TIE; endturn = 1; - } else if (result == CHESS_STEP_UNDO) { - char buf[4]; - - strcpy(info->warnmsg, ANSI_COLOR(1;31) "要求悔棋!" ANSI_RESET); + } else if (result == CHESS_STEP_TIE_REJ) { + strcpy(info->warnmsg, ANSI_COLOR(1;31) "求和被拒!" ANSI_RESET); ChessDrawLine(info, CHESS_DRAWING_WARN_ROW); - bell(); - - IGNORE_PEER(); - getdata(b_lines, 0, "對方要求悔棋,是否接受?(y/N)", - buf, sizeof(buf), DOECHO); - CONNECT_PEER(); - ChessDrawHelpLine(info); - - if (buf[0] == 'y' || buf[0] == 'Y') { + } else if (result == CHESS_STEP_UNDO) { + if (ChessAnswerRequest(info, "悔棋")) { ChessMessageSend(info, CHESS_STEP_UNDO_ACC); info->actions->init_board(info->board); @@ -426,9 +457,15 @@ ChessPlayFuncMy(ChessInfo* info) endturn = 1; } else ChessMessageSend(info, CHESS_STEP_UNDO_REJ); - - info->warnmsg[0] = 0; - ChessDrawLine(info, CHESS_DRAWING_WARN_ROW); + } else if (result == CHESS_STEP_NORMAL || + result == CHESS_STEP_SPECIAL) { + info->actions->prepare_step(info, &info->step_tmp); + game_result = + info->actions->apply_step(info->board, + &info->step_tmp); + info->actions->drawstep(info, &info->step_tmp); + endturn = 1; + ChessStepMade(info, 0); } break; @@ -494,7 +531,15 @@ ChessPlayFuncMy(ChessInfo* info) break; case 'p': - if (info->mode != CHESS_MODE_PERSONAL) { + if (info->constants->pass_is_step) { + ChessStepType type = CHESS_STEP_PASS; + ChessHistoryAppend(info, &type); + strcpy(info->last_movestr, "虛手"); + + info->pass[(int) info->turn] = 1; + ChessMessageSend(info, CHESS_STEP_PASS); + endturn = 1; + } else if (info->mode != CHESS_MODE_PERSONAL) { char buf[4]; IGNORE_PEER(); getdata(b_lines, 0, "是否真的要和棋?(y/N)", @@ -503,8 +548,7 @@ ChessPlayFuncMy(ChessInfo* info) ChessDrawHelpLine(info); if (buf[0] == 'y' || buf[1] == 'Y') { - info->ipass = 1; - ChessMessageSend(info, CHESS_STEP_PASS); + ChessMessageSend(info, CHESS_STEP_TIE); strlcpy(info->warnmsg, ANSI_COLOR(1;33) "要求和棋!" ANSI_RESET, sizeof(info->warnmsg)); @@ -534,6 +578,17 @@ ChessPlayFuncMy(ChessInfo* info) case ' ': endturn = info->actions->select(info, info->cursor, &game_result); break; + + case I_TIMEOUT: + break; + + default: + if (info->actions->process_key) { + IGNORE_PEER(); + endturn = + info->actions->process_key(info, ch, &game_result); + CONNECT_PEER(); + } } } ChessTimeCountDown(info, 0, now - last_time); @@ -552,6 +607,7 @@ ChessPlayFuncHis(ChessInfo* info) while (!endturn) { ChessStepType result; + int ch; if (ChessTimeCountDown(info, 1, now - last_time)) { info->lefttime[1] = 0; @@ -565,7 +621,7 @@ ChessPlayFuncHis(ChessInfo* info) move(1, 0); oflush(); - switch (igetch()) { + switch (ch = igetch()) { case 'q': { char buf[4]; @@ -582,14 +638,6 @@ ChessPlayFuncHis(ChessInfo* info) } break; - case 'p': - if (info->hepass) { - ChessMessageSend(info, CHESS_STEP_PASS); - game_result = CHESS_RESULT_TIE; - endturn = 1; - } - break; - case 'u': if (info->history.used > 0) { strcpy(info->warnmsg, ANSI_COLOR(1;31) "要求悔棋!" ANSI_RESET); @@ -607,12 +655,21 @@ ChessPlayFuncHis(ChessInfo* info) game_result = CHESS_RESULT_WIN; endturn = 1; } else if (result == CHESS_STEP_PASS) { - info->hepass = 1; - strlcpy(info->warnmsg, - ANSI_COLOR(1;33) "要求和局!" ANSI_RESET, - sizeof(info->warnmsg)); - ChessDrawLine(info, CHESS_DRAWING_WARN_ROW); - } else if (result == CHESS_STEP_NORMAL) { + ChessStepType type = CHESS_STEP_PASS; + strcpy(info->last_movestr, "虛手"); + + info->pass[info->turn] = 1; + endturn = 1; + } else if (result == CHESS_STEP_TIE) { + if (ChessAnswerRequest(info, "和棋")) { + ChessMessageSend(info, CHESS_STEP_TIE_ACC); + + game_result = CHESS_RESULT_TIE; + endturn = 1; + } else + ChessMessageSend(info, CHESS_STEP_TIE_REJ); + } else if (result == CHESS_STEP_NORMAL || + result == CHESS_STEP_SPECIAL) { info->actions->prepare_step(info, &info->step_tmp); switch (info->actions->apply_step(info->board, &info->step_tmp)) { case CHESS_RESULT_LOST: @@ -627,7 +684,7 @@ ChessPlayFuncHis(ChessInfo* info) game_result = CHESS_RESULT_CONTINUE; } endturn = 1; - info->hepass = 0; + info->pass[info->turn] = 0; ChessStepMade(info, 1); info->actions->drawstep(info, &info->step_tmp); } else if (result == CHESS_STEP_UNDO_ACC) { @@ -646,6 +703,17 @@ ChessPlayFuncHis(ChessInfo* info) strcpy(info->warnmsg, ANSI_COLOR(1;31) "悔棋被拒!" ANSI_RESET); ChessDrawLine(info, CHESS_DRAWING_WARN_ROW); } + + case I_TIMEOUT: + break; + + default: + if (info->actions->process_key) { + IGNORE_PEER(); + endturn = + info->actions->process_key(info, ch, &game_result); + CONNECT_PEER(); + } } } ChessTimeCountDown(info, 1, now - last_time); @@ -688,7 +756,8 @@ ChessPlayFuncWatch(ChessInfo* info) ChessRedraw(info); } info->history.used--; - } else if (result == CHESS_STEP_NORMAL) { + } else if (result == CHESS_STEP_NORMAL || + result == CHESS_STEP_SPECIAL) { if (info->current_step == info->history.used - 1) { /* was watching up-to-date board */ info->actions->prepare_step(info, &info->step_tmp); @@ -696,7 +765,9 @@ ChessPlayFuncWatch(ChessInfo* info) info->actions->drawstep(info, &info->step_tmp); info->current_step++; } - } + } else if (result == CHESS_STEP_PASS) + strcpy(info->last_movestr, "虛手"); + break; case KEY_LEFT: /* 往前一步 */ @@ -967,7 +1038,18 @@ ChessPlay(ChessInfo* info) ChessDrawLine(info, CHESS_DRAWING_TURN_ROW); ChessDrawLine(info, CHESS_DRAWING_WARN_ROW); game_result = info->play_func[(int) info->turn](info); + + if (info->constants->pass_is_step && + info->pass[0] && info->pass[1]) + game_result = CHESS_RESULT_END; } + + if (game_result == CHESS_RESULT_END && + info->actions->post_game && + (info->mode == CHESS_MODE_VERSUS || + info->mode == CHESS_MODE_PERSONAL)) + game_result = info->actions->post_game(info); + IGNORE_PEER(); if (info->sock) @@ -1292,19 +1374,19 @@ ChessPhotoInitial(ChessInfo* info) if (fp != NULL) { if (fgets(genbuf, sizeof(genbuf), fp)) { chomp(genbuf); - sprintf(PHOTO(line), "%s ", genbuf); + sprintf(PHOTO(line), "%s", genbuf); } else - strcpy(PHOTO(line), " "); + strcpy(PHOTO(line), " "); } else strcpy(PHOTO(line), blank_photo[line]); switch (line) { - case 0: sprintf(genbuf, "<代號> %s", xuser.userid); break; - case 1: sprintf(genbuf, "<暱稱> %.16s", xuser.nickname); break; - case 2: sprintf(genbuf, "<上站> %d", xuser.numlogins); break; - case 3: sprintf(genbuf, "<文章> %d", xuser.numposts); break; - case 4: sprintf(genbuf, "<職位> %-4s %s", country, level); break; - case 5: sprintf(genbuf, "<來源> %.16s", xuser.lasthost); break; + case 0: sprintf(genbuf, " <代號> %s", xuser.userid); break; + case 1: sprintf(genbuf, " <暱稱> %.16s", xuser.nickname); break; + case 2: sprintf(genbuf, " <上站> %d", xuser.numlogins); break; + case 3: sprintf(genbuf, " <文章> %d", xuser.numposts); break; + case 4: sprintf(genbuf, " <職位> %-4s %s", country, level); break; + case 5: sprintf(genbuf, " <來源> %.16s", xuser.lasthost); break; default: genbuf[0] = 0; } strcat(PHOTO(line), genbuf); @@ -1512,16 +1594,22 @@ ChessTimeStr(int second) } void -ChessDrawExtraInfo(const ChessInfo* info, int line) +ChessDrawExtraInfo(const ChessInfo* info, int line, int space) { + if (line == b_lines || line == 0) + return; + if (info->photo) { if (line >= 3 && line < 3 + CHESS_PHOTO_LINE) { - outs(" "); + if (space > 3) + outs(" "); outs(info->photo + (line - 3) * CHESS_PHOTO_COLUMN); - } else if (line >= CHESS_DRAWING_PHOTOED_TURN_ROW && + } else if (line >= CHESS_DRAWING_PHOTOED_STEP_ROW && line <= CHESS_DRAWING_PHOTOED_WARN_ROW) { - outs(" "); - if (line == CHESS_DRAWING_PHOTOED_TURN_ROW) + prints("%*s", space, ""); + if (line == CHESS_DRAWING_PHOTOED_STEP_ROW) + outs(info->last_movestr); + else 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) { @@ -1561,7 +1649,7 @@ ChessDrawExtraInfo(const ChessInfo* info, int line) outs(info->warnmsg); } } else if (line >= 3 && line <= CHESS_DRAWING_HISWIN_ROW) { - outs(" "); + prints("%*s", space, ""); if (line >= 3 && line < 3 + (int)dim(ChessHintStr)) { outs(ChessHintStr[line - 3]); } else if (line == CHESS_DRAWING_SIDE_ROW) { @@ -1,550 +1,357 @@ /* $Id$ */ -/*-------------------------------------------------------*/ -/* go.c ( NTU FPG BBS Ver 1.00 ) */ -/*-------------------------------------------------------*/ -/* target : 圍棋 */ -/* create : 01/09/00 */ -/*-------------------------------------------------------*/ #include "bbs.h" #include <sys/socket.h> -#define BBLANK (0) /* 空白 */ -#define BBLACK (1) /* 黑子 */ -#define BWHITE (2) /* 白子 */ +#define BBLANK (-1) /* 空白 */ +#define BWHITE (0) /* 白子, 後手 */ +#define BBLACK (1) /* 黑子, 先手 */ +#define LWHITE (2) /* 白空 */ +#define LBLACK (3) /* 黑空 */ -#define redoln() redoscr() +/* only used for communicating */ +#define SETHAND (5) /* 讓子 */ +#define CLEAN (6) /* 清除死子 */ +#define UNCLEAN (7) /* 清除錯子,重新來過*/ +#define CLEANDONE (8) /* 開始計地 */ + +#define MAX_TIME (300) + +#define BOARD_LINE_ON_SCREEN(X) ((X) + 2) #define BRDSIZ (19) /* 棋盤單邊大小 */ -/* FIXME 當游標在棋盤邊緣, 再繼續移, cursor 會跑掉 */ -#define move(y,x) move(y, (x) + ((y) < 2 || (y) > 20 ? 0 : \ - (x) > 43 ? 11 : 8)) -#define iBGOTO(x,y) move(20 - (y) , (x) * 2 + 4 - 8),do_move(20-(y),(x)*2+4) // really dirty >< -#define BGOTO(x,y) move(20 - (y) , (x) * 2 + 4),do_move(20-(y),(x)*2+4) - -struct GOData { - unsigned char go[BRDSIZ][BRDSIZ]; - unsigned char l[BRDSIZ][BRDSIZ]; - unsigned char ml[BRDSIZ][BRDSIZ]; - Horder_t pool[500]; - int lib, mik, mjk, hik, hjk, mk, hk; - float win; - char AB[41]; - - unsigned char me, he, hand; +static const char* turn_color[] = { ANSI_COLOR(37;43), ANSI_COLOR(30;43) }; + +static const rc_t SetHandPoints[] = +{ + /* 1 */ { 0, 0}, + /* 2 */ { 3, 3}, {15, 15}, + /* 3 */ { 3, 3}, { 3, 15}, {15, 15}, + /* 4 */ { 3, 3}, { 3, 15}, {15, 3}, {15, 15}, + /* 5 */ { 3, 3}, { 3, 15}, { 9, 9}, {15, 3}, {15, 15}, + /* 6 */ { 3, 3}, { 3, 15}, { 9, 3}, { 9, 15}, {15, 3}, {15, 15}, + /* 7 */ { 3, 3}, { 3, 15}, { 9, 3}, { 9, 9}, { 9, 15}, {15, 3}, + {15, 15}, + /* 8 */ { 3, 3}, { 3, 9}, { 3, 15}, { 9, 3}, { 9, 15}, {15, 3}, + {15, 9}, {15, 15}, + /* 9 */ { 3, 3}, { 3, 9}, { 3, 15}, { 9, 3}, { 9, 9}, { 9, 15}, + {15, 3}, {15, 9}, {15, 15}, }; -//extern char *bw_chess[]; /* 和五子棋共用 */ +typedef char board_t[BRDSIZ][BRDSIZ]; +typedef char (*board_p)[BRDSIZ]; + +typedef struct { + ChessStepType type; /* necessary one */ + int color; + rc_t loc; +} go_step_t; +#define RC_T_EQ(X,Y) ((X).r == (Y).r && (X).c == (Y).c) + +typedef struct { + board_t backup_board; + char game_end; + char clean_end; /* bit 1 => I, bit 2 => he */ + char need_redraw; + float feed_back; /* 貼還 */ + int eaten[2]; + int backup_eaten[2]; + rc_t forbidden[2]; /* 打劫之禁手 */ +} go_tag_t; +#define GET_TAG(INFO) ((go_tag_t*)(INFO)->tag) static char * const locE = "ABCDEFGHJKLMNOPQRST"; +static void go_init_user(const userinfo_t* uinfo, ChessUser* user); +static void go_init_user_userec(const userec_t* urec, ChessUser* user); +static void go_init_board(board_t board); +static void go_drawline(const ChessInfo* info, int line); +static void go_movecur(int r, int c); +static void go_prepare_play(ChessInfo* info); +static int go_process_key(ChessInfo* info, int key, ChessGameResult* result); +static int go_select(ChessInfo* info, rc_t location, + ChessGameResult* result); +static void go_prepare_step(ChessInfo* info, const go_step_t* step); +static ChessGameResult go_apply_step(board_t board, const go_step_t* step); +static void go_drawstep(ChessInfo* info, const go_step_t* step); +static ChessGameResult go_post_game(ChessInfo* info); +static void go_gameend(ChessInfo* info, ChessGameResult result); +static void go_genlog(ChessInfo* info, FILE* fp, ChessGameResult result); + +const static ChessActions go_actions = { + &go_init_user, + &go_init_user_userec, + (void (*)(void*)) &go_init_board, + &go_drawline, + &go_movecur, + &go_prepare_play, + &go_process_key, + &go_select, + (void (*)(ChessInfo*, const void*)) &go_prepare_step, + (ChessGameResult (*)(void*, const void*)) &go_apply_step, + (void (*)(ChessInfo*, const void*)) &go_drawstep, + &go_post_game, + &go_gameend, + &go_genlog +}; -static Horder_t *v; - -static void -GO_init(struct GOData *gd) -{ - memset(gd, 0, sizeof(struct GOData)); - v = gd->pool; -} +const static ChessConstants go_constants = { + sizeof(go_step_t), + MAX_TIME, + BRDSIZ, + BRDSIZ, + 1, + "圍棋", + "photo_go", +#ifdef GLOBAL_GOCHESS_LOG + GLOBAL_GOCHESS_LOG, +#else + NULL, +#endif + { ANSI_COLOR(37;43), ANSI_COLOR(30;43) }, + { "白棋", "黑棋" }, +}; static void -GO_add(struct GOData *gd, Horder_t *mv) +go_sethand(board_t board, int n) { - if (v < gd->pool + 500) - *v++ = *mv; + if (n >= 2 && n <= 9) { + const int lower = n * (n - 1) / 2; + const int upper = lower + n; + int i; + for (i = lower; i < upper; ++i) + board[SetHandPoints[i].r][SetHandPoints[i].c] = BBLACK; + } } +/* 計算某子的氣數, recursion part of go_countlib() */ static int -GO_sethand(struct GOData *gd, int i) +go_count(board_t board, board_t mark, int x, int y, int color) { - int j; - char tmp[5]; - unsigned char (*go)[BRDSIZ]=gd->go; - - if (i > 0 && i < 10) - { - move(1, 71); - prints("讓子:%d", i); - - gd->win = 0; - go[3][3] = BBLACK; - if (i > 1) - { - go[15][15] = BBLACK; - if (i > 2) - { - go[3][15] = BBLACK; - if (i > 3) - { - go[15][3] = BBLACK; - if (i == 5) - go[9][9] = BBLACK; - else - if (i > 5) - { - go[9][15] = BBLACK; - go[9][3] = BBLACK; - if (i == 7) - go[9][9] = BBLACK; - else - if (i > 7) - { - go[15][9] = BBLACK; - go[3][9] = BBLACK; - if (i > 8) - go[9][9] = BBLACK; - } - } - } - } + const static int diff[][2] = { + {1, 0}, {-1, 0}, {0, 1}, {0, -1} + }; + int i; + int total = 0; + + mark[x][y] = 0; + + for (i = 0; i < 4; ++i) { + int xx = x + diff[i][0]; + int yy = y + diff[i][1]; + + if (xx >= 0 && xx < BRDSIZ && yy >= 0 && yy < BRDSIZ) { + if (board[xx][yy] == BBLANK && mark[xx][yy]) { + ++total; + mark[xx][yy] = 0; + } else if (board[xx][yy] == color && mark[xx][yy]) + total += go_count(board, mark, xx, yy, color); } } - else - return 0; - - gd->hand = i; - *gd->AB = 0; - for (i = 0;i < 19;i++) - for (j = 0;j < 19;j++) - if (go[i][j]) - { - BGOTO(i, j); - outs(bw_chess[go[i][j] - 1]); - redoln(); - sprintf(tmp, "[%c%c]", 'a' + i, 's' - j); - strcat(gd->AB, tmp); - } - return 1; -} - - -static void -GO_count(struct GOData *gd, int x, int y, int color) -{ - unsigned char (*go)[BRDSIZ]=gd->go; - unsigned char (*ml)[BRDSIZ]=gd->ml; - ml[x][y] = 0; - if (x != 0) - { - if ((go[x - 1][y] == BBLANK) && ml[x - 1][y]) - { - ++gd->lib; - ml[x - 1][y] = 0; - } - else - if ((go[x - 1][y] == color) && ml[x - 1][y]) - GO_count(gd, x - 1, y, color); - } - if (x != 18) - { - if ((go[x + 1][y] == BBLANK) && ml[x + 1][y]) - { - ++gd->lib; - ml[x + 1][y] = 0; - } - else - if ((go[x + 1][y] == color) && ml[x + 1][y]) - GO_count(gd, x + 1, y, color); - } - if (y != 0) - { - if ((go[x][y - 1] == BBLANK) && ml[x][y - 1]) - { - ++gd->lib; - ml[x][y - 1] = 0; - } - else - if ((go[x][y - 1] == color) && ml[x][y - 1]) - GO_count(gd, x, y - 1, color); - } - if (y != 18) - { - if ((go[x][y + 1] == BBLANK) && ml[x][y + 1]) - { - ++gd->lib; - ml[x][y + 1] = 0; - } - else - if ((go[x][y + 1] == color) && ml[x][y + 1]) - GO_count(gd, x, y + 1, color); - } + return total; } -static void -GO_countlib(struct GOData *gd, int x, int y, char color) +/* 計算某子的氣數 */ +static int +go_countlib(board_t board, int x, int y, char color) { int i, j; + board_t mark; - for (i = 0; i < 19; i++) - for (j = 0; j < 19; j++) - gd->ml[i][j] = 1; + for (i = 0; i < BRDSIZ; i++) + for (j = 0; j < BRDSIZ; j++) + mark[i][j] = 1; - GO_count(gd, x, y, color); + return go_count(board, mark, x, y, color); } +/* 計算盤面上每個子的氣數 */ static void -GO_eval(struct GOData *gd, char color) +go_eval(board_t board, int lib[][BRDSIZ], char color) { int i, j; for (i = 0; i < 19; i++) for (j = 0; j < 19; j++) - if (gd->go[i][j] == color) - { - gd->lib = 0; - GO_countlib(gd, i, j, color); - gd->l[i][j] = gd->lib; - } + if (board[i][j] == color) + lib[i][j] = go_countlib(board, i, j, color); } +/* 檢查一步是否合法 */ static int -GO_check(struct GOData *gd, Horder_t *mv) +go_check(ChessInfo* info, const go_step_t* step) { - int m, n, k; - unsigned char (*go)[BRDSIZ]=gd->go; - unsigned char (*l)[BRDSIZ]=gd->l; - - gd->lib = 0; - GO_countlib(gd, mv->x, mv->y, gd->me); - - if (gd->lib == 0) - { - go[(int)mv->x][(int)mv->y] = gd->me; - - GO_eval(gd, gd->he); - k = 0; - - for (m = 0; m < 19; m++) - for (n = 0; n < 19; n++) - if ((go[m][n] == gd->he) && !l[m][n]) ++k; - - if ((k == 0) || (k == 1 && ((mv->x == gd->mik) && (mv->y == gd->mjk)))) - { - go[(int)mv->x][(int)mv->y] = BBLANK; /* restore to open */ + board_p board = (board_p) info->board; + int lib = go_countlib(board, step->loc.r, step->loc.c, step->color); + + if (lib == 0) { + int i, j; + int board_lib[BRDSIZ][BRDSIZ]; + go_tag_t* tag = (go_tag_t*) info->tag; + + board[step->loc.r][step->loc.c] = step->color; + go_eval(board, board_lib, !step->color); + board[step->loc.r][step->loc.c] = BBLANK; /* restore to open */ + + lib = 0; + for (i = 0; i < BRDSIZ; i++) + for (j = 0; j < BRDSIZ; j++) + if (board[i][j] == !step->color && !board_lib[i][j]) + ++lib; + + if (lib == 0 || + (lib == 1 && RC_T_EQ(step->loc, tag->forbidden[step->color]))) return 0; - } else return 1; - } - else + } else return 1; } -static void -GO_blank(char x, char y) -{ - char *str = "┌┬┐├┼┤└┴┘"; - int n1, n2, loc; - - BGOTO(x, y); - n1 = (x == 0) ? 0 : (x == 18) ? 2 : 1; - n2 = (y == 18) ? 0 : (y == 0) ? 2 : 1; - loc= 2 * (n2 * 3 + n1); - prints("%.2s", str + loc); - //redoln(); -} - -static void -GO_examboard(struct GOData *gd, char color) +/* Clean up the dead chess of color `color,' summarize number of + * eaten chesses and set the forbidden point. + * + * `info' might be NULL which means no forbidden point check is + * needed and don't have to count the number of eaten chesses. + * + * Return: 1 if any chess of color `color' was eaten; 0 otherwise. */ +static int +go_examboard(board_t board, int color, ChessInfo* info) { int i, j, n; - unsigned char (*go)[BRDSIZ]=gd->go; - unsigned char (*l)[BRDSIZ]=gd->l; + int lib[BRDSIZ][BRDSIZ]; - GO_eval(gd, color); + rc_t dummy_rc; + rc_t *forbidden; + int dummy_eaten; + int *eaten; - if (color == gd->he) - { - gd->hik = -1; - gd->hjk = -1; + if (info) { + go_tag_t* tag = (go_tag_t*) info->tag; + forbidden = &tag->forbidden[color]; + eaten = &tag->eaten[!color]; + } else { + forbidden = &dummy_rc; + eaten = &dummy_eaten; } - else - { - gd->mik = -1; - gd->mjk = -1; - } - n = 0; - for (i = 0; i < 19; i++) - for (j = 0; j < 19; j++) - if ((go[i][j] == color) && (l[i][j] == 0)) - { - go[i][j] = BBLANK; - GO_blank(i, j); - if (color == gd->he) - { - gd->hik = i; - gd->hjk = j; - ++gd->hk; - } - else - { - gd->mik = i; - gd->mjk = j; - ++gd->mk; - } + go_eval(board, lib, color); + + forbidden->r = -1; + forbidden->c = -1; + + n = 0; + for (i = 0; i < BRDSIZ; i++) + for (j = 0; j < BRDSIZ; j++) + if (board[i][j] == color && lib[i][j] == 0) { + board[i][j] = BBLANK; + forbidden->r = i; + forbidden->c = j; + ++*eaten; ++n; } - if (color == gd->he && n > 1) - { - gd->hik = -1; - gd->hjk = -1; + if ( n != 1 ) { + /* No or more than one chess were eaten, + * no forbidden points, then. */ + forbidden->r = -1; + forbidden->c = -1; } - else if ( n > 1 ) - { - gd->mik = -1; - gd->mjk = -1; - } -} - -static void -GO_clean(struct GOData *gd, int fd, int x, int y, int color) -{ - Horder_t tmp; - unsigned char (*go)[BRDSIZ]=gd->go; - unsigned char (*ml)[BRDSIZ]=gd->ml; - ml[x][y] = 0; - - go[x][y] = BBLANK; - GO_blank(x, y); - - tmp.x = x; - tmp.y = y; - - if (send(fd, &tmp, sizeof(Horder_t), 0) != sizeof(Horder_t)) - return; - - if (x != 0) - { - if ((go[x - 1][y] == color) && ml[x - 1][y]) - GO_clean(gd, fd, x - 1, y, color); - } - if (x != 18) - { - if ((go[x + 1][y] == color) && ml[x + 1][y]) - GO_clean(gd, fd, x + 1, y, color); - } - if (y != 0) - { - if ((go[x][y - 1] == color) && ml[x][y - 1]) - GO_clean(gd, fd, x, y - 1, color); - } - if (y != 18) - { - if ((go[x][y + 1] == color) && ml[x][y + 1]) - GO_clean(gd, fd, x, y + 1, color); - } + return (n > 0); } -static void -GO_cleandead(struct GOData *gd, int fd, char x, char y, char color) +static int +go_clean(board_t board, int mark[][BRDSIZ], int x, int y, int color) { - int i, j; - - for (i = 0; i < 19; i++) - for (j = 0; j < 19; j++) - gd->ml[i][j] = 1; + const static int diff[][2] = { + {1, 0}, {-1, 0}, {0, 1}, {0, -1} + }; + int i; + int total = 1; + + mark[x][y] = 0; + board[x][y] = BBLANK; + + for (i = 0; i < 4; ++i) { + int xx = x + diff[i][0]; + int yy = y + diff[i][1]; + + if (xx >= 0 && xx < BRDSIZ && yy >= 0 && yy < BRDSIZ) { + if ((board[xx][yy] == color) && mark[xx][yy]) + total += go_clean(board, mark, xx, yy, color); + } + } - GO_clean(gd, fd, x, y, color); + return total; } -static void -GO_log(struct GOData *gd, char *userid) +static int +go_cleandead(board_t board, int x, int y) { - fileheader_t mymail; - char title[128], buf[80]; - int i = 0; - FILE *fp; - Horder_t *ptr = gd->pool; - //extern screenline *big_picture; - - sethomepath(buf, cuser.userid); - stampfile(buf, &mymail); - - fp = fopen(buf, "w"); - for(i = 1; i < 21; i++) - fprintf(fp, "%.*s\n", big_picture[i].len, big_picture[i].data + 1); - - i = 0; - - fprintf(fp, "\n"); - - do - { - if (ptr->x == -1 || ptr->y == -1) - fprintf(fp, "[%3d]%s => %c", i + 1, gd->win ? bw_chess[i % 2] : bw_chess[(i + 1) % 2], - (i % 5) == 4 ? '\n' : '\t'); - else - fprintf(fp, "[%3d]%s => %.1s%d%c", i + 1, gd->win ? bw_chess[i % 2] : bw_chess[(i + 1) % 2], - locE + ptr->x, ptr->y + 1, (i % 5) == 4 ? '\n' : '\t'); - i++; - - } while (++ptr < v); - - fprintf(fp, "\n\n《以下為 sgf 格式棋譜》\n<golog>\n(;GM[1]"); - if (userid == NULL) - fprintf(fp, "GN[Gobot-Gobot FPG]\n"); - else - fprintf(fp, "GN[%s-%s(%c) FPG]\n", userid, cuser.userid, gd->me == BBLACK ? 'B' : 'W'); - fprintf(fp, "SZ[19]HA[%d]", gd->hand); - if (userid == NULL) - { - fprintf(fp, "PB[Gobot]PW[Gobot]\n"); - } - else - { - if (gd->me == BBLACK) - fprintf(fp, "PB[%s]PW[%s]\n", cuser.userid, userid); - else - fprintf(fp, "PB[%s]PW[%s]\n", userid, cuser.userid); - } - fprintf(fp, "PC[FPG BBS/Ptt BBS: ptt.cc]\n"); - - if (gd->win) - i = 0; - else - { - i = 1; - fprintf(fp, "AB%s\n", gd->AB); - } - ptr = gd->pool; - do - { - if (ptr->x == -1 || ptr->y == -1) - fprintf(fp, ";%c[]%c", i % 2 ? 'W' : 'B', (i % 10) == 9 ? '\n' : ' '); - else - fprintf(fp, ";%c[%c%c]%c", i % 2 ? 'W' : 'B', 'a' + ptr->x, 's' - ptr->y, (i % 10) == 9 ? '\n' : ' '); - - i++; - } while (++ptr < v); + int mark[BRDSIZ][BRDSIZ]; + int i, j; - fprintf(fp, ";)\n<golog>\n\n"); - fclose(fp); + if (board[x][y] == BBLANK) + return 0; - mymail.filemode = FILE_READ; + for (i = 0; i < BRDSIZ; i++) + for (j = 0; j < BRDSIZ; j++) + mark[i][j] = 1; - strcpy(mymail.owner, "[備.忘.錄]"); - if (userid == NULL) - { - strcpy(mymail.title, "圍棋打譜"); - } - else - snprintf(mymail.title, sizeof(mymail.title), - ANSI_COLOR(37;41) "棋譜" ANSI_RESET " %s VS %s", cuser.userid, userid); - - sethomedir(title, cuser.userid); - append_record(title, &mymail, sizeof(mymail)); + return go_clean(board, mark, x, y, board[x][y]); } static int -go_key(struct GOData *gd, int fd, int ch, Horder_t *mv) -{ - if (ch >= 'a' && ch <= 's' && ch != 'i') - { - char pbuf[4]; - int vx, vy; - - pbuf[0] = ch; - pbuf[1] = 0; - - if (fd) add_io(0, 0); - getdata(21, 9, "直接指定位置(1 - 19):", pbuf, 4, DOECHO); - if (fd) add_io(fd, 0); - move(21, 9); - clrtoeol(); - //outs(" "); - - vx = ch - 'a'; - if (ch > 'i') - vx--; - vy = atoi(pbuf) - 1; - if( vx >= 0 && vx < BRDSIZ && vy >= 0 && vy < BRDSIZ && gd->go[vx][vy] == BBLANK) - { - mv->x = vx; - mv->y = vy; - return 1; - } - } - else - { - switch(ch) - { - case KEY_RIGHT: - mv->x = (mv->x == BRDSIZ - 1) ? mv->x : mv->x + 1; - break; - case KEY_LEFT: - mv->x = (mv->x == 0 ) ? 0 : mv->x - 1; - break; - case KEY_UP: - mv->y = (mv->y == BRDSIZ - 1) ? mv->y : mv->y + 1; - break; - case KEY_DOWN: - mv->y = (mv->y == 0 ) ? 0 : mv->y - 1; - break; - case ' ': - case '\r': - case '\n': - if (gd->go[(int)mv->x][(int)mv->y] == BBLANK && GO_check(gd, mv)) - return 1; - } - } - return 0; -} - -static unsigned char -GO_findcolor(struct GOData *gd, int x, int y) +go_findcolor(board_p board, int x, int y) { int k, result = 0, color[4]; - unsigned char (*go)[BRDSIZ]=gd->go; - if (go[x][y] != BBLANK) - return 0; + if (board[x][y] != BBLANK) + return BBLANK; if (x > 0) { k = x; do --k; - while ((go[k][y] == BBLANK) && (k > 0)); - color[0] = go[k][y]; + while ((board[k][y] == BBLANK) && (k > 0)); + color[0] = board[k][y]; } else - color[0] = go[x][y]; + color[0] = board[x][y]; if (x < 18) { k = x; do ++k; - while ((go[k][y] == BBLANK) && (k < 18)); - color[1] = go[k][y]; + while ((board[k][y] == BBLANK) && (k < 18)); + color[1] = board[k][y]; } else - color[1] = go[x][y]; + color[1] = board[x][y]; if (y > 0) { k = y; do --k; - while ((go[x][k] == BBLANK) && (k > 0)); - color[2] = go[x][k]; + while ((board[x][k] == BBLANK) && (k > 0)); + color[2] = board[x][k]; } - else color[2] = go[x][y]; + else color[2] = board[x][y]; if (y < 18) { k = y; do ++k; - while ((go[x][k] == BBLANK) && (k < 18)); - color[3] = go[x][k]; + while ((board[x][k] == BBLANK) && (k < 18)); + color[3] = board[x][k]; } else - color[3] = go[x][y]; + color[3] = board[x][y]; - for (k = 0;k < 4;k++) + for (k = 0; k < 4; k++) { if (color[k] == BBLANK) continue; @@ -554,944 +361,562 @@ GO_findcolor(struct GOData *gd, int x, int y) break; } } + if (k == 4) + return BBLANK; - for (k = 0;k < 4;k++) + for (k = 0; k < 4; k++) { if ((color[k] != BBLANK) && (color[k] != result)) - return 0; + return BBLANK; } return result; } static int -GO_result(struct GOData *gd) +go_result(ChessInfo* info) { - int i, j, result; - float count[2]; - char *chessresult[] = { "•", "。" }; - unsigned char (*go)[BRDSIZ]=gd->go; + int i, j; + int count[2]; + board_p board = (board_p) info->board; + go_tag_t *tag = (go_tag_t*) info->tag; + board_t result_board; + memcpy(result_board, board, sizeof(result_board)); count[0] = count[1] = 0; for (i = 0; i < 19; i++) for (j = 0; j < 19; j++) - if (go[i][j] == BBLANK) + if (board[i][j] == BBLANK) { - result = GO_findcolor(gd, i, j); - BGOTO(i, j); - if (result) - { - outs(chessresult[result - 1]); - count[result - 1]++; - } - else - { - outs("×"); - gd->win -= 0.5; + int result = go_findcolor(board, i, j); + if (result != BBLANK) { + count[result]++; + + /* BWHITE => LWHITE, BBLACK => LBLACK */ + result_board[i][j] = result + 2; } } else - count[go[i][j] - 1]++; - redoscr(); + count[(int) board[i][j]]++; - if (gd->me == BBLACK) - { - move(5, 46); - prints("%s 方目數:%-3.1f ", bw_chess[gd->me - 1], count[0]); - move(6, 46); - prints("%s 方目數:%-3.1f ", bw_chess[gd->he - 1], count[1]); - move(21, 46); - clrtoeol(); - move(8, 46); - - if (count[0] > 181 + gd->win) - return 1; - } + memcpy(board, result_board, sizeof(result_board)); + + /* 死子回填 */ + count[0] -= tag->eaten[1]; + count[1] -= tag->eaten[0]; + + tag->eaten[0] = count[0]; + tag->eaten[1] = count[1]; + + if (tag->feed_back < 0.01 && tag->eaten[0] == tag->eaten[1]) + return BBLANK; /* tie */ else - { - move(5, 46); - prints("%s 方目數:%-3.1f ", bw_chess[gd->me - 1], count[1]); - move(6, 46); - prints("%s 方目數:%-3.1f ", bw_chess[gd->he - 1], count[0]); - move(21, 46); - clrtoeol(); - move(8, 46); - - if (count[0] <= 181 + gd->win) - return 1; - } - return 0; + return tag->eaten[0] + tag->feed_back > tag->eaten[1] ? + BWHITE : BBLACK; } -void -GO_cleantable(void) +static char* +go_getstep(const go_step_t* step, char buf[]) { - move(1, 0); -#define AC ANSI_COLOR(30;43) -#define AR ANSI_RESET - outs( - " A B C D E F G H J K L M N O P Q R S T\n" - " 19" AC " ┌┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┐ " AR "\n" - " 18" AC " ├┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┤ " AR "\n" - " 17" AC " ├┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┤ " AR "\n" - " 16" AC " ├┼┼+┼┼┼┼┼+┼┼┼┼┼+┼┼┤ " AR "\n" - " 15" AC " ├┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┤ " AR "\n" - " 14" AC " ├┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┤ " AR "\n" - " 13" AC " ├┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┤ " AR "\n" - " 12" AC " ├┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┤ " AR "\n" - " 11" AC " ├┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┤ " AR "\n" - " 10" AC " ├┼┼+┼┼┼┼┼+┼┼┼┼┼+┼┼┤ " AR "\n" - " 9" AC " ├┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┤ " AR "\n" - " 8" AC " ├┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┤ " AR "\n" - " 7" AC " ├┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┤ " AR "\n" - " 6" AC " ├┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┤ " AR "\n" - " 5" AC " ├┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┤ " AR "\n" - " 4" AC " ├┼┼+┼┼┼┼┼+┼┼┼┼┼+┼┼┤ " AR "\n" - " 3" AC " ├┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┤ " AR "\n" - " 2" AC " ├┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┤ " AR "\n" - " 1" AC " └┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┘ " AR "\n" - ); + const static char* const ColName = "ABCDEFGHJKLMNOPQRST"; + const static char* const RawName = "19181716151413121110987654321"; + const static int ansi_length = sizeof(ANSI_COLOR(30;43)) - 1; + + 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; } -int -gochess(int fd) +static void +go_init_tag(go_tag_t* tag) { - Horder_t mv; - userinfo_t *my = currutmp; - time4_t mtime, htime, btime; - int i, j, ch = 0, passflag, endflag, totalgo, timeflag, is_view; - unsigned char mhand, hhand; - int scr_need_redraw = 1; - - struct GOData gd; - unsigned char (*go)[BRDSIZ]=gd.go; - unsigned char (*l)[BRDSIZ]=gd.l; - Horder_t *pool=gd.pool; - - GO_init(&gd); - - gd.hk = gd.mk = 0; - totalgo = 0; - gd.hik = gd.hjk = -1; - gd.mik = gd.mjk = -1; - mhand = hhand = 250; /* 不太可能一分鐘內下這麼多手 :p */ - mtime = htime = 60; /* 一開始的一分鐘內不計手 */ - gd.win = 3.5; - - gd.me = !(my->turn) + 1; - gd.he = my->turn + 1; - if (gd.me > 2) gd.me = 2; - if (gd.he > 2) gd.he = 2; - - endflag = passflag = timeflag = 0; - is_view = 1; - - setutmpmode(GO); - - clear(); - - /* 觀戰用程式碼, 與 ptt 不相容 - if (gd.me == BWHITE) - { - VIEWCHESS vs; - - memset(&vs, 0, sizeof(VIEWCHESS)); - strcpy(vs.userid[0], cuser.userid); - strcpy(vs.userid[1], my->mateid); - if (cshm_new(&vs) == -1) - is_view = 0; - } - */ - - prints(ANSI_COLOR(1;46) " 圍棋對戰 " ANSI_COLOR(45) "%31s VS %-31s" ANSI_RESET, - cuser.userid, my->mateid); - GO_cleantable(); - - /* film_out(FILM_GO, 1); */ - - add_io(fd, 0); - - mv.x = mv.y = 9; - btime = now; - - for(;;) - { - if(scr_need_redraw){ - move(2, 46); - prints("%s 方提子數:%3d", bw_chess[gd.me - 1], gd.hk); - move(3, 46); - prints("%s 方提子數:%3d", bw_chess[gd.he - 1], gd.mk); - - move(8, 46); - clrtoeol(); - if (endflag) - outs("請清除死子,以便計算勝負"); - else if (my->turn) - prints("輪到自己下了.... 我是 %s", bw_chess[gd.me - 1]); - else - outs("等待對方下子...."); - - - move(10, 46); - clrtoeol(); - if (totalgo > 0) - { - if (pool[totalgo - 1].x == -1 || pool[totalgo - 1].y == -1) - prints("%s #%-3d PASS 上一手 ", gd.win ? bw_chess[(totalgo - 1) & 1] : bw_chess[totalgo & 1], totalgo); - else - prints("%s #%-3d %.1s%-2d 上一手 ", gd.win ? bw_chess[(totalgo - 1) & 1] : bw_chess[totalgo & 1], totalgo, locE + pool[totalgo - 1].x, pool[totalgo - 1].y + 1); - } - - for (i = totalgo - 1;i > 0 && totalgo - i <= 10;i--) - { - move(10 + totalgo - i, 46); - clrtoeol(); - if (pool[i - 1].x == -1 || pool[i - 1].y == -1) - prints("%s #%-3d PASS", gd.win ? bw_chess[(i - 1) & 1] : bw_chess[i & 1], i); - else - prints("%s #%-3d %.1s%-2d ", gd.win ? bw_chess[(i - 1) & 1] : bw_chess[i & 1], i, locE + pool[i - 1].x, pool[i - 1].y + 1); - } - - move(21, 46); + tag->game_end = 0; + tag->need_redraw = 0; + tag->feed_back = 5.5; + tag->eaten[0] = 0; + tag->eaten[1] = 0; + tag->forbidden[0].r = -1; + tag->forbidden[0].c = -1; + tag->forbidden[1].r = -1; + tag->forbidden[1].c = -1; +} - if (v == pool) - { - if (gd.me == BWHITE && gd.win != 0) - outs(ANSI_COLOR(1;33) "按 x 讓子 y 不限時 Ctrl-C 中止棋局" ANSI_RESET); - else - outs(ANSI_COLOR(1;33) "按 Ctrl-C 中止棋局" ANSI_RESET); - } - else if (passflag && my->turn) - { - if (endflag) - outs(ANSI_COLOR(1;33) "對方 DONE,己方 DONE 就計算結果" ANSI_RESET); - else - outs(ANSI_COLOR(1;33) "對方 PASS,己方 PASS 就結束棋局" ANSI_RESET); - } - else if (v > pool) - clrtoeol(); +static void +go_init_user(const userinfo_t* uinfo, ChessUser* user) +{ + strlcpy(user->userid, uinfo->userid, sizeof(user->userid)); + user->win = 0; + user->lose = 0; + user->tie = 0; +} - if (endflag) - outmsg(ANSI_COLOR(1;33;42) " 下棋 " ANSI_COLOR(;31;47) " (←↑↓→)" ANSI_COLOR(30) "移動 " ANSI_COLOR(31) "(空白鍵/ENTER)" ANSI_COLOR(30) "下子 " ANSI_COLOR(31) "(v)" ANSI_COLOR(30) "傳訊 " ANSI_COLOR(31) "(z)" ANSI_COLOR(30) "投降 " ANSI_COLOR(31) "(w)" ANSI_COLOR(30) "DONE " ANSI_COLOR(31) "(u)" ANSI_COLOR(30) "回復 " ANSI_RESET); - else - outmsg(ANSI_COLOR(1;33;42) " 下棋 " ANSI_COLOR(;31;47) " (←↑↓→)" ANSI_COLOR(30) "移動 " ANSI_COLOR(31) "(空白鍵/ENTER)" ANSI_COLOR(30) "下子 " ANSI_COLOR(31) "(v)" ANSI_COLOR(30) "傳訊 " ANSI_COLOR(31) "(z)" ANSI_COLOR(30) "投降 " ANSI_COLOR(31) "(w)" ANSI_COLOR(30) "PASS " ANSI_RESET); +static void +go_init_user_userec(const userec_t* urec, ChessUser* user) +{ + strlcpy(user->userid, urec->userid, sizeof(user->userid)); + user->win = 0; + user->lose = 0; + user->tie = 0; +} - redoscr(); - scr_need_redraw = 0; - } +static void +go_init_board(board_t board) +{ + memset(board, BBLANK, sizeof(board_t)); +} - if (endflag || timeflag) - { - char buf[128]; - int n; - //move(5, 46); - n = sprintf(buf, ANSI_MOVETO(6,47) "%s 方時間:----- --", bw_chess[gd.me - 1]); - output(buf, n); - //move(6, 46); - n = sprintf(buf, ANSI_MOVETO(7,47) "%s 方時間:----- --", bw_chess[gd.he - 1]); - output(buf, n); - } - else - { - if (my->turn) - { - mtime -= now - btime; - if (mtime < 0) - { - if (mhand > 25) /* 第一分鐘過後,要在 12 分鐘內下 25 手 */ - { - mtime = 12 * 60; - mhand = 25; - } - else - { - mv.x = mv.y = -8; - if (send(fd, &mv, sizeof(Horder_t), 0) != sizeof(Horder_t)) - break; - move(8, 46); - outs("未在時間內完成 25 手,裁定敗"); - break; - } - } - } +static void +go_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, 1, + 1, 1, 1, 2 }; + + board_p board = (board_p) info->board; + go_tag_t* tag = (go_tag_t*) info->tag; + + 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 J K L M N O P Q R S T"); + } else if (line >= 2 && line <= 20) { + const int board_line = line - 2; + const char* const* const pics = + board_line == 0 ? &BoardPic[0] : + board_line == BRDSIZ - 1 ? &BoardPic[6] : &BoardPic[3]; + int i; + + prints("%2d" ANSI_COLOR(30;43), 21 - line); + + for (i = 0; i < BRDSIZ; ++i) + if (board[board_line][i] == BBLANK) + outs(pics[BoardPicIndex[i]]); else - { - htime -= now - btime; - if (htime < 0) - { - if (hhand > 25) /* 第一分鐘過後,要在 12 分鐘內下 25 手 */ - { - htime = 12 * 60; - hhand = 25; - } - else - htime = 0; - } - } - move(5, 46); - clrtoeol(); - /* move() only move pointer in screen.c, doesn't move - * curses correctly */ - //do_move(5, 35); - { - char buf[128]; - int n; - //move(5, 46); - n = sprintf(buf, ANSI_MOVETO(6,47) "%s 方時間:%02d:%02d ", - bw_chess[gd.me - 1], (int)mtime / 60, (int)mtime % 60); - if (mhand <= 25) - n += sprintf(buf + n, "%2d 手", 25 - mhand); - output(buf, n); - //move(6, 46); - n = sprintf(buf, ANSI_MOVETO(7,47) "%s 方時間:%02d:%02d ", - bw_chess[gd.he - 1], (int)htime / 60, (int)htime % 60); - if (hhand <= 25) - n += sprintf(buf + n, "%2d 手", 25 - hhand); - output(buf, n); - } + outs(bw_chess[(int) board[board_line][i]]); + + outs(ANSI_RESET); + } else if (line >= 21 && line < b_lines) + prints("%40s", ""); + else if (line == b_lines) { + if (info->mode == CHESS_MODE_VERSUS || + info->mode == CHESS_MODE_PERSONAL) { + if (tag->game_end) + outs(ANSI_COLOR(31;47) "(w)" ANSI_COLOR(30) "計地" ANSI_RESET); + else if (info->history.used == 0 && (info->myturn == BWHITE + || info->mode == CHESS_MODE_PERSONAL)) + outs(ANSI_COLOR(31;47) "(x)" ANSI_COLOR(30) "授子" ANSI_RESET); } - btime = now; + } - iBGOTO(mv.x, mv.y); + if (line == 1 || line == 2) { + int color = line - 1; /* BWHITE or BBLACK */ - /* - if (ch == -1 && is_view) - cshm_update(mv.x, mv.y); - */ + if (tag->game_end && tag->clean_end == 3) + prints(" " ANSI_COLOR(30;43) "%s" ANSI_RESET + " 方子空:%3.1f", bw_chess[color], + tag->eaten[color] + + (color == BWHITE ? tag->feed_back : 0.0)); + else + prints(" " ANSI_COLOR(30;43) "%s" ANSI_RESET + " 方提子數:%3d", bw_chess[color], tag->eaten[color]); + } else + ChessDrawExtraInfo(info, line, 3); +} - ch = igetch(); +static void +go_movecur(int r, int c) +{ + move(r + 2, c * 2 + 3); +} - if (ch == 'v') - { - screen_backup_t old_screen; +static void +go_prepare_play(ChessInfo* info) +{ + if (((go_tag_t*) info->tag)->game_end) { + strlcpy(info->warnmsg, "請清除死子,以便計算勝負", + sizeof(info->warnmsg)); + if (info->last_movestr[0] != ' ') + strcpy(info->last_movestr, " "); + } - screen_backup(&old_screen); - add_io(0, 0); - if (ch == 'v') - { - //extern char watermode; + if (info->history.used == 1) + ChessDrawLine(info, b_lines); /* clear the 'x' instruction */ +} - //watermode = 2; - my_write(0, "丟水球過去:", my->mateid, WATERBALL_GENERAL, &SHM->uinfo[my->destuip]); - //watermode = 0; - } - /* ??? scw: when will these code be executed? - else - { - show_last_call_in(); - my_write(currutmp->msgs[0].last_pid, "水球丟回去:"); - } - */ - screen_restore(&old_screen); - add_io(fd, 0); - scr_need_redraw = 1; - continue; - } else if (ch == 'x') { - if (v == pool && gd.me == BWHITE && gd.win != 0) - { - char buf[4]; - - add_io(0, 0); - getdata(21, 46, "要讓多少子呢(1 - 9)? ", buf, 4, DOECHO); - add_io(fd, 0); - - if (GO_sethand(&gd, atoi(buf))) - { - mv.x = -9; - mv.y = atoi(buf); - if (send(fd, &mv, sizeof(Horder_t), 0) != sizeof(Horder_t)) - break; - mv.x = mv.y = 9; - my->turn = 1; - ch = -1; - } - continue; - } - } - else if (ch == 'y') - { - if (v == pool && gd.me == BWHITE) - { - timeflag = 1; - mv.x = mv.y = -10; - if (send(fd, &mv, sizeof(Horder_t), 0) != sizeof(Horder_t)) - break; - mv.x = mv.y = 9; - ch = -1; +static int +go_process_key(ChessInfo* info, int key, ChessGameResult* result) +{ + go_tag_t* tag = (go_tag_t*) info->tag; + if (tag->game_end) { + if (key == 'w') { + if (!(tag->clean_end & 1)) { + go_step_t step = { CHESS_STEP_SPECIAL, CLEANDONE }; + ChessStepSend(info, &step); + tag->clean_end |= 1; } - } - else if (ch == 'w') - { - if (endflag) - { - Horder_t tmp; - if (passflag && my->turn) - { - tmp.x = tmp.y = -3; - if (send(fd, &tmp, sizeof(Horder_t), 0) != sizeof(Horder_t)) - break; + if (tag->clean_end & 2 || info->mode == CHESS_MODE_PERSONAL) { + /* both sides agree */ + int winner = go_result(info); - if (GO_result(&gd)) - outs("恭禧,您獲得勝利.... "); - else - outs("輸了,再接再勵呦.... "); + tag->clean_end = 3; - if (gd.me == BWHITE) - ch = -1; - - break; - } + if (winner == BBLANK) + *result = CHESS_RESULT_TIE; else - { - Horder_t tmp; + *result = (winner == info->myturn ? + CHESS_RESULT_WIN : CHESS_RESULT_LOST); - passflag = 1; - tmp.x = tmp.y = -6; - if (send(fd, &tmp, sizeof(Horder_t), 0) != sizeof(Horder_t)) - break; - my->turn = 0; + ChessRedraw(info); + return 1; + } + } else if (key == 'u') { + char buf[4]; + getdata(b_lines, 0, "是否真的要重新點死子? (y/N)", + buf, sizeof(buf), DOECHO); + ChessDrawLine(info, b_lines); - if (gd.me == BWHITE) - ch = -1; + if (buf[0] == 'y' || buf[0] == 'Y') { + go_step_t step = { CHESS_STEP_SPECIAL, UNCLEAN }; + ChessStepSend(info, &step); - continue; - } + memcpy(info->board, tag->backup_board, sizeof(tag->backup_board)); + tag->eaten[0] = tag->backup_eaten[0]; + tag->eaten[1] = tag->backup_eaten[1]; } - else - { - if (my->turn) - { - if (passflag) - { - endflag = 1; - passflag = 0; - mv.x = mv.y = -2; - if (send(fd, &mv, sizeof(Horder_t), 0) != sizeof(Horder_t)) - break; - mv.x = mv.y = 9; - memcpy(l, go, sizeof(gd.l)); /* 備份 */ - - if (gd.me == BWHITE) - ch = -1; - continue; - } - else - { - passflag = 1; - mv.x = mv.y = -1; - if (send(fd, &mv, sizeof(Horder_t), 0) != sizeof(Horder_t)) - break; - GO_add(&gd, &mv); - totalgo++; - mv.x = mv.y = 9; - my->turn = 0; - - if (gd.me == BWHITE) - ch = -1; - continue; - } - } - } - } - else if (ch == Ctrl('C')/* && v == pool */) - { - mv.x = mv.y = -5; - if (send(fd, &mv, sizeof(Horder_t), 0) != sizeof(Horder_t)) - break; - break; - } - else if (ch == 'u') - { - if (endflag) - { - memcpy(go, l, sizeof(gd.go)); - - for(i = 0;i < 19;i++) - for(j = 0;j < 19;j++) - { - BGOTO(i, j); - if (go[i][j]) - { - outs(bw_chess[go[i][j] - 1]); - } - else - GO_blank(i, j); - } - redoscr(); - mv.x = mv.y = -7; - if (send(fd, &mv, sizeof(Horder_t), 0) != sizeof(Horder_t)) - break; - mv = *(v - 1); - - if (gd.me == BWHITE) - ch = -1; - } - } - else if (ch == 'z') - { - mv.x = mv.y = -4; - if (send(fd, &mv, sizeof(Horder_t), 0) != sizeof(Horder_t)) - break; - move(8, 46); - outs("您認輸了.... "); - break; } + } else if (key == 'x' && info->history.used == 0 && + ((info->mode == CHESS_MODE_VERSUS && info->myturn == BWHITE) || + info->mode == CHESS_MODE_PERSONAL)) { + char buf[4]; + int n; + + getdata(22, 43, "要授多少子呢(2 - 9)? ", buf, sizeof(buf), DOECHO); + n = atoi(buf); + + if (n >= 2 && n <= 9) { + go_step_t step = { CHESS_STEP_NORMAL, SETHAND, {n, 0} }; + + ChessStepSend(info, &step); + ChessHistoryAppend(info, &step); + + go_sethand(info->board, n); + ((go_tag_t*)info->tag)->feed_back = 0.0; + + snprintf(info->last_movestr, sizeof(info->last_movestr), + ANSI_COLOR(1) "授 %d 子" ANSI_RESET, n); + ChessRedraw(info); + return 1; + } else + ChessDrawLine(info, 22); + } + return 0; +} - if (ch == I_OTHERDATA) - { - ch = recv(fd, &mv, sizeof(Horder_t), 0); - scr_need_redraw = 1; - - if (ch <= 0) - { - move(8, 46); - outs("對方斷線.... "); - break; - } +static int +go_select(ChessInfo* info, rc_t location, ChessGameResult* result) +{ + board_p board = (board_p) info->board; - if (ch != sizeof(Horder_t)) - { - continue; - } + if (GET_TAG(info)->game_end) { + go_step_t step = { CHESS_STEP_SPECIAL, CLEAN, location }; + if (board[location.r][location.c] == BBLANK) + return 0; - if (mv.x == -9 && mv.y > 0) - { - GO_sethand(&gd, mv.y); - mv.x = mv.y = 9; - my->turn = 0; - continue; - } + GET_TAG(info)->eaten[!board[location.r][location.c]] += + go_cleandead(board, location.r, location.c); - if (mv.x == -10 && mv.y == -10) - { - timeflag = 1; - mv.x = mv.y = 9; - continue; - } + ChessStepSend(info, &step); + ChessRedraw(info); + return 0; /* don't have to return from ChessPlayFuncMy() */ + } else { + go_step_t step = { CHESS_STEP_NORMAL, info->turn, location }; - if (mv.x == -5 && mv.y == -5){ - move(8, 46); - outs("對方斷線.... "); - break; - } + if (board[location.r][location.c] != BBLANK) + return 0; - if (mv.x == -4 && mv.y == -4) - { - move(8, 46); - outs("對方認輸.... "); - break; - } + if (go_check(info, &step)) { + board[location.r][location.c] = info->turn; + ChessStepSend(info, &step); + ChessHistoryAppend(info, &step); - if (mv.x == -8 && mv.y == -8) - { - move(8, 46); - outs("對方未在時間內完成 25 手,裁定勝"); - break; - } + go_getstep(&step, info->last_movestr); + if (go_examboard(board, !info->myturn, info)) + ChessRedraw(info); + else + ChessDrawLine(info, BOARD_LINE_ON_SCREEN(location.r)); + return 1; + } else + return 0; + } +} - if (mv.x == -3 && mv.y == -3) - { - if (GO_result(&gd)) - outs("恭禧,您獲得勝利.... "); +static void +go_prepare_step(ChessInfo* info, const go_step_t* step) +{ + go_tag_t* tag = GET_TAG(info); + if (tag->game_end) { + /* some actions need tag so are done here */ + if (step->color == CLEAN) { + board_p board = (board_p) info->board; + tag->eaten[!board[step->loc.r][step->loc.c]] += + go_cleandead(board, step->loc.r, step->loc.c); + } else if (step->color == UNCLEAN) { + memcpy(info->board, tag->backup_board, sizeof(tag->backup_board)); + tag->eaten[0] = tag->backup_eaten[0]; + tag->eaten[1] = tag->backup_eaten[1]; + } else if (step->color == CLEANDONE) { + if (tag->clean_end & 1) { + /* both sides agree */ + int winner = go_result(info); + + tag->clean_end = 3; + + if (winner == BBLANK) + ((go_step_t*)step)->loc.r = (int) CHESS_RESULT_TIE; else - outs("輸了,再接再勵呦.... "); - break; - - if (gd.me == BWHITE) - ch = -1; - } + ((go_step_t*)step)->loc.r = (int) + (winner == info->myturn ? + CHESS_RESULT_WIN : CHESS_RESULT_LOST); - if (mv.x == -2 && mv.y == -2) - { - endflag = 1; - passflag = 0; - mv.x = mv.y = 9; - my->turn = 1; - memcpy(l, go, sizeof(gd.l)); /* 備份 */ - - if (gd.me == BWHITE) - ch = -1; - continue; - } - - if (mv.x == -7 && mv.y == -7) - { - memcpy(go, l, sizeof(gd.go)); - - for(i = 0;i < 19;i++) - for(j = 0;j < 19;j++) - { - BGOTO(i, j); - if (go[i][j]) - { - outs(bw_chess[go[i][j] - 1]); - redoln(); - } - else - GO_blank(i, j); - } - mv = *(v - 1); - - if (gd.me == BWHITE) - ch = -1; - - continue; + ChessRedraw(info); + } else { + ((go_step_t*)step)->color = BBLANK; /* tricks apply */ + tag->clean_end |= 2; } + } + } else if (step->type == CHESS_STEP_NORMAL) { + if (step->color != SETHAND) { + go_getstep(step, info->last_movestr); + + memcpy(tag->backup_board, info->board, sizeof(board_t)); + tag->backup_board[step->loc.r][step->loc.c] = step->color; + + /* if any chess was eaten, wholely redraw is needed */ + tag->need_redraw = + go_examboard(tag->backup_board, !step->color, info); + } else { + snprintf(info->last_movestr, sizeof(info->last_movestr), + ANSI_COLOR(1) "授 %d 子" ANSI_RESET, step->loc.r); + tag->need_redraw = 1; + ((go_tag_t*)info->tag)->feed_back = 0.0; + } + } +} - if (mv.x == -6 && mv.y == -6) - { - passflag = 1; - mv = *(v - 1); - my->turn = 1; +static ChessGameResult +go_apply_step(board_t board, const go_step_t* step) +{ + switch (step->color) { + case BWHITE: + case BBLACK: + board[step->loc.r][step->loc.c] = step->color; + go_examboard(board, !step->color, NULL); + break; - if (gd.me == BWHITE) - ch = -1; + case SETHAND: + go_sethand(board, step->loc.r); + break; - continue; - } + case CLEAN: + go_cleandead(board, step->loc.r, step->loc.c); + break; - if (mv.x == -1 && mv.y == -1) - { - GO_add(&gd, &mv); - totalgo++; - mv.x = mv.y = 9; + case CLEANDONE: + /* should be agreed by both sides, [see go_prepare_step()] */ + return (ChessGameResult) step->loc.r; + } + return CHESS_RESULT_CONTINUE; +} - passflag = 1; - my->turn = 1; +static void +go_drawstep(ChessInfo* info, const go_step_t* step) +{ + go_tag_t* tag = GET_TAG(info); + if (tag->game_end || tag->need_redraw) + ChessRedraw(info); + else + ChessDrawLine(info, BOARD_LINE_ON_SCREEN(step->loc.r)); +} - if (gd.me == BWHITE) - ch = -1; +static ChessGameResult +go_post_game(ChessInfo* info) +{ + extern ChessGameResult ChessPlayFuncMy(ChessInfo* info); - continue; - } + go_tag_t *tag = (go_tag_t*) info->tag; + ChessTimeLimit *orig_limit = info->timelimit; + ChessGameResult result; - if (endflag) - { - int y, x; - - getyx(&y, &x); - - go[(int)mv.x][(int)mv.y] = BBLANK; - GO_blank(mv.x, mv.y); - /* - gd.hk++; - */ - mv.x = (x - 4) / 2; - mv.y = 20 - y; - iBGOTO(mv.x, mv.y); - - if (gd.me == BWHITE) - ch = -1; - continue; - } + info->timelimit = NULL; + info->turn = info->myturn; + strcpy(info->warnmsg, "請點除死子"); + ChessDrawLine(info, CHESS_DRAWING_WARN_ROW); - if (!my->turn) - { - GO_add(&gd, &mv); + memcpy(tag->backup_board, info->board, sizeof(tag->backup_board)); + tag->game_end = 1; + tag->clean_end = 0; + tag->backup_eaten[0] = tag->eaten[0]; + tag->backup_eaten[1] = tag->eaten[1]; - totalgo++; - if (--hhand <= 0) - { - htime = 12 * 60; - hhand = 25; - } - go[(int)mv.x][(int)mv.y] = gd.he; - BGOTO(mv.x, mv.y); - outs(bw_chess[gd.he - 1]); - - GO_examboard(&gd, gd.me); - my->turn = 1; - htime -= now - btime; - btime = now; - passflag = 0; - - if (gd.me == BWHITE) - ch = -1; - } - continue; - } + ChessDrawLine(info, b_lines); /* 'w' instruction */ - if (endflag == 1 && (ch == ' ' || ch == '\r' || ch == '\n')) { - if (go[(int)mv.x][(int)mv.y] == gd.me) - GO_cleandead(&gd, fd, mv.x, mv.y, gd.me); + while ((result = ChessPlayFuncMy(info)) == CHESS_RESULT_CONTINUE); - if (gd.me == BWHITE) - ch = -1; - continue; - } + ChessRedraw(info); - if (my->turn) - { - if (go_key(&gd, fd, ch, &mv)) - my->turn = 0; - else - continue; + info->timelimit = orig_limit; - if (!my->turn) - { - GO_add(&gd, &mv); - - totalgo++; - mtime -= now - btime; - btime = now; - if (--mhand <= 0) - { - mtime = 12 * 60; - mhand = 25; - } - BGOTO(mv.x, mv.y); - outs(bw_chess[gd.me - 1]); - go[(int)mv.x][(int)mv.y] = gd.me; - GO_examboard(&gd, gd.he); - if (send(fd, &mv, sizeof(Horder_t), 0) != sizeof(Horder_t)) - break; - passflag = 0; - - if (gd.me == BWHITE) - ch = -1; - scr_need_redraw = 1; - } - } - } - - add_io(0, 0); - close(fd); - redoscr(); + return result; +} - igetch(); +static void +go_gameend(ChessInfo* info, ChessGameResult result) +{ + /* TODO: implement */ +} - /* - if (gd.me == BWHITE && is_view) - cshm_free(); - */ +static void +go_genlog(ChessInfo* info, FILE* fp, ChessGameResult result) +{ + const static char ColName[] = "ABCDEFGHJKLMNOPQRST"; + const int nStep = info->history.used; + int i; + int sethand = 0; - if (endflag) - { - for(i = 0;i < 19;i++) - for(j = 0;j < 19;j++) - { - BGOTO(i, j); - if (l[i][j]) - { - outs(bw_chess[l[i][j] - 1]); - } - else - GO_blank(i, j); - } + if (nStep > 0) { + const go_step_t* const step = + (const go_step_t*) ChessHistoryRetrieve(info, 0); + if (step->color == SETHAND) + sethand = step->loc.r; } - redoscr(); - if (v > pool + 10) - { - char ans[3]; + for (i = 1; i <= 22; i++) + fprintf(fp, "%.*s\n", big_picture[i].len, big_picture[i].data); - getdata(b_lines - 1, 0, "要存成棋譜嗎(Y/N)?[Y] ", ans, 3, LCECHO); + if (sethand) { + fprintf(fp, "[ 1] 授 %d 子\n ", sethand); + i = 1; + } else + i = 0; - if (*ans != 'n') - GO_log(&gd, my->mateid); + for (; i < nStep; ++i) { + const go_step_t* const step = + (const go_step_t*) ChessHistoryRetrieve(info, i); + if (step->type == CHESS_STEP_NORMAL) + fprintf(fp, "[%3d]%s => %c%-4d", i + 1, bw_chess[step->color], + ColName[step->loc.c], 19 - step->loc.r); + else if (step->type == CHESS_STEP_PASS) + fprintf(fp, "[%3d]%s => 虛手 ", i + 1, bw_chess[(i + 1) % 2]); + else + break; + if (i % 5 == 4) + fputc('\n', fp); + } + + fprintf(fp, + "\n\n《以下為 sgf 格式棋譜》\n<golog>\n(;GM[1]" + "GN[%s-%s(W) Ptt]\n" + "SZ[19]HA[%d]PB[%s]PW[%s]\n" + "PC[FPG BBS/Ptt BBS: ptt.cc]\n", + info->user1.userid, info->user2.userid, + sethand, + info->user1.userid, info->user2.userid); + + if (sethand) { + const int lower = sethand * (sethand - 1) / 2; + const int upper = lower + sethand; + int j; + fputs("AB", fp); + for (j = lower; j < upper; ++j) + fprintf(fp, "[%c%c]", + SetHandPoints[j].c + 'a', + SetHandPoints[j].r + 'a'); + fputc('\n', fp); + } + + for (i = (sethand ? 1 : 0); i < nStep; ++i) { + const go_step_t* const step = + (const go_step_t*) ChessHistoryRetrieve(info, i); + if (step->type == CHESS_STEP_NORMAL) + fprintf(fp, ";%c[%c%c]", + step->color == BWHITE ? 'W' : 'B', + step->loc.c + 'a', + step->loc.r + 'a'); + else if (step->type == CHESS_STEP_PASS) + fprintf(fp, ";%c[] ", i % 2 ? 'W' : 'B'); + else + break; + if (i % 10 == 9) + fputc('\n', fp); } - - return 0; + fprintf(fp, ";)\n<golog>\n\n"); } -int -GoBot(void) +void +gochess(int s, ChessGameMode mode) { - Horder_t mv; - int i, ch, totalgo; - unsigned char tmp_go[2][BRDSIZ][BRDSIZ]; - unsigned char tmp_l[2][BRDSIZ][BRDSIZ]; - unsigned char tmp_ml[2][BRDSIZ][BRDSIZ]; - int tmp_lib[2], tmp_mik[2], tmp_mjk[2], tmp_hik[2], tmp_hjk[2]; - int scr_need_redraw = 1; - - struct GOData gd; - unsigned char (*go)[BRDSIZ]=gd.go; - unsigned char (*l)[BRDSIZ]=gd.l; - unsigned char (*ml)[BRDSIZ]=gd.ml; - Horder_t *pool=gd.pool; - - GO_init(&gd); - - memset(&tmp_go, 0, sizeof(tmp_go)); - memset(&tmp_l, 0, sizeof(tmp_l)); - memset(&tmp_ml, 0, sizeof(tmp_ml)); - for (i = 0;i < 2;i++) - { - tmp_lib[i] = 0; - tmp_mik[i] = tmp_mjk[i] = tmp_hik[i] = tmp_hjk[i] = -1; - } - - - gd.me = BBLACK; - gd.he = BWHITE; - gd.hand = 0; - totalgo = 0; - gd.hik = gd.hjk = -1; - gd.mik = gd.mjk = -1; - - setutmpmode(GO); + ChessInfo* info = NewChessInfo(&go_actions, &go_constants, s, mode); + board_t board; + go_tag_t tag; - clear(); + go_init_board(board); + go_init_tag(&tag); - prints(ANSI_COLOR(1;46) " 圍棋打譜 " ANSI_COLOR(45) "%66s" ANSI_RESET, " "); - GO_cleantable(); + info->board = board; + info->tag = &tag; - /* film_out(FILM_GO, 1); */ + info->cursor.r = 9; + info->cursor.c = 9; - mv.x = mv.y = 9; - - for(;;) - { - if(scr_need_redraw){ - move(8, 46); - clrtoeol(); - prints("輪到 %s 方下了....", bw_chess[gd.me - 1]); - - move(10, 46); - clrtoeol(); - if (totalgo > 0) - { - if (pool[totalgo - 1].x == -1 || pool[totalgo - 1].y == -1) - prints("%s #%-3d PASS 上一手 ", bw_chess[(totalgo - 1) & 1], totalgo); - else - prints("%s #%-3d %.1s%-2d 上一手 ", bw_chess[(totalgo - 1) & 1], totalgo, locE + pool[totalgo - 1].x, pool[totalgo - 1].y + 1); - } - - for (i = totalgo - 1;i > 0 && totalgo - i <= 10;i--) - { - move(10 + totalgo - i, 46); - clrtoeol(); - if (pool[i - 1].x == -1 || pool[i - 1].y == -1) - prints("%s #%-3d PASS", bw_chess[(i - 1) & 1], i); - else - prints("%s #%-3d %.1s%-2d ", bw_chess[(i - 1) & 1], i, locE + pool[i - 1].x, pool[i - 1].y + 1); - } - - outmsg(ANSI_COLOR(1;33;42)" 打譜 " - ANSI_COLOR(;31;47)" (←↑↓→)" - ANSI_COLOR(30)"移動 " - ANSI_COLOR(31)"(空白鍵/ENTER)" - ANSI_COLOR(30)"下子 " - ANSI_COLOR(31)"(u)" - ANSI_COLOR(30)"回上一步 " - ANSI_COLOR(31) "(z)" - ANSI_COLOR(30) "離開 " - ANSI_RESET); - redoscr(); - scr_need_redraw = 0; - } - - iBGOTO(mv.x, mv.y); + if (mode == CHESS_MODE_WATCH) + setutmpmode(CHESSWATCHING); + else + setutmpmode(GO); + currutmp->sig = SIG_GO; - ch = igetch(); + ChessPlay(info); - if (ch == 'z') - break; - else if (ch == 'u') - { - int j; - if (!totalgo) - continue; - memset(go, 0, sizeof(gd.go)); - memset( l, 0, sizeof(gd.go)); - memset(ml, 0, sizeof(gd.go)); - memset(&tmp_go, 0, sizeof(tmp_go)); - memset(&tmp_l, 0, sizeof(tmp_l)); - memset(&tmp_ml, 0, sizeof(tmp_ml)); - for (i = 0;i < 2;i++) - { - tmp_lib[i] = 0; - tmp_mik[i] = tmp_mjk[i] = tmp_hik[i] = tmp_hjk[i] = -1; - } - gd.me = BBLACK; - gd.he = BWHITE; - gd.hik = gd.hjk = -1; - gd.mik = gd.mjk = -1; - - /* film_out(FILM_GO, 1); */ - totalgo--; - for (i = 0;i < totalgo;i++) - { - go[(int)pool[i].x][(int)pool[i].y] = gd.me; - GO_examboard(&gd, gd.he); - memcpy(&tmp_go[gd.me - 1], go, sizeof(gd.l)); - memcpy(&tmp_l[gd.me - 1], l, sizeof(gd.l)); - memcpy(&tmp_ml[gd.me - 1], ml, sizeof(gd.ml)); - tmp_lib[gd.me - 1] = gd.lib; - tmp_mik[gd.me - 1] = gd.mik; - tmp_mjk[gd.me - 1] = gd.mjk; - tmp_hik[gd.me - 1] = gd.hik; - tmp_hjk[gd.me - 1] = gd.hjk; - gd.me = gd.he; - gd.he = 3 - gd.me; - memcpy(go, &tmp_go[gd.me - 1], sizeof(gd.l)); - memcpy(l, &tmp_l[gd.me - 1], sizeof(gd.l)); - memcpy(ml, &tmp_ml[gd.me - 1], sizeof(gd.ml)); - gd.lib = tmp_lib[gd.me - 1]; - gd.mik = tmp_mik[gd.me - 1]; - gd.mjk = tmp_mjk[gd.me - 1]; - gd.hik = tmp_hik[gd.me - 1]; - gd.hjk = tmp_hjk[gd.me - 1]; - go[(int)pool[i].x][(int)pool[i].y] = gd.he; - GO_examboard(&gd, gd.me); - } - GO_cleantable(); - for (i = 0; i < BRDSIZ; ++i) - for(j = 0; j < BRDSIZ; ++j) - if (go[i][j]) { - BGOTO(i, j); - outs(bw_chess[go[i][j] - 1]); - } - scr_need_redraw = 1; - mv = *(--v); - } - else - { - if (go_key(&gd, 0, ch, &mv)) - { - GO_add(&gd, &mv); - totalgo++; - BGOTO(mv.x, mv.y); - outs(bw_chess[gd.me - 1]); - go[(int)mv.x][(int)mv.y] = gd.me; - GO_examboard(&gd, gd.he); - memcpy(&tmp_go[gd.me - 1], go, sizeof(gd.l)); - memcpy(&tmp_l[gd.me - 1], l, sizeof(gd.l)); - memcpy(&tmp_ml[gd.me - 1], ml, sizeof(gd.ml)); - tmp_lib[gd.me - 1] = gd.lib; - tmp_mik[gd.me - 1] = gd.mik; - tmp_mjk[gd.me - 1] = gd.mjk; - tmp_hik[gd.me - 1] = gd.hik; - tmp_hjk[gd.me - 1] = gd.hjk; - gd.me = gd.he; - gd.he = 3 - gd.me; - memcpy(go, &tmp_go[gd.me - 1], sizeof(gd.l)); - memcpy(l, &tmp_l[gd.me - 1], sizeof(gd.l)); - memcpy(ml, &tmp_ml[gd.me - 1], sizeof(gd.ml)); - gd.lib = tmp_lib[gd.me - 1]; - gd.mik = tmp_mik[gd.me - 1]; - gd.mjk = tmp_mjk[gd.me - 1]; - gd.hik = tmp_hik[gd.me - 1]; - gd.hjk = tmp_hjk[gd.me - 1]; - go[(int)mv.x][(int)mv.y] = gd.he; - GO_examboard(&gd, gd.me); - scr_need_redraw = 1; - } - } - } + DeleteChessInfo(info); +} - if (v > pool) - { - char ans[3]; +int +gochess_main(void) +{ + return ChessStartGame('g', SIG_GO, "圍棋"); +} - getdata(b_lines - 1, 0, "要存成棋譜嗎(Y/N)?[Y] ", ans, 3, LCECHO); +int +gochess_personal(void) +{ + gochess(0, CHESS_MODE_PERSONAL); + return 0; +} - if (*ans != 'n') - GO_log(&gd, NULL); - } +int +gochess_watch(void) +{ + return ChessWatchGame(&gochess, GO, "圍棋"); +} - return 0; +ChessInfo* +gochess_replay(FILE* fp) +{ + return NULL; } diff --git a/mbbsd/gomo.c b/mbbsd/gomo.c index 3e242517..d2196bab 100644 --- a/mbbsd/gomo.c +++ b/mbbsd/gomo.c @@ -21,11 +21,6 @@ typedef struct { 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_user_userec(const userec_t* urec, ChessUser* user); static void gomo_init_board(board_t board); @@ -40,26 +35,29 @@ 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 = { +const static ChessActions gomo_actions = { &gomo_init_user, &gomo_init_user_userec, (void (*)(void*)) &gomo_init_board, &gomo_drawline, &gomo_movecur, &gomo_prepare_play, + NULL, &gomo_select, (void (*)(ChessInfo*, const void*)) &gomo_prepare_step, (ChessGameResult (*)(void*, const void*)) &gomo_apply_step, (void (*)(ChessInfo*, const void*)) &gomo_drawstep, + NULL, /* post_game */ &gomo_gameend, &gomo_genlog }; -ChessConstants gomo_constants = { +const static ChessConstants gomo_constants = { sizeof(gomo_step_t), MAX_TIME, BRDSIZ, BRDSIZ, + 0, "五子棋", "photo_fivechess", #ifdef GLOBAL_FIVECHESS_LOG @@ -274,7 +272,7 @@ gomo_init_user_userec(const userec_t* urec, ChessUser* user) static void gomo_init_board(board_t board) { - memset(board, 0xff, sizeof(board_t)); + memset(board, BBLANK, sizeof(board_t)); } static void @@ -290,8 +288,6 @@ gomo_drawline(const ChessInfo* info, int line) 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, @@ -303,22 +299,22 @@ gomo_drawline(const ChessInfo* info, int line) const int board_line = line - 2; const char* const* const pics = board_line == 0 ? &BoardPic[0] : - board_line == 14 ? &BoardPic[6] : &BoardPic[3]; + board_line == BRDSIZ - 1 ? &BoardPic[6] : &BoardPic[3]; int i; prints("%3d" ANSI_COLOR(30;43), 17 - line); - for (i = 0; i < 15; ++i) + for (i = 0; i < BRDSIZ; ++i) if (board[board_line][i] == -1) outs(pics[BoardPicIndex[i]]); else outs(bw_chess[(int) board[board_line][i]]); outs(ANSI_RESET); - } else if (line >= 17 && line <= 23) + } else if (line >= 17 && line < b_lines) prints("%33s", ""); - ChessDrawExtraInfo(info, line); + ChessDrawExtraInfo(info, line, 8); } static void diff --git a/mbbsd/menu.c b/mbbsd/menu.c index 3d5bd4ac..98ce0f4e 100644 --- a/mbbsd/menu.c +++ b/mbbsd/menu.c @@ -599,13 +599,15 @@ static const commands_t playlist[] = { }; static const commands_t chesslist[] = { - {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 "】"}, + {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 "】"}, + {gochess_main, PERM_LOGINOK, "77GoChessFight 【" ANSI_COLOR(1;33) " 圍棋邀局 " ANSI_RESET "】"}, + {gochess_personal, PERM_LOGINOK, "88GoChessSelf 【" ANSI_COLOR(1;34) " 圍棋打譜 " ANSI_RESET "】"}, + {gochess_watch, PERM_LOGINOK, "99GoChessWatch 【" ANSI_COLOR(1;35) " 圍棋觀棋 " ANSI_RESET "】"}, {NULL, 0, NULL} }; diff --git a/mbbsd/talk.c b/mbbsd/talk.c index 12d526bf..56f1d4bd 100644 --- a/mbbsd/talk.c +++ b/mbbsd/talk.c @@ -1487,7 +1487,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 || ch == M_FIVE || ch == CHESSWATCHING) { + if (ch == CHC || ch == M_FIVE || ch == GO || ch == CHESSWATCHING) { sock = make_connection_to_somebody(uin, 20); if (sock < 0) vmsg("無法建立連線"); @@ -1512,6 +1512,10 @@ my_talk(userinfo_t * uin, int fri_stat, char defact) case SIG_GOMO: gomoku(msgsock, CHESS_MODE_WATCH); break; + + case SIG_GO: + gochess(msgsock, CHESS_MODE_WATCH); + break; } } } @@ -1613,7 +1617,7 @@ my_talk(userinfo_t * uin, int fri_stat, char defact) close(sock); currutmp->sockactive = NA; - if (uin->sig == SIG_CHC || uin->sig == SIG_GOMO) + if (uin->sig == SIG_CHC || uin->sig == SIG_GOMO || uin->sig == SIG_GO) ChessEstablishRequest(msgsock); add_io(msgsock, 0); @@ -1648,7 +1652,7 @@ my_talk(userinfo_t * uin, int fri_stat, char defact) chc(msgsock, CHESS_MODE_VERSUS); break; case SIG_GO: - gochess(msgsock); + gochess(msgsock, CHESS_MODE_VERSUS); break; case SIG_TALK: default: @@ -3066,7 +3070,7 @@ talkreply(void) currutmp->destuid = uip->uid; currstat = REPLY; /* 避免出現動畫 */ - is_chess = (sig == SIG_CHC || sig == SIG_GOMO); + is_chess = (sig == SIG_CHC || sig == SIG_GOMO || sig == SIG_GO); a = reply_connection_request(uip); if (a < 0) { @@ -3152,7 +3156,7 @@ talkreply(void) chc(a, CHESS_MODE_VERSUS); break; case SIG_GO: - gochess(a); + gochess(a, CHESS_MODE_VERSUS); break; case SIG_TALK: default: diff --git a/mbbsd/var.c b/mbbsd/var.c index 26078085..c8d8ef98 100644 --- a/mbbsd/var.c +++ b/mbbsd/var.c @@ -408,7 +408,7 @@ char roll = 0; char msg_occupied = 0; /* gomo.c */ -const char * const bw_chess[] = {"○", "●"}; +const char * const bw_chess[] = {"○", "●", "。", "•"}; const unsigned char * const pat_gomoku /* [1954] */ =(unsigned char*) /* 0 */ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" /* 16 */ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x44\x55\xcc\x00\x00\x00\x00" |