summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorscw <scw@63ad8ddf-47c3-0310-b6dd-a9e9d9715204>2007-05-30 23:42:18 +0800
committerscw <scw@63ad8ddf-47c3-0310-b6dd-a9e9d9715204>2007-05-30 23:42:18 +0800
commit715542867ba891acf8c1fd6234f5d6ea2fc285f6 (patch)
tree35727b8664dce3eb0f7421dd0cbb28c6636c672b
parent05df0b0f9445089d03f7a2933875b9c7266eb96e (diff)
downloadpttbbs-715542867ba891acf8c1fd6234f5d6ea2fc285f6.tar
pttbbs-715542867ba891acf8c1fd6234f5d6ea2fc285f6.tar.gz
pttbbs-715542867ba891acf8c1fd6234f5d6ea2fc285f6.tar.bz2
pttbbs-715542867ba891acf8c1fd6234f5d6ea2fc285f6.tar.lz
pttbbs-715542867ba891acf8c1fd6234f5d6ea2fc285f6.tar.xz
pttbbs-715542867ba891acf8c1fd6234f5d6ea2fc285f6.tar.zst
pttbbs-715542867ba891acf8c1fd6234f5d6ea2fc285f6.zip
Reversi (multiplayer othello) added
git-svn-id: http://opensvn.csie.org/pttbbs/trunk/pttbbs@3523 63ad8ddf-47c3-0310-b6dd-a9e9d9715204
-rw-r--r--mbbsd/Makefile2
-rw-r--r--mbbsd/chc.c8
-rw-r--r--mbbsd/chess.c22
-rw-r--r--mbbsd/go.c6
-rw-r--r--mbbsd/gomo.c8
-rw-r--r--mbbsd/pmore.c2
-rw-r--r--mbbsd/reversi.c506
-rw-r--r--mbbsd/talk.c31
8 files changed, 558 insertions, 27 deletions
diff --git a/mbbsd/Makefile b/mbbsd/Makefile
index 70775694..eb26c91f 100644
--- a/mbbsd/Makefile
+++ b/mbbsd/Makefile
@@ -15,7 +15,7 @@ OBJS= admin.o announce.o args.o assess.o bbs.o board.o cache.o cal.o card.o\
more.o name.o osdep.o othello.o read.o record.o register.o\
screen.o stuff.o talk.o term.o topsong.o user.o brc.o vice.o vote.o\
xyz.o voteboard.o syspost.o var.o passwd.o calendar.o go.o file.o \
- pmore.o chess.o
+ pmore.o chess.o reversi.o
.if defined(DIET)
OBJS+= random.o time.o alloc.o
diff --git a/mbbsd/chc.c b/mbbsd/chc.c
index 19fce8fb..a4d3eeeb 100644
--- a/mbbsd/chc.c
+++ b/mbbsd/chc.c
@@ -42,7 +42,7 @@ static void chc_init_user_userec(const userec_t *urec, ChessUser *user);
static void chc_init_board(board_t board);
static void chc_drawline(const ChessInfo* info, int line);
static void chc_movecur(int r, int c);
-static void chc_prepare_play(ChessInfo* info);
+static int chc_prepare_play(ChessInfo* info);
static int chc_select(ChessInfo* info, rc_t scrloc, ChessGameResult* result);
static void chc_prepare_step(ChessInfo* info, const void* step);
static ChessGameResult chc_movechess(board_t board, const drc_t* move);
@@ -105,7 +105,7 @@ static const ChessActions chc_actions = {
&chc_drawline,
&chc_movecur,
&chc_prepare_play,
- NULL,
+ NULL, /* process_key */
&chc_select,
&chc_prepare_step,
(ChessGameResult (*) (void*, const void*)) &chc_movechess,
@@ -692,7 +692,7 @@ chc_init_user_userec(const userec_t *urec, ChessUser *user)
user->orig_rating = user->rating;
}
-static void
+static int
chc_prepare_play(ChessInfo* info)
{
if (chc_ischeck((board_p) info->board, info->turn)) {
@@ -701,6 +701,8 @@ chc_prepare_play(ChessInfo* info)
bell();
} else
info->warnmsg[0] = 0;
+
+ return 0;
}
static int
diff --git a/mbbsd/chess.c b/mbbsd/chess.c
index 9df4f5bc..ca99bfaf 100644
--- a/mbbsd/chess.c
+++ b/mbbsd/chess.c
@@ -56,6 +56,7 @@ static const struct {
{ "gomoku", 6, &gomoku_replay },
{ "chc", 3, &chc_replay },
{ "go", 2, &gochess_replay },
+ { "reversi",7, &reversi_replay },
{ NULL }
};
@@ -386,9 +387,9 @@ ChessReplayUntil(ChessInfo* info, int n)
/* spcial for last one to maintian information correct */
step = ChessHistoryRetrieve(info, info->current_step);
+ info->turn = info->current_step++ & 1;
info->actions->prepare_step(info, step);
info->actions->apply_step(info->board, step);
- info->current_step++;
}
static int
@@ -778,6 +779,7 @@ ChessPlayFuncWatch(ChessInfo* info)
/* at head but redo-ed */
info->actions->init_board(info->board);
info->current_step = 0;
+ info->turn = 1;
ChessReplayUntil(info, info->history.used - 1);
ChessRedraw(info);
}
@@ -786,10 +788,10 @@ ChessPlayFuncWatch(ChessInfo* info)
result == CHESS_STEP_SPECIAL) {
if (info->current_step == info->history.used - 1) {
/* was watching up-to-date board */
+ info->turn = info->current_step++ & 1;
info->actions->prepare_step(info, &info->step_tmp);
info->actions->apply_step(info->board, &info->step_tmp);
info->actions->drawstep(info, &info->step_tmp);
- info->current_step++;
}
} else if (result == CHESS_STEP_PASS)
strcpy(info->last_movestr, "虛手");
@@ -817,10 +819,10 @@ ChessPlayFuncWatch(ChessInfo* info)
else {
const void* step =
ChessHistoryRetrieve(info, info->current_step);
+ info->turn = info->current_step++ & 1;
info->actions->prepare_step(info, step);
info->actions->apply_step(info->board, step);
info->actions->drawstep(info, step);
- info->current_step++;
}
break;
@@ -1070,13 +1072,15 @@ ChessPlay(ChessInfo* info)
for (game_result = CHESS_RESULT_CONTINUE;
game_result == CHESS_RESULT_CONTINUE;
info->turn ^= 1) {
- info->actions->prepare_play(info);
- ChessDrawLine(info, CHESS_DRAWING_TURN_ROW);
- ChessDrawLine(info, CHESS_DRAWING_WARN_ROW);
- game_result = info->play_func[(int) info->turn](info);
+ if (info->actions->prepare_play(info))
+ info->pass[(int) info->turn] = 1;
+ else {
+ 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])
+ if (info->pass[0] && info->pass[1])
game_result = CHESS_RESULT_END;
}
diff --git a/mbbsd/go.c b/mbbsd/go.c
index cd59f39d..ac117b1a 100644
--- a/mbbsd/go.c
+++ b/mbbsd/go.c
@@ -68,7 +68,7 @@ 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_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);
@@ -545,7 +545,7 @@ go_movecur(int r, int c)
move(r + 2, c * 2 + 3);
}
-static void
+static int
go_prepare_play(ChessInfo* info)
{
if (((go_tag_t*) info->tag)->game_end) {
@@ -557,6 +557,8 @@ go_prepare_play(ChessInfo* info)
if (info->history.used == 1)
ChessDrawLine(info, b_lines); /* clear the 'x' instruction */
+
+ return 0;
}
static int
diff --git a/mbbsd/gomo.c b/mbbsd/gomo.c
index 71f0bbfc..e3664176 100644
--- a/mbbsd/gomo.c
+++ b/mbbsd/gomo.c
@@ -26,7 +26,7 @@ static void gomo_init_user_userec(const userec_t* urec, ChessUser* user);
static void gomo_init_board(board_t board);
static void gomo_drawline(const ChessInfo* info, int line);
static void gomo_movecur(int r, int c);
-static void gomo_prepare_play(ChessInfo* info);
+static int gomo_prepare_play(ChessInfo* info);
static int gomo_select(ChessInfo* info, rc_t location,
ChessGameResult* result);
static void gomo_prepare_step(ChessInfo* info, const gomo_step_t* step);
@@ -42,7 +42,7 @@ const static ChessActions gomo_actions = {
&gomo_drawline,
&gomo_movecur,
&gomo_prepare_play,
- NULL,
+ NULL, /* process_key */
&gomo_select,
(void (*)(ChessInfo*, const void*)) &gomo_prepare_step,
(ChessGameResult (*)(void*, const void*)) &gomo_apply_step,
@@ -323,11 +323,13 @@ gomo_movecur(int r, int c)
move(r + 2, c * 2 + 3);
}
-static void
+static int
gomo_prepare_play(ChessInfo* info)
{
if (!gomo_move_warn(*(int*) info->tag, info->warnmsg))
info->warnmsg[0] = 0;
+
+ return 0;
}
static int
diff --git a/mbbsd/pmore.c b/mbbsd/pmore.c
index dd22ed60..d71fd1ee 100644
--- a/mbbsd/pmore.c
+++ b/mbbsd/pmore.c
@@ -1523,7 +1523,7 @@ static const char * const pmore_help[] = {
"(t/[-/]+) 主題式閱\讀:循序/前/後篇",
"(\\/|) 切換顯示原始內容", // this IS already aligned!
"(w/W/l) 切換自動斷行/斷行符號/分隔線顯示方式",
- "(p/o) 播放動畫/切換傳統模式(狀態列與斷行方式)",
+ "(p/z/o) 播放動畫/棋局打譜/切換傳統模式(狀態列與斷行方式)",
"(q/←) (h/H/?/F1) 結束/本說明畫面",
#ifdef DEBUG
"(d) 切換除錯(debug)模式",
diff --git a/mbbsd/reversi.c b/mbbsd/reversi.c
new file mode 100644
index 00000000..c396ef0a
--- /dev/null
+++ b/mbbsd/reversi.c
@@ -0,0 +1,506 @@
+/* $Id$ */
+
+#include "bbs.h"
+
+#define MAX_TIME (300)
+#define BRDSIZ (8) /* 棋盤單邊大小 */
+
+#define NONE_CHESS " "
+#define WHITE_CHESS "●"
+#define BLACK_CHESS "○"
+#define HINT_CHESS "#"
+#define NONE 0
+#define HINT 1
+#define BLACK 2
+#define WHITE 3
+
+#define STARTY 10
+
+#define INVERT(COLOR) (((COLOR))==WHITE?BLACK:WHITE)
+
+#define IS_BLANK(COLOR) ((COLOR) < BLACK) /* NONE or HINT */
+#define IS_CHESS(COLOR) ((COLOR) >= BLACK)
+#define TURN_TO_COLOR(TURN) (WHITE - (TURN))
+#define COLOR_TO_TURN(COLOR) (WHITE - (COLOR))
+
+typedef char color_t;
+typedef color_t board_t[BRDSIZ + 2][BRDSIZ + 2];
+typedef color_t (*board_p)[BRDSIZ + 2];
+/* [0] & [9] are dummy */
+
+typedef struct {
+ ChessStepType type; /* necessary one */
+ color_t color;
+ rc_t loc;
+} reversi_step_t;
+
+typedef struct {
+ int number[2];
+} reversi_tag_t;
+
+/* chess framework action functions */
+static void reversi_init_user(const userinfo_t *uinfo, ChessUser *user);
+static void reversi_init_user_userec(const userec_t *urec, ChessUser *user);
+static void reversi_init_board(board_t board);
+static void reversi_drawline(const ChessInfo* info, int line);
+static void reversi_movecur(int r, int c);
+static int reversi_prepare_play(ChessInfo* info);
+static int reversi_select(ChessInfo* info, rc_t scrloc, ChessGameResult* result);
+static void reversi_prepare_step(ChessInfo* info, const reversi_step_t* step);
+static ChessGameResult reversi_apply_step(board_t board, const reversi_step_t* step);
+static void reversi_drawstep(ChessInfo* info, const void* move);
+static ChessGameResult reversi_post_game(ChessInfo* info);
+static void reversi_gameend(ChessInfo* info, ChessGameResult result);
+static void reversi_genlog(ChessInfo* info, FILE* fp, ChessGameResult result);
+
+static const char *CHESS_TYPE[] = {NONE_CHESS, HINT_CHESS, BLACK_CHESS, WHITE_CHESS};
+static const char DIRX[] = {-1, -1, -1, 0, 1, 1, 1, 0};
+static const char DIRY[] = {-1, 0, 1, 1, 1, 0, -1, -1};
+
+static const ChessActions reversi_actions = {
+ &reversi_init_user,
+ &reversi_init_user_userec,
+ (void (*) (void*)) &reversi_init_board,
+ &reversi_drawline,
+ &reversi_movecur,
+ &reversi_prepare_play,
+ NULL, /* process_key */
+ &reversi_select,
+ (void (*)(ChessInfo*, const void*)) &reversi_prepare_step,
+ (ChessGameResult (*)(void*, const void*)) &reversi_apply_step,
+ &reversi_drawstep,
+ &reversi_post_game,
+ &reversi_gameend,
+ &reversi_genlog
+};
+
+const static ChessConstants reversi_constants = {
+ sizeof(reversi_step_t),
+ MAX_TIME,
+ BRDSIZ,
+ BRDSIZ,
+ 0,
+ "黑白棋",
+ "photo_reversi",
+#ifdef GLOBAL_REVERSI_LOG
+ GLOBAL_REVERSI_LOG,
+#else
+ NULL,
+#endif
+ { "", "" },
+ { "白棋", "黑棋" },
+};
+
+static int
+can_put(board_t board, color_t who, int x, int y)
+{
+ int i, temp, checkx, checky;
+
+ if (IS_BLANK(board[x][y]))
+ for (i = 0; i < 8; ++i) {
+ checkx = x + DIRX[i];
+ checky = y + DIRY[i];
+ temp = board[checkx][checky];
+ if (IS_BLANK(temp))
+ continue;
+ if (temp != who) {
+ while (board[checkx += DIRX[i]][checky += DIRY[i]] == temp);
+ if (board[checkx][checky] == who)
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static int
+caculate_hint(board_t board, color_t who)
+{
+ int i, j, count = 0;
+
+ for (i = 1; i <= 8; i++)
+ for (j = 1; j <= 8; j++) {
+ if (board[i][j] == HINT)
+ board[i][j] = NONE;
+ if (can_put(board, who, i, j)) {
+ board[i][j] = HINT;
+ ++count;
+ }
+ }
+ return count;
+}
+
+static void
+reversi_init_user(const userinfo_t* uinfo, ChessUser* user)
+{
+ strlcpy(user->userid, uinfo->userid, sizeof(user->userid));
+ user->win =
+ user->lose =
+ user->tie = 0;
+}
+
+static void
+reversi_init_user_userec(const userec_t* urec, ChessUser* user)
+{
+ strlcpy(user->userid, urec->userid, sizeof(user->userid));
+ user->win =
+ user->lose =
+ user->tie = 0;
+}
+
+static void
+reversi_init_board(board_t board)
+{
+ memset(board, NONE, sizeof(board_t));
+ board[4][4] = board[5][5] = WHITE;
+ board[4][5] = board[5][4] = BLACK;
+
+ caculate_hint(board, BLACK);
+}
+
+static void
+reversi_drawline(const ChessInfo* info, int line){
+ static const char* num_str[] =
+ {"", "1", "2", "3", "4", "5", "6", "7", "8"};
+ if(line)
+ move(line, STARTY);
+
+ 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 == 2)
+ outs(" A B C D E F G H");
+ else if (line == 3)
+ outs("┌─┬─┬─┬─┬─┬─┬─┬─┐");
+ else if (line == 19)
+ outs("└─┴─┴─┴─┴─┴─┴─┴─┘");
+ else if (line == 20)
+ prints(" (黑) %-15s%2d%*s",
+ info->myturn ? info->user1.userid : info->user2.userid,
+ ((reversi_tag_t*)info->tag)->number[COLOR_TO_TURN(BLACK)],
+ 34 - 24, "");
+ else if (line == 21)
+ prints(" (白) %-15s%2d%*s",
+ info->myturn ? info->user2.userid : info->user1.userid,
+ ((reversi_tag_t*)info->tag)->number[COLOR_TO_TURN(WHITE)],
+ 34 - 24, "");
+ else if (line > 3 && line < 19) {
+ if ((line & 1) == 1)
+ outs("├─┼─┼─┼─┼─┼─┼─┼─┤");
+ else {
+ int x = line / 2 - 1;
+ int y;
+ board_p board = (board_p) info->board;
+
+ move(line, STARTY - 2);
+ prints("%s│", num_str[x]);
+ for(y = 1; y <= 8; ++y)
+ prints("%s│", CHESS_TYPE[(int) board[x][y]]);
+ }
+ }
+
+ ChessDrawExtraInfo(info, line, 4);
+}
+
+static void
+reversi_movecur(int r, int c)
+{
+ move(r * 2 + 4, c * 4 + STARTY + 2);
+}
+
+static int
+reversi_prepare_play(ChessInfo* info)
+{
+ int x, y;
+ int result;
+ board_p board = (board_p) info->board;
+ reversi_tag_t* tag = (reversi_tag_t*) info->tag;
+
+ tag->number[0] = tag->number[1] = 0;
+ for(x = 1; x <= 8; ++x)
+ for(y = 1; y <= 8; ++y)
+ if (IS_CHESS(board[x][y]))
+ ++tag->number[COLOR_TO_TURN(board[x][y])];
+
+ result = !caculate_hint(board, TURN_TO_COLOR(info->turn));
+ if (result) {
+ reversi_step_t step = { CHESS_STEP_SPECIAL, TURN_TO_COLOR(info->turn) };
+ if (info->turn == info->myturn) {
+ ChessStepSend(info, &step);
+ ChessHistoryAppend(info, &step);
+ strcpy(info->last_movestr, "你必須放棄這一步!!");
+ } else {
+ ChessStepReceive(info, &step);
+ strcpy(info->last_movestr, "對方必須放棄這一步!!");
+ }
+ }
+
+ ChessRedraw(info);
+ return result;
+}
+
+static int
+reversi_select(ChessInfo* info, rc_t loc, ChessGameResult* result)
+{
+ board_p board = (board_p) info->board;
+
+ ++loc.r; ++loc.c;
+ if (can_put(board, TURN_TO_COLOR(info->turn), loc.r, loc.c)) {
+ reversi_step_t step = { CHESS_STEP_NORMAL,
+ TURN_TO_COLOR(info->turn), loc };
+ reversi_apply_step(board, &step);
+
+ snprintf(info->last_movestr, sizeof(info->last_movestr),
+ "%c%d", step.loc.c - 1 + 'A', step.loc.r);
+
+ ChessStepSend(info, &step);
+ ChessHistoryAppend(info, &step);
+
+ return 1;
+ } else
+ return 0;
+}
+
+static ChessGameResult
+reversi_apply_step(board_t board, const reversi_step_t* step)
+{
+ int i;
+ color_t opposite = INVERT(step->color);
+
+ if (step->type != CHESS_STEP_NORMAL)
+ return CHESS_RESULT_CONTINUE;
+
+ for (i = 0; i < 8; ++i) {
+ int x = step->loc.r;
+ int y = step->loc.c;
+
+ while (board[x += DIRX[i]][y += DIRY[i]] == opposite);
+
+ if (board[x][y] == step->color) {
+ x = step->loc.r;
+ y = step->loc.c;
+
+ while (board[x += DIRX[i]][y += DIRY[i]] == opposite)
+ board[x][y] = step->color;
+ }
+ }
+ board[step->loc.r][step->loc.c] = step->color;
+
+ return CHESS_RESULT_CONTINUE;
+}
+
+static void
+reversi_prepare_step(ChessInfo* info, const reversi_step_t* step)
+{
+ if (step->type == CHESS_STEP_NORMAL)
+ snprintf(info->last_movestr, sizeof(info->last_movestr),
+ "%c%d", step->loc.c - 1 + 'A', step->loc.r);
+ else if (step->color == TURN_TO_COLOR(info->myturn))
+ strcpy(info->last_movestr, "你必須放棄這一步!!");
+ else
+ strcpy(info->last_movestr, "對方必須放棄這一步!!");
+}
+
+static void
+reversi_drawstep(ChessInfo* info, const void* move)
+{
+ ChessRedraw(info);
+}
+
+static ChessGameResult
+reversi_post_game(ChessInfo* info)
+{
+ int x, y;
+ board_p board = (board_p) info->board;
+ reversi_tag_t* tag = (reversi_tag_t*) info->tag;
+
+ tag->number[0] = tag->number[1] = 0;
+ for(x = 1; x <= 8; ++x)
+ for(y = 1; y <= 8; ++y)
+ if (board[x][y] == HINT)
+ board[x][y] = NONE;
+ else if (IS_CHESS(board[x][y]))
+ ++tag->number[COLOR_TO_TURN(board[x][y])];
+
+ ChessRedraw(info);
+
+ if (tag->number[0] == tag->number[1])
+ return CHESS_RESULT_TIE;
+ else if (tag->number[(int) info->myturn] < tag->number[info->myturn ^ 1])
+ return CHESS_RESULT_LOST;
+ else
+ return CHESS_RESULT_WIN;
+}
+
+static void
+reversi_gameend(ChessInfo* info, ChessGameResult result)
+{
+ /* nothing to do now
+ * TODO game record */
+}
+
+static void
+reversi_genlog(ChessInfo* info, FILE* fp, ChessGameResult result)
+{
+ const int nStep = info->history.used;
+ int i;
+
+ for (i = 2; i <= 21; i++)
+ fprintf(fp, "%.*s\n", big_picture[i].len, big_picture[i].data);
+
+ fprintf(fp, "\n");
+ fprintf(fp, "按 z 可進入打譜模式\n");
+ fprintf(fp, "\n");
+
+ fprintf(fp, "<reversilog>\nblack:%s\nwhite:%s\n",
+ info->myturn ? info->user1.userid : info->user2.userid,
+ info->myturn ? info->user2.userid : info->user1.userid);
+
+ for (i = 0; i < nStep; ++i) {
+ const reversi_step_t* const step =
+ (const reversi_step_t*) ChessHistoryRetrieve(info, i);
+ if (step->type == CHESS_STEP_NORMAL)
+ fprintf(fp, "[%2d]%s ==> %c%-5d", i + 1,
+ CHESS_TYPE[(int) step->color],
+ 'A' + step->loc.c - 1, step->loc.r);
+ else
+ fprintf(fp, "[%2d]%s ==> pass ", i + 1,
+ CHESS_TYPE[(int) step->color]);
+ if (i % 2)
+ fputc('\n', fp);
+ }
+
+ if (i % 2)
+ fputc('\n', fp);
+ fputs("</reversilog>\n", fp);
+}
+
+static int
+reversi_loadlog(FILE *fp, ChessInfo *info)
+{
+ char buf[256];
+
+#define INVALID_ROW(R) ((R) <= 0 || (R) > 8)
+#define INVALID_COL(C) ((C) <= 0 || (C) > 8)
+ while (fgets(buf, sizeof(buf), fp)) {
+ if (strcmp("</reversilog>\n", buf) == 0)
+ return 1;
+ else if (strncmp("black:", buf, 6) == 0 ||
+ strncmp("white:", buf, 6) == 0) {
+ /* /(black|white):([a-zA-Z0-9]+)/; $2 */
+ userec_t rec;
+ ChessUser *user = (buf[0] == 'b' ? &info->user1 : &info->user2);
+
+ chomp(buf);
+ if (getuser(buf + 6, &rec))
+ reversi_init_user_userec(&rec, user);
+ } else if (buf[0] == '[') {
+ /* "[ 1]● ==> C4 [ 2]○ ==> C5" */
+ reversi_step_t step = { CHESS_STEP_NORMAL };
+ int c, r;
+ const char *p = buf;
+ int i;
+
+ for(i=0; i<2; i++) {
+ p = strchr(p, '>');
+
+ if (p == NULL) break;
+
+ ++p; /* skip '>' */
+ while (*p && isspace(*p)) ++p;
+ if (!*p) break;
+
+ /* i=0, p -> "C4 ..." */
+ /* i=1, p -> "C5\n" */
+
+ if (strncmp(p, "pass", 4) == 0)
+ /* [..] .. => pass */
+ step.type = CHESS_STEP_SPECIAL;
+ else {
+ c = p[0] - 'A' + 1;
+ r = atoi(p + 1);
+
+ if (INVALID_COL(c) || INVALID_ROW(r))
+ break;
+
+ step.loc.r = r;
+ step.loc.c = c;
+ }
+
+ step.color = i==0 ? BLACK : WHITE;
+ ChessHistoryAppend(info, &step);
+ }
+ }
+ }
+#undef INVALID_ROW
+#undef INVALID_COL
+ return 0;
+}
+
+void
+reversi(int s, ChessGameMode mode)
+{
+ ChessInfo* info = NewChessInfo(&reversi_actions, &reversi_constants, s, mode);
+ board_t board;
+ reversi_tag_t tag = { { 2, 2 } }; /* will be overridden */
+
+ reversi_init_board(board);
+
+ info->board = board;
+ info->tag = &tag;
+
+ info->cursor.r = 3;
+ info->cursor.c = 3;
+
+ if (mode == CHESS_MODE_WATCH)
+ setutmpmode(CHESSWATCHING);
+ else
+ setutmpmode(REVERSI);
+ currutmp->sig = SIG_REVERSI;
+
+ ChessPlay(info);
+
+ DeleteChessInfo(info);
+}
+
+int
+reversi_main(void)
+{
+ return ChessStartGame('r', SIG_REVERSI, "黑白棋");
+}
+
+int
+reversi_personal(void)
+{
+ reversi(0, CHESS_MODE_PERSONAL);
+ return 0;
+}
+
+int
+reversi_watch(void)
+{
+ return ChessWatchGame(&reversi, REVERSI, "黑白棋");
+}
+
+ChessInfo*
+reversi_replay(FILE* fp)
+{
+ ChessInfo *info;
+
+ info = NewChessInfo(&reversi_actions, &reversi_constants,
+ 0, CHESS_MODE_REPLAY);
+
+ if(!reversi_loadlog(fp, info)) {
+ DeleteChessInfo(info);
+ return NULL;
+ }
+
+ info->board = malloc(sizeof(board_t));
+ info->tag = malloc(sizeof(reversi_tag_t));
+
+ reversi_init_board(info->board);
+ /* tag will be initialized later */
+
+ return info;
+}
diff --git a/mbbsd/talk.c b/mbbsd/talk.c
index 7495bcba..a4ba7a1d 100644
--- a/mbbsd/talk.c
+++ b/mbbsd/talk.c
@@ -7,10 +7,10 @@ static char * const IdleTypeTable[] = {
"偶在花呆啦", "情人來電", "覓食中", "拜見周公", "假死狀態", "我在思考"
};
static char * const sig_des[] = {
- "鬥雞", "聊天", "", "下棋", "象棋", "暗棋", "下圍棋",
+ "鬥雞", "聊天", "", "下棋", "象棋", "暗棋", "下圍棋", "下黑白棋",
};
static char * const withme_str[] = {
- "談天", "下五子棋", "鬥寵物", "下象棋", "下暗棋", "下圍棋", NULL
+ "談天", "下五子棋", "鬥寵物", "下象棋", "下暗棋", "下圍棋", "下黑白棋", NULL
};
#define MAX_SHOW_MODE 6
@@ -1566,10 +1566,11 @@ my_talk(userinfo_t * uin, int fri_stat, char defact)
if (ch == EDITING || ch == TALK || ch == CHATING || ch == PAGE ||
ch == MAILALL || ch == MONITOR || ch == M_FIVE || ch == CHC ||
- ch == DARK || ch == UMODE_GO || ch == CHESSWATCHING ||
+ ch == DARK || ch == UMODE_GO || ch == CHESSWATCHING || ch == REVERSI ||
(!ch && (uin->chatid[0] == 1 || uin->chatid[0] == 3)) ||
uin->lockmode == M_FIVE || uin->lockmode == CHC) {
- if (ch == CHC || ch == M_FIVE || ch == UMODE_GO || ch == CHESSWATCHING) {
+ if (ch == CHC || ch == M_FIVE || ch == UMODE_GO ||
+ ch == CHESSWATCHING || ch == REVERSI) {
sock = make_connection_to_somebody(uin, 20);
if (sock < 0)
vmsg("無法建立連線");
@@ -1599,6 +1600,10 @@ my_talk(userinfo_t * uin, int fri_stat, char defact)
case SIG_GO:
gochess(msgsock, CHESS_MODE_WATCH);
break;
+
+ case SIG_REVERSI:
+ reversi(msgsock, CHESS_MODE_WATCH);
+ break;
}
}
}
@@ -1638,7 +1643,8 @@ my_talk(userinfo_t * uin, int fri_stat, char defact)
outc('\n');
}
}
- outs("要和他(她) (T)談天(F)下五子棋(P)鬥寵物(C)下象棋(D)下暗棋(G)下圍棋\n");
+ move(4, 0);
+ outs("要和他(她) (T)談天(F)下五子棋(P)鬥寵物(C)下象棋(D)下暗棋(G)下圍棋(R)下黑白棋");
getdata(5, 0, " (N)沒事找錯人了?[N] ", genbuf, 4, LCECHO);
}
@@ -1661,6 +1667,9 @@ my_talk(userinfo_t * uin, int fri_stat, char defact)
case 'g':
uin->sig = SIG_GO;
break;
+ case 'r':
+ uin->sig = SIG_REVERSI;
+ break;
case 'p':
reload_chicken();
getuser(uin->userid, &xuser);
@@ -1705,7 +1714,8 @@ my_talk(userinfo_t * uin, int fri_stat, char defact)
close(sock);
currutmp->sockactive = NA;
- if (uin->sig == SIG_CHC || uin->sig == SIG_GOMO || uin->sig == SIG_GO)
+ if (uin->sig == SIG_CHC || uin->sig == SIG_GOMO ||
+ uin->sig == SIG_GO || uin->sig == SIG_REVERSI)
ChessEstablishRequest(msgsock);
add_io(msgsock, 0);
@@ -1725,7 +1735,6 @@ my_talk(userinfo_t * uin, int fri_stat, char defact)
if (c == 'y') {
snprintf(save_page_requestor, sizeof(save_page_requestor),
"%s (%s)", uin->userid, uin->nickname);
- /* gomo */
switch (uin->sig) {
case SIG_DARK:
main_dark(msgsock, uin);
@@ -1742,6 +1751,9 @@ my_talk(userinfo_t * uin, int fri_stat, char defact)
case SIG_GO:
gochess(msgsock, CHESS_MODE_VERSUS);
break;
+ case SIG_REVERSI:
+ reversi(msgsock, CHESS_MODE_VERSUS);
+ break;
case SIG_TALK:
default:
do_talk(msgsock);
@@ -3164,7 +3176,7 @@ talkreply(void)
currutmp->destuid = uip->uid;
currstat = REPLY; /* 避免出現動畫 */
- is_chess = (sig == SIG_CHC || sig == SIG_GOMO || sig == SIG_GO);
+ is_chess = (sig == SIG_CHC || sig == SIG_GOMO || sig == SIG_GO || sig == SIG_REVERSI);
a = reply_connection_request(uip);
if (a < 0) {
@@ -3254,6 +3266,9 @@ talkreply(void)
case SIG_GO:
gochess(a, CHESS_MODE_VERSUS);
break;
+ case SIG_REVERSI:
+ reversi(a, CHESS_MODE_VERSUS);
+ break;
case SIG_TALK:
default:
do_talk(a);