summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/chess.h18
-rw-r--r--include/gomo.h3
-rw-r--r--include/proto.h7
-rw-r--r--mbbsd/chc.c7
-rw-r--r--mbbsd/chess.c244
-rw-r--r--mbbsd/go.c2001
-rw-r--r--mbbsd/gomo.c24
-rw-r--r--mbbsd/menu.c16
-rw-r--r--mbbsd/talk.c14
-rw-r--r--mbbsd/var.c2
10 files changed, 931 insertions, 1405 deletions
diff --git a/include/chess.h b/include/chess.h
index 8384e225..f51dfa5b 100644
--- a/include/chess.h
+++ b/include/chess.h
@@ -97,7 +97,7 @@ typedef struct ChessInfo {
const char myturn; /* 我方顏色 */
char turn;
- char ipass, hepass;
+ char pass[2];
char warnmsg[64];
char last_movestr[36];
char *photo;
@@ -128,11 +128,13 @@ typedef struct ChessActions {
void (*drawline) (const ChessInfo* info, int line);
void (*movecur) (int r, int c);
void (*prepare_play)(ChessInfo* info);
+ int (*process_key) (ChessInfo* info, int key, ChessGameResult* result);
int (*select) (ChessInfo* info, rc_t location,
ChessGameResult* result);
void (*prepare_step)(ChessInfo* info, const void* step);
- ChessGameResult (*apply_step) (void* board, const void* step);
+ ChessGameResult (*apply_step)(void* board, const void* step);
void (*drawstep) (ChessInfo* info, const void* step);
+ ChessGameResult (*post_game)(ChessInfo* info);
/* ending */
void (*gameend) (ChessInfo* info, ChessGameResult result);
@@ -144,6 +146,7 @@ typedef struct ChessConstants {
int traditional_timeout;
int board_height;
int board_width;
+ int pass_is_step;
const char *chess_name;
const char *photo_file_name;
const char *log_board;
@@ -154,7 +157,13 @@ typedef struct ChessConstants {
typedef enum {
CHESS_STEP_NORMAL, CHESS_STEP_PASS,
CHESS_STEP_DROP, CHESS_STEP_FAILURE,
- CHESS_STEP_NOP, /* for wake up */
+ CHESS_STEP_SPECIAL, /* chesses' special steps */
+ CHESS_STEP_NOP, /* for wake up */
+
+ CHESS_STEP_TIE, /* tie request */
+ CHESS_STEP_TIE_ACC, /* accept */
+ CHESS_STEP_TIE_REJ, /* reject */
+
CHESS_STEP_UNDO, /* undo request */
CHESS_STEP_UNDO_ACC, /* accept */
CHESS_STEP_UNDO_REJ, /* reject */
@@ -185,7 +194,8 @@ void ChessEstablishRequest(int sock);
void ChessAcceptingRequest(int sock);
void ChessShowRequest(void);
+void ChessRedraw(const ChessInfo* info);
void ChessDrawLine(const ChessInfo* info, int line);
-void ChessDrawExtraInfo(const ChessInfo* info, int line);
+void ChessDrawExtraInfo(const ChessInfo* info, int line, int space);
#endif /* INCLUDE_CHESS_H */
diff --git a/include/gomo.h b/include/gomo.h
index b5e8d014..85b9d276 100644
--- a/include/gomo.h
+++ b/include/gomo.h
@@ -11,9 +11,6 @@
#define BRDSIZ (15) /* 棋盤單邊大小 */
#endif
-#define BGOTO(x, y) move( 16 - (y) , (x) * 2 + 3)
-#define BGOTOCUR(x, y) move(16 - (y), (x) * 2 + 4 - 8)
-
/*
0 0 0 = #@# : len= 3 : NO 00 NO
1 1 0 = #_@# : len= 4 : NO 00 NO
diff --git a/include/proto.h b/include/proto.h
index 38bd407c..b34cfab1 100644
--- a/include/proto.h
+++ b/include/proto.h
@@ -290,8 +290,11 @@ int openticket(int bid);
int ticket(int bid);
/* go */
-int gochess(int fd);
-int GoBot(void);
+void gochess(int s, ChessGameMode mode);
+int gochess_main(void);
+int gochess_personal(void);
+int gochess_watch(void);
+ChessInfo* gochess_replay(FILE* fp);
/* gomo */
void gomoku(int s, ChessGameMode mode);
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) {
diff --git a/mbbsd/go.c b/mbbsd/go.c
index 4f43ec09..afce6b64 100644
--- a/mbbsd/go.c
+++ b/mbbsd/go.c
@@ -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"