/* $Id$ */
#include "bbs.h"
#include "gomo.h"
#define QCAST int (*)(const void *, const void *)
static int tick, lastcount, mylasttick, hislasttick;
//static char ku[BRDSIZ][BRDSIZ];
static Horder_t *v;
static int draw_photo;
#define move(y,x) move(y, (x) + ((y) < 2 || (y) > 16 ? 0 : \
(x) > 35 ? 11 : 8))
/* pattern and advance map */
static int
intrevcmp(const void *a, const void *b)
{
return (*(int *)b - *(int *)a);
}
// 以 (x,y) 為起點, 方向 (dx,dy), 傳回以 bit 表示相鄰哪幾格有子
// 如 10111 表示該方向相鄰 1,2,3 有子, 4 空地
// 最高位 1 表示對方的子, 或是牆
/* x,y: 0..BRDSIZ-1 ; color: CBLACK,CWHITE ; dx,dy: -1,0,+1 */
static int
gomo_getindex(char ku[][BRDSIZ], int x, int y, int color, int dx, int dy)
{
int i, k, n;
for (n = -1, i = 0, k = 1; i < 5; i++, k*=2) {
x += dx;
y += dy;
if ((x < 0) || (x >= BRDSIZ) || (y < 0) || (y >= BRDSIZ)) {
n += k;
break;
} else if (ku[x][y] != BBLANK) {
n += k;
if (ku[x][y] != color)
break;
}
}
if (i >= 5)
n += k;
return n;
}
int
chkwin(int style, int limit)
{
if (style == 0x0c)
return 1 /* style */ ;
else if (limit == 0) {
if (style == 0x0b)
return 1 /* style */ ;
return 0;
}
if ((style < 0x0c) && (style > 0x07))
return -1 /* -style */ ;
return 0;
}
static int getstyle(char ku[][BRDSIZ], int x, int y, int color, int limit);
/* x,y: 0..BRDSIZ-1 ; color: CBLACK,CWHITE ; limit:1,0 ; dx,dy: 0,1 */
static int
dirchk(char ku[][BRDSIZ], int x, int y, int color, int limit, int dx, int dy)
{
int le, ri, loc, style = 0;
le = gomo_getindex(ku, x, y, color, -dx, -dy);
ri = gomo_getindex(ku, x, y, color, dx, dy);
loc = (le > ri) ? (((le * (le + 1)) >> 1) + ri) :
(((ri * (ri + 1)) >> 1) + le);
style = pat[loc];
if (limit == 0)
return (style & 0x0f);
style >>= 4;
if ((style == 3) || (style == 2)) {
int i, n = 0, tmp, nx, ny;
n = adv[loc / 2];
if(loc%2==0)
n/=16;
else
n%=16;
ku[x][y] = color;
for (i = 0; i < 2; i++) {
if ((tmp = (i == 0) ? (-(n >> 2)) : (n & 3)) != 0) {
nx = x + (le > ri ? 1 : -1) * tmp * dx;
ny = y + (le > ri ? 1 : -1) * tmp * dy;
if ((dirchk(ku, nx, ny, color, 0, dx, dy) == 0x06) &&
(chkwin(getstyle(ku, nx, ny, color, limit), limit) >= 0))
break;
}
}
if (i >= 2)
style = 0;
ku[x][y] = BBLANK;
}
return style;
}
/* 例外=F 錯誤=E 有子=D 連五=C 連六=B 雙四=A 四四=9 三三=8 */
/* 四三=7 活四=6 斷四=5 死四=4 活三=3 斷三=2 保留=1 無效=0 */
/* x,y: 0..BRDSIZ-1 ; color: CBLACK,CWHITE ; limit: 1,0 */
static int
getstyle(char ku[][BRDSIZ], int x, int y, int color, int limit)
{
int i, j, dir[4], style;
if ((x < 0) || (x >= BRDSIZ) || (y < 0) || (y >= BRDSIZ))
return 0x0f;
if (ku[x][y] != BBLANK)
return 0x0d;
// (-1,1), (0,1), (1,0), (1,1)
for (i = 0; i < 4; i++)
dir[i] = dirchk(ku, x, y, color, limit, i ? (i >> 1) : -1, i ? (i & 1) : 1);
qsort(dir, 4, sizeof(int), (QCAST)intrevcmp);
if ((style = dir[0]) >= 2) {
for (i = 1, j = 6 + (limit ? 1 : 0); i < 4; i++) {
if ((style > j) || (dir[i] < 2))
break;
if (dir[i] > 3)
style = 9;
else if ((style < 7) && (style > 3))
style = 7;
else
style = 8;
}
}
return style;
}
static void
HO_init(char ku[][BRDSIZ], Horder_t *pool)
{
memset(pool, 0, sizeof(Horder_t)*BRDSIZ*BRDSIZ);
v = pool;
pat = pat_gomoku;
adv = adv_gomoku;
memset(ku, 0, (BRDSIZ*BRDSIZ));
}
static void
HO_add(Horder_t * mv)
{
*v++ = *mv;
}
static void
HO_undo(char ku[][BRDSIZ], Horder_t * mv)
{
char *str = "┌┬┐├┼┤└┴┘";
int n1, n2, loc;
*mv = *(--v);
ku[(int)mv->x][(int)mv->y] = BBLANK;
BGOTO(mv->x, mv->y);
n1 = (mv->x == 0) ? 0 : (mv->x == 14) ? 2 : 1;
n2 = (mv->y == 14) ? 0 : (mv->y == 0) ? 2 : 1;
loc = 2 * (n2 * 3 + n1);
prints("%.2s", str + loc);
redoln();
}
static void
HO_log(Horder_t *pool, FILE* fp, char *mate)
{
int i;
Horder_t *ptr = pool;
for (i = 1; i < 18; i++)
fprintf(fp, "%.*s\n", big_picture[i].len, big_picture[i].data);
if (mate != NULL)
fprintf(fp, "<gomokulog>\nblack:%s\nwhite:%s\n", cuser.userid, mate);
i = 0;
do {
fprintf(fp, "[%2d]%s ==> %c%-5d", i + 1, bw_chess[i % 2],
'A' + ptr->x, ptr->y + 1);
if (i % 2)
fputc('\n', fp);
i++;
} while (++ptr < v);
if (mate != NULL)
fputs("\n</gomokulog>\n", fp);
}
static void
HO_log_user(Horder_t* pool, char *mate)
{
char buf[200];
fileheader_t mail_header;
FILE* fp;
sethomepath(buf, cuser.userid);
stampfile(buf, &mail_header);
fp = fopen(buf, "w");
if (fp != NULL) {
HO_log(pool, fp, NULL);
fclose(fp);
mail_header.filemode = FILE_READ;
strlcpy(mail_header.owner, "[備.忘.錄]", sizeof(mail_header.owner));
snprintf(mail_header.title, sizeof(mail_header.title),
ANSI_COLOR(37;41) "棋譜" ANSI_RESET " %s VS %s", cuser.userid, mate);
sethomedir(buf, cuser.userid);
append_record(buf, &mail_header, sizeof(mail_header));
}
}
#ifdef GLOBAL_FIVECHESS_LOG
static void
HO_log_board(Horder_t* pool, char *mate)
{
char buf[200];
fileheader_t log_header;
FILE* fp;
int bid;
if ((bid = getbnum(GLOBAL_FIVECHESS_LOG)) == 0)
return;
setbpath(buf, GLOBAL_FIVECHESS_LOG);
stampfile(buf, &log_header);
fp = fopen(buf, "w");
if (fp != NULL) {
HO_log(pool, fp, mate);
fclose(fp);
strlcpy(log_header.owner, "[棋譜機器人]", sizeof(log_header.owner));
snprintf(log_header.title, sizeof(log_header.title),
"[棋譜] %s VS %s", cuser.userid, mate);
setbdir(buf, GLOBAL_FIVECHESS_LOG);
append_record(buf, &log_header, sizeof(log_header));
setbtotal(bid);
}
}
#endif
static int
countgomo(Horder_t *pool)
{
return v-pool;
}
static int
chkmv(char ku[][BRDSIZ], Horder_t * mv, int color, int limit)
{
char *xtype[] = {ANSI_COLOR(1;31) "跳三" ANSI_RESET, ANSI_COLOR(1;31) "活三" ANSI_RESET,
ANSI_COLOR(1;31) "死四" ANSI_RESET, ANSI_COLOR(1;31) "跳四" ANSI_RESET,
ANSI_COLOR(1;31) "活四" ANSI_RESET, ANSI_COLOR(1;31) "四三" ANSI_RESET,
ANSI_COLOR(1;31) "雙三" ANSI_RESET, ANSI_COLOR(1;31) "雙四" ANSI_RESET,
ANSI_COLOR(1;31) "雙四" ANSI_RESET, ANSI_COLOR(1;31) "連六" ANSI_RESET,
ANSI_COLOR(1;31) "連五" ANSI_RESET};
int rule = getstyle(ku, mv->x, mv->y, color, limit);
if (rule > 1 && rule < 13) {
move(draw_photo ? 19 : 15, 40);
outs(xtype[rule - 2]);
bell();
}
return chkwin(rule, limit);
}
static int
gomo_key(char ku[][BRDSIZ], int fd, int ch, Horder_t * mv)
{
if (ch >= 'a' && ch <= 'o') {
char pbuf[4], vx, vy;
pbuf[0] = ch;
pbuf[1] = '\0';
if (fd)
add_io(0, 0);
oldgetdata(17, 0, "直接指定位置 :", pbuf, sizeof(pbuf), DOECHO);
if (fd)
add_io(fd, 0);
vx = pbuf[0] - 'a';
vy = atoi(pbuf + 1) - 1;
if (vx >= 0 && vx < 15 && vy >= 0 && vy < 15 &&
ku[(int)vx][(int)vy] == BBLANK) {
mv->x = vx;
mv->y = vy;
return 1;
}
} else {
switch (ch) {
case KEY_RIGHT:
if(mv->x<BRDSIZ-1)
mv->x++;
break;
case KEY_LEFT:
if(mv->x>0)
mv->x--;
break;
case KEY_UP:
if(mv->y<BRDSIZ-1)
mv->y++;
break;
case KEY_DOWN:
if(mv->y>0)
mv->y--;
break;
case ' ':
case '\r':
if (ku[(int)mv->x][(int)mv->y] == BBLANK)
return 1;
}
}
return 0;
}
#define PASS_REQUEST -2
#define PASS_REJECT -3
#define UNDO_REQUEST -1
#define UNDO_REJECT -4
int
gomoku(int fd)
{
Horder_t mv;
int me, he, ch;
char hewantpass, iwantpass, passrejected;
char hewantundo, iwantundo, undorejected;
userinfo_t *my = currutmp;
Horder_t pool[BRDSIZ*BRDSIZ];
int scr_need_redraw;
char ku[BRDSIZ][BRDSIZ];
char genbuf[200];
userec_t xuser;
HO_init(ku, pool);
me = !(my->turn) + 1;
he = my->turn + 1;
tick = now + MAX_TIME;
lastcount = MAX_TIME;
setutmpmode(M_FIVE);
clear();
prints(ANSI_COLOR(1;46) " 五子棋對戰 " ANSI_COLOR(45) "%30s VS %-30s" ANSI_RESET,
cuser.userid, my->mateid);
//show_file("etc/@five", 1, -1, ONLY_COLOR);
move(1, 0);
outs(
" A B C D E F G H I J K L M N\n"
" 15" ANSI_COLOR(30;43) "┌┬┬┬┬┬┬┬┬┬┬┬┬┬┐" ANSI_RESET "\n"
" 14" ANSI_COLOR(30;43) "├┼┼┼┼┼┼┼┼┼┼┼┼┼┤" ANSI_RESET "\n"
" 13" ANSI_COLOR(30;43) "├┼┼┼┼┼┼┼┼┼┼┼┼┼┤" ANSI_RESET "\n"
" 12" ANSI_COLOR(30;43) "├┼┼┼┼┼┼┼┼┼┼┼┼┼┤" ANSI_RESET "\n"
" 11" ANSI_COLOR(30;43) "├┼┼┼┼┼┼┼┼┼┼┼┼┼┤" ANSI_RESET "\n"
" 10" ANSI_COLOR(30;43) "├┼┼┼┼┼┼┼┼┼┼┼┼┼┤" ANSI_RESET "\n"
" 9" ANSI_COLOR(30;43) "├┼┼┼┼┼┼┼┼┼┼┼┼┼┤" ANSI_RESET "\n"
" 8" ANSI_COLOR(30;43) "├┼┼┼┼┼┼┼┼┼┼┼┼┼┤" ANSI_RESET "\n"
" 7" ANSI_COLOR(30;43) "├┼┼┼┼┼┼┼┼┼┼┼┼┼┤" ANSI_RESET "\n"
" 6" ANSI_COLOR(30;43) "├┼┼┼┼┼┼┼┼┼┼┼┼┼┤" ANSI_RESET "\n"
" 5" ANSI_COLOR(30;43) "├┼┼┼┼┼┼┼┼┼┼┼┼┼┤" ANSI_RESET "\n"
" 4" ANSI_COLOR(30;43) "├┼┼┼┼┼┼┼┼┼┼┼┼┼┤" ANSI_RESET "\n"
" 3" ANSI_COLOR(30;43) "├┼┼┼┼┼┼┼┼┼┼┼┼┼┤" ANSI_RESET "\n"
" 2" ANSI_COLOR(30;43) "├┼┼┼┼┼┼┼┼┼┼┼┼┼┤" ANSI_RESET "\n"
" 1" ANSI_COLOR(30;43) "└┴┴┴┴┴┴┴┴┴┴┴┴┴┘" ANSI_RESET "\n"
);
draw_photo = 0;
setuserfile(genbuf, "photo_fivechess");
if (dashf(genbuf))
draw_photo = 1;
else {
sethomefile(genbuf, my->mateid, "photo_fivechess");
if (dashf(genbuf))
draw_photo = 1;
}
getuser(my->mateid, &xuser);
if (draw_photo) {
int line;
FILE* fp;
static const char * const blank_photo[6] = {
"┌──────┐",
"│ 空 │",
"│ 白 │",
"│ 照 │",
"│ 片│",
"└──────┘"
};
char country[5], level[11];
setuserfile(genbuf, "photo_fivechess");
fp = fopen(genbuf, "r");
if (fp == NULL) {
strcpy(country, "無");
level[0] = 0;
} else {
int i, j;
for (line = 1; line < 8; ++line)
fgets(genbuf, 200, fp);
fgets(genbuf, 200, fp);
chomp(genbuf);
strip_ansi(genbuf + 11, genbuf + 11,
STRIP_ALL); /* country name may have color */
for (i = 11, j = 0; genbuf[i] && j < 4; ++i)
if (genbuf[i] != ' ') /* and spaces */
country[j++] = genbuf[i];
country[j] = 0; /* two chinese words */
fgets(genbuf, 200, fp);
chomp(genbuf);
strlcpy(level, genbuf + 11, 11); /* five chinese words*/
rewind(fp);
}
for (line = 2; line < 8; ++line) {
move(line, 37);
if (fp != NULL) {
if (fgets(genbuf, 200, fp)) {
chomp(genbuf);
prints("%s ", genbuf);
} else
outs(" ");
} else
outs(blank_photo[line - 2]);
switch (line - 2) {
case 0: prints("<代號> %s", cuser.userid); break;
case 1: prints("<暱稱> %.16s", cuser.nickname); break;
case 2: prints("<上站> %d", cuser.numlogins); break;
case 3: prints("<文章> %d", cuser.numposts); break;
case 4: prints("<職位> %-4s %s", country, level); break;
case 5: prints("<來源> %.16s", cuser.lasthost); break;
}
}
if (fp != NULL)
fclose(fp);
move(8, 43);
prints(ANSI_COLOR(7) "%s" ANSI_RESET, me == BBLACK ? "黑棋" : "白棋");
move(9, 43);
outs(" V.S ");
move(10, 68);
prints(ANSI_COLOR(7) "%s" ANSI_RESET, me == BBLACK ? "白棋" : "黑棋");
sethomefile(genbuf, my->mateid, "photo_fivechess");
fp = fopen(genbuf, "r");
if (fp == NULL) {
strcpy(country, "無");
level[0] = 0;
} else {
int i, j;
for (line = 1; line < 8; ++line)
fgets(genbuf, 200, fp);
fgets(genbuf, 200, fp);
chomp(genbuf);
strip_ansi(genbuf + 11, genbuf + 11,
STRIP_ALL); /* country name may have color */
for (i = 11, j = 0; genbuf[i] && j < 4; ++i)
if (genbuf[i] != ' ') /* and spaces */
country[j++] = genbuf[i];
country[j] = 0; /* two chinese words */
fgets(genbuf, 200, fp);
chomp(genbuf);
strlcpy(level, genbuf + 11, 11); /* five chinese words*/
rewind(fp);
}
for (line = 11; line < 17; ++line) {
move(line, 37);
switch (line - 11) {
case 0: prints("<代號> %-16.16s ", xuser.userid); break;
case 1: prints("<暱稱> %-16.16s ", xuser.nickname); break;
case 2: prints("<上站> %-16d ", xuser.numlogins); break;
case 3: prints("<文章> %-16d ", xuser.numposts); break;
case 4: prints("<職位> %-4s %-10s ", country, level); break;
case 5: prints("<來源> %-16.16s ", xuser.lasthost); break;
}
if (fp != NULL) {
if (fgets(genbuf, 200, fp)) {
chomp(genbuf);
outs(genbuf);
} else
outs(" ");
} else
outs(blank_photo[line - 11]);
}
if (fp != NULL)
fclose(fp);
move(18, 4);
prints("我是 %s", me == BBLACK ? "先手 ●,有禁手" : "後手 ○");
} else {
move(3, 40); outs("[q] 認輸離開");
move(4, 40); outs("[u] 悔棋");
move(5, 40); outs("[p] 要求和棋");
move(9, 39); outs("[歡迎到five_chess討論五子棋喔]");
move(11, 40);
prints("我是 %s", me == BBLACK ? "先手 ●, 有禁手" : "後手 ○");
move(16, 40);
prints(ANSI_COLOR(1;33) "%s", cuser.userid);
move(17, 40);
prints(ANSI_COLOR(1;33) "%s", my->mateid);
move(16, 60);
prints(ANSI_COLOR(1;31) "%d" ANSI_COLOR(37) "勝 " ANSI_COLOR(34) "%d" ANSI_COLOR(37) "敗 " ANSI_COLOR(36) "%d" ANSI_COLOR(37) "和"
ANSI_RESET, cuser.five_win, cuser.five_lose, cuser.five_tie);
move(17, 60);
prints(ANSI_COLOR(1;31) "%d" ANSI_COLOR(37) "勝 " ANSI_COLOR(34) "%d" ANSI_COLOR(37) "敗 " ANSI_COLOR(36) "%d" ANSI_COLOR(37) ""
"和" ANSI_RESET, xuser.five_win, xuser.five_lose, xuser.five_tie);
move(18, 40);
prints("%s時間還剩%d:%02d\n", my->turn ? "你的" : "對方",
MAX_TIME / 60, MAX_TIME % 60);
}
cuser.five_lose++;
/* 一進來先加一場敗場, 贏了後再扣回去, 避免快輸了惡意斷線 */
passwd_update(usernum, &cuser);
add_io(fd, 0);
hewantpass = iwantpass = passrejected = 0;
hewantundo = iwantundo = undorejected = 0;
mv.x = mv.y = 7;
scr_need_redraw = 1;
for (;;) {
if (scr_need_redraw){
if (draw_photo)
move(19, 4);
else
move(13, 40);
outs(my->turn ? "輪到自己下了!" : "等待對方下子..");
redoln();
outmsg(ANSI_COLOR(1;33;42) " 下五子棋 " 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_RESET);
scr_need_redraw = 0;
}
if (lastcount != tick - now) {
lastcount = tick - now;
move(18, 40);
prints("%s時間還剩%d:%02d\n", my->turn ? "你的" : "對方",
lastcount / 60, lastcount % 60);
if (lastcount <= 0 && my->turn) {
move(19, 40);
outs("時間已到, 你輸了");
my->five_lose++;
send(fd, '\0', 1, 0);
break;
}
if (lastcount <= -5 && !my->turn) {
move(19, 40);
outs("對手太久沒下, 你贏了!");
cuser.five_lose--;
cuser.five_win++;
my->five_win++;
passwd_update(usernum, &cuser);
mv.x = mv.y = -2;
send(fd, &mv, sizeof(Horder_t), 0);
mv = *(v - 1);
break;
}
}
move(draw_photo ? 20 : 14, 40);
clrtoeol();
if (hewantpass) {
outs(ANSI_COLOR(1;32) "和棋要求!" ANSI_RESET);
bell();
} else if (iwantpass)
outs(ANSI_COLOR(1;32) "提出和棋要求!" ANSI_RESET);
else if (passrejected) {
outs(ANSI_COLOR(1;32) "要求被拒!" ANSI_RESET);
passrejected = 0;
} else if (hewantundo) {
outs(ANSI_COLOR(1;33) "悔棋要求! (按 u 接受, 任意鍵拒絕)" ANSI_RESET);
bell();
} else if (iwantundo)
outs(ANSI_COLOR(1;33) "提出悔棋要求!" ANSI_RESET);
else if (undorejected) {
outs(ANSI_COLOR(1;33) "要求被拒!" ANSI_RESET);
undorejected = 0;
}
BGOTOCUR(mv.x, mv.y);
ch = igetch();
if ((iwantpass || hewantpass) && ch != 'p' && ch != I_OTHERDATA) {
mv.x = mv.y = PASS_REJECT;
send(fd , &mv, sizeof(Horder_t), 0);
mv = *(v - 1);
iwantpass = 0;
hewantpass = 0;
continue;
}
if ((iwantundo || hewantundo) && ch != 'u' && ch != I_OTHERDATA) {
mv.x = mv.y = UNDO_REJECT;
send(fd , &mv, sizeof(Horder_t), 0);
mv = *(v - 1);
iwantundo = 0;
hewantundo = 0;
continue;
}
if (ch == 'q') {
if (countgomo(pool) < 10) {
cuser.five_lose--;
passwd_update(usernum, &cuser);
}
send(fd, "", 1, 0);
break;
} else if (ch == 'u') {
if (my->turn) {
if (hewantundo) {
mv.x = mv.y = UNDO_REQUEST;
ch = send(fd, &mv, sizeof(Horder_t), 0);
tick = hislasttick;
HO_undo(ku, &mv);
my->turn = 0;
hewantundo = 0;
scr_need_redraw = 1;
}
continue;
}
else if (v > pool) {
mv.x = mv.y = UNDO_REQUEST;
ch = send(fd, &mv, sizeof(Horder_t), 0);
if (ch == sizeof(Horder_t)) {
iwantundo = 1;
continue;
} else
break;
}
}
if (ch == 'p') {
if (my->turn) {
if (iwantpass == 0) {
iwantpass = 1;
mv.x = mv.y = PASS_REQUEST;
send(fd, &mv, sizeof(Horder_t), 0);
mv = *(v - 1);
}
continue;
} else if (hewantpass) {
cuser.five_lose--;
cuser.five_tie++;
my->five_tie++;
passwd_update(usernum, &cuser);
mv.x = mv.y = PASS_REQUEST;
send(fd, &mv, sizeof(Horder_t), 0);
mv = *(v - 1);
break;
}
}
if (ch == I_OTHERDATA) {
ch = recv(fd, &mv, sizeof(Horder_t), 0);
if (ch != sizeof(Horder_t)) {
lastcount = tick - now;
if (lastcount >= 0) {
cuser.five_lose--;
if (countgomo(pool) >= 10) {
cuser.five_win++;
my->five_win++;
}
passwd_update(usernum, &cuser);
outmsg("對方認輸了!!");
break;
} else {
outmsg("你超過時間未下子, 輸了!");
my->five_lose++;
break;
}
} else if (mv.x == PASS_REQUEST && mv.y == PASS_REQUEST) {
if (iwantpass == 1) {
cuser.five_lose--;
cuser.five_tie++;
my->five_tie++;
passwd_update(usernum, &cuser);
break;
} else {
hewantpass = 1;
mv = *(v - 1);
continue;
}
} else if (mv.x == PASS_REJECT && mv.y == PASS_REJECT) {
if (iwantpass)
passrejected = 1;
iwantpass = 0;
hewantpass = 0;
mv = *(v - 1);
continue;
} else if (mv.x == UNDO_REJECT && mv.y == UNDO_REJECT) {
if (iwantundo)
undorejected = 1;
iwantundo = 0;
hewantundo = 0;
mv = *(v - 1);
continue;
} else if (mv.x == UNDO_REQUEST && mv.y == UNDO_REQUEST) {
if (!my->turn) {
if (iwantundo) {
HO_undo(ku, &mv);
tick = mylasttick;
my->turn = 1;
iwantundo = hewantundo = 0;
scr_need_redraw = 1;
}
/* else shouldn't happend */
} else {
hewantundo = 1;
mv = *(v - 1);
}
continue;
}
if (!my->turn) {
int win;
win = chkmv(ku, &mv, he, he == BBLACK);
HO_add(&mv);
hislasttick = tick;
tick = now + MAX_TIME;
ku[(int)mv.x][(int)mv.y] = he;
bell();
BGOTO(mv.x, mv.y);
outs(bw_chess[he - 1]);
redoln();
if (win) {
outmsg(win == 1 ? "對方贏了!" : "對方禁手");
if (win != 1) {
cuser.five_lose--;
cuser.five_win++;
my->five_win++;
passwd_update(usernum, &cuser);
} else
my->five_lose++;
break;
}
my->turn = 1;
}
scr_need_redraw = 1;
continue;
}
if (my->turn) {
if (gomo_key(ku, fd, ch, &mv))
my->turn = 0;
else
continue;
if (!my->turn) {
int win;
HO_add(&mv);
BGOTO(mv.x, mv.y);
outs(bw_chess[me - 1]);
redoln();
win = chkmv(ku, &mv, me, me == BBLACK);
ku[(int)mv.x][(int)mv.y] = me;
mylasttick = tick;
tick = now + MAX_TIME; /* 倒數 */
lastcount = MAX_TIME;
if (send(fd, &mv, sizeof(Horder_t), 0) != sizeof(Horder_t))
break;
if (win) {
outmsg(win == 1 ? "我贏囉~~" : "禁手輸了");
if (win == 1) {
cuser.five_lose--;
cuser.five_win++;
my->five_win++;
passwd_update(usernum, &cuser);
} else
my->five_lose++;
break;
}
move(draw_photo ? 19 : 15, 40);
clrtoeol();
}
scr_need_redraw = 1;
}
}
add_io(0, 0);
close(fd);
igetch();
if (v > pool) {
char ans[4];
getdata(19, 0, "要保留本局成棋譜嗎?(y/N)", ans, sizeof(ans), LCECHO);
if (*ans == 'y')
HO_log_user(pool, my->mateid);
#ifdef GLOBAL_FIVECHESS_LOG
if (me == BBLACK)
HO_log_board(pool, my->mateid);
#endif
}
return 0;
}