summaryrefslogblamecommitdiffstats
path: root/mbbsd/gomo.c
blob: 52d7bbf399d781feda7e2e0740894fd7bbb5f91b (plain) (tree)
1
2
3
4
5
6
7
8
9
          
                
                 
 

                                                   
                                                         
                                     
 
                   
                       
 


                                                                  












                                                               
                                                                         




































                                                                   
                                                                           

                                                                      
                                                                             


                                           

                                                  



























                                                                

                                                                             













                                                             
          
                                                               









                                                             
                                                                                    
















                                                          
 
           
                                          
 
                                                    


                     
                                   

 
           

                     


               
           
                                         


                                               




                                                  

                                                  
                              
             

 
           
                                            

                      
                               
 
                            



                                                                             
 

          
                                                                 
                                                                 
            
                        
 

















                                       
 


                                                                            
                                                                                     
 


                                                              

 






                                        



                                                   










                                                                            
                                                                                     


                                                            

                       



      
          
                         
 
                  

 
          
                                                             
 





                                                                                                      
                                                                    
                                
                                       





                               
          
                                                          



                                        
                     

                       
               
                         

                                                                        
                          



                                                       


                       
         
            
                     
                       

                              
                  
                      

                        
                  
                    

                              
                  
                      

                        
                  

                  
                                                     
                         
         



             




                       
   


                       
                               
                                                        
                                                        
                                  
                                        
                         
                            
                     
                   
 
                      

                         
                          


                         
 
                                                                                       
                                     



                                                














                                                                                    
          
 

                                           


                       



                                                           
 
                                
                     

                 
                                                    






                               
                                   


                                               




                                  
                     

                                            
 

                                   






                                                                        





                                                                    

                                          

                                             
                                  


                                               
                  
                                            





                                                                      
                                                                         


                                                                      

                       

                    
                                                                              


                                            
                                                                              


                                                           




                                  
                     

                                            
 

                                   






                                                                        





                                                                    






                                                                          
                                                                             


                                                                          

                                             
                                  


                                             
                  
                                             
         

                       



                                                                        







                                                                        
                                                    
                     
                                                  

                     

                                                                                                                                          

                     

                                                                                                                                        




                                                                 
 
                      
                                                                
                                   
 
                  
 
                                              
                                              
                    
                        
              
                             



                             
                                                                
                     
 
                                                                                                                                                                                                                                                                                                                            

                                

                                      


                                                                     
                                             





                                         
                                               

                                              

                                  
                               
                                               

                                                   

                              

             
                                       
                   
                         
                                                          
                   
                             
                                                              
                                
                                                          
                             
                                
                                                                                  

                             
                                                              
                                
                                                          
                             
         
                             
                      
                                                                          
                                      

                                                
                          


                           







                                                                          
                        
                                       

                                               
             
                               
                  










                                                            
                         









                                                        
         


                                     
                                  
                                               



                                                       
                                    

                                  
                               
                                               
                                           




                                                   
                                
                                                    


                                         
                                      
                                                
                                         

                                       
                                                   


                                           



                                                      
                                                                      
                                     

                                      
                                   
                                                   





                                   
                                                                    





                                     




















                                                                      

                         
                            
                        
                                                       

                                   
                                      


                                              
                                       
                         

                          
                                                                
                                   

                                          
                                       
                                                       
                          
                                        



                             
                                

                     
                       
                                          


                             

                            
                        

                                  
                                       
                         
                                                       

                                              
                                                  
                                     
                                                                           
                          


                                                               

                                          
                                       
                                                       

                                        

                          
                                               

                           
                                



                 
 
             




                                                                             





                                           


             
/* $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%d%c", i + 1, bw_chess[i % 2],
        'A' + ptr->x, ptr->y + 1, (i % 2) ? '\n' : '\t');
    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),
        ANSI_COLOR(37;41) "棋譜" ANSI_RESET " %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.username); 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.username); 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;
}