summaryrefslogtreecommitdiffstats
path: root/mbbsd/chess.c
diff options
context:
space:
mode:
Diffstat (limited to 'mbbsd/chess.c')
-rw-r--r--mbbsd/chess.c244
1 files changed, 166 insertions, 78 deletions
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) {