From 715542867ba891acf8c1fd6234f5d6ea2fc285f6 Mon Sep 17 00:00:00 2001
From: scw <scw@63ad8ddf-47c3-0310-b6dd-a9e9d9715204>
Date: Wed, 30 May 2007 15:42:18 +0000
Subject: Reversi (multiplayer othello) added

git-svn-id: http://opensvn.csie.org/pttbbs/trunk/pttbbs@3523 63ad8ddf-47c3-0310-b6dd-a9e9d9715204
---
 mbbsd/Makefile  |   2 +-
 mbbsd/chc.c     |   8 +-
 mbbsd/chess.c   |  22 ++-
 mbbsd/go.c      |   6 +-
 mbbsd/gomo.c    |   8 +-
 mbbsd/pmore.c   |   2 +-
 mbbsd/reversi.c | 506 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 mbbsd/talk.c    |  31 +++-
 8 files changed, 558 insertions(+), 27 deletions(-)
 create mode 100644 mbbsd/reversi.c

(limited to 'mbbsd')

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/[-/]+)             �D�D���\\Ū:�`��/�e/��g",
     "(\\/|)                 ������ܭ�l���e", // this IS already aligned!
     "(w/W/l)               �����۰��_��/�_��Ÿ�/���j�u��ܤ覡",
-    "(p/o)                 ����ʵe/�����DzμҦ�(���A�C�P�_��覡)",
+    "(p/z/o)               ����ʵe/�ѧ�����/�����DzμҦ�(���A�C�P�_��覡)",
     "(q/��) (h/H/?/F1)     ����/�������e��",
 #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) 	/* �ѽL����j�p */
+
+#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[] =
+    {"", "��", "��", "��", "��", "��", "��", "��", "��"};
+    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("  ��  ��  ��  ��  ��  ��  ��  ��");
+    else if (line == 3)
+	outs("�z�w�s�w�s�w�s�w�s�w�s�w�s�w�s�w�{");
+    else if (line == 19)
+	outs("�|�w�r�w�r�w�r�w�r�w�r�w�r�w�r�w�}");
+    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("�u�w�q�w�q�w�q�w�q�w�q�w�q�w�q�w�t");
+	else {
+	    int x = line / 2 - 1;
+	    int y;
+	    board_p board = (board_p) info->board;
+
+	    move(line, STARTY - 2);
+	prints("%s�x", num_str[x]);
+	    for(y = 1; y <= 8; ++y)
+		prints("%s�x", 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, "�A�������o�@�B!!");
+	} else {
+	    ChessStepReceive(info, &step);
+	    strcpy(info->last_movestr, "��襲�����o�@�B!!");
+	}
+    }
+
+    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, "�A�������o�@�B!!");
+    else
+	strcpy(info->last_movestr, "��襲�����o�@�B!!");
+}
+
+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 �i�i�J���мҦ�\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[] = {
     "���b��b��", "���H�ӹq", "�V����", "�����P��", "�������A", "�ڦb���"
 };
 static char    * const sig_des[] = {
-    "����", "���", "", "�U��", "�H��", "�t��", "�U���",
+    "����", "���", "", "�U��", "�H��", "�t��", "�U���", "�U�¥մ�",
 };
 static char    * const withme_str[] = {
-  "�ͤ�", "�U���l��", "���d��", "�U�H��", "�U�t��", "�U���", NULL
+  "�ͤ�", "�U���l��", "���d��", "�U�H��", "�U�t��", "�U���", "�U�¥մ�", 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("�L�k�إ߳s�u");
@@ -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("�n�M�L(�o) (T)�ͤ�(F)�U���l��(P)���d��(C)�U�H��(D)�U�t��(G)�U���\n");
+	    move(4, 0);
+	    outs("�n�M�L(�o) (T)�ͤ�(F)�U���l��(P)���d��(C)�U�H��(D)�U�t��(G)�U���(R)�U�¥մ�");
 	    getdata(5, 0, "           (N)�S�Ƨ���H�F?[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;		/* �קK�X�{�ʵe */
 
-    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);
-- 
cgit v1.2.3