zoukankan      html  css  js  c++  java
  • 局域网象棋游戏(C++实现,使用Socket,界面使用Win32,CodeBlocks+GCC编译)

     目录

      成果

        运行效果图

      过程

        1. 首先的问题是下棋的两端应该是什么样的?

        2. 接下来的问题是怎么表示,怎么存储?

        3. 然后应该怎么通信呢?

      代码

        main.cpp

        chinese_chess.h

        Server.h

        Client.h

        END


     

    成果

    运行效果图

      左边是在虚拟机里运行的,右边是在Host机上运行的。

    最新更改后的界面:

     

    过程

      记不起自己为什么要写这个象棋游戏的,大概是因为刚学了点儿Socket ,所以想用用,于是就写个局域网对战的象棋吧。。。

    1. 首先的问题是下棋的两端应该是什么样的?

      我希望下棋的两个人使用相同的程序。所以就不能像FTP一样,一个客户端,一个服务器端,而只能每个程序都是一样的,既是客户端(Client),又是服务器端(Server)。在通信时,己方的Client 向对方的Server 发送信息,对方的Client 向己方的Server 发送信息。两端都存储棋盘信息,通过通信保持棋盘信息的一致。

      然后呢,应该是一端点击界面移子之后,应该能通知对方进行相同的移动。

      综合以上两点,运行过程应该是这样的:

      当在界面上点击棋子时,先判断当前是否轮到自己落子,如果是,则进行移动,更新界面,并通过Client 向对方Server 发送移动信息。对方Server 收到后,进行同样的移动,更新界面。

      这里要求Server能随时接到对方发来的消息,所以Server的监听应该是一个额外的线程。

    2. 接下来的问题是怎么表示,怎么存储?

      棋盘,应该用二维数组存储比较好,数组坐标(以下所说的"数组坐标 "是指该二维数组中的一个(x,y)数对)对应棋盘坐标。那么数组里存储什么呢,一共有車、马、象、士、将、砲、卒七种棋子,那么设置一个棋子类作为基类,然后设置七个类继承棋子类?基类有一个move函数,每个子类重写该函数?但是移动似乎只是我程序的一小部分,这样似乎没必要。

      那么存储整型数值?不同的数值代表不同的棋子?似乎可以。

      那么就用7个数代替七种棋子,但是棋子有黑白色,要用一个数表示棋子类型(即是車、马或其他)和棋子颜色两个信息,那就用BLANK =8代表空子,黑方的車、马、象、士、将、砲、卒分别为1到7,白方的車、马、相、士、帅、炮、兵分别为9到15。

      这样判断某数组坐标上棋子的颜色,就把其值与BLANK 比较,大于BLANK为白色,否则为黑色。

      判断某数组坐标上棋子的类型,则将其值模BLANK 

      另外,因为下棋双方的视角是相反的,所以,棋盘在存储时应该是相反的,移动时的坐标也应该进行转换。

    3. 然后应该怎么通信呢?

      我希望这个程序打开后,就能找到对方,并确定谁是黑色,谁是白色。

      也许可以让Client 在运行之后就对局域网进行端口扫描,然后给出正在运行此程序的IP 地址列表,让用户选择要连接到哪个,如果对方已经有了连接,则对方会拒绝此连接,如果对方没有连接,则对方程序会向对方用户提示该连接请求,如果,对方用户同意,则连接建立,否则依然是拒绝此连接。

      但是,我没有采用以上所述方法(因为太复杂,我还是先做好主体工作吧=_=)。

      所以在程序开始运行后,会让用户输入对方的IP 地址,然后Server 开始监听。之后Client 开始向对方发出连接请求。

      Server 监听时,如果收到连接请求,就看对方的IP 地址是否是用户输入的IP 地址,如果不是,说明连接请求不是用户所希望的对方发送的,那就继续监听。

      Client 请求连接时,如果对方同意了,就要开始确定自己的颜色了。

      确定颜色这里困扰了我很久,最后采用的解决方法是这样的:

        核心思想就是谁先发出连接请求,谁就是黑色。

        也就是在Client 连接上对方之后,要判断Server 是不是已经连接了对方,如果Server 已连接,就说明是对方先发出的连接请求,那么对方就是黑色,自己就设为白色。如果Server 没有连接,就说明自己先连接上了对方,也就是自己是黑色。

      以上就是编码前及编码时的大致想法。

     

    代码

    注: 用 CodeBlocks 编译时若出现类似" undefined reference to `send@16' " 的错误,在Settings->Complier->Global Complier Settings->Linker Settings 中添加 C:\Program Files (x86)\CodeBlocks\MinGW\lib\libwsock32.a

    main.cpp

      1 #if defined(UNICODE) && !defined(_UNICODE)
      2 #define _UNICODE
      3 #elif defined(_UNICODE) && !defined(UNICODE)
      4 #define UNICODE
      5 #endif
      6 
      7 #include <tchar.h>
      8 #include <windows.h>
      9 #include <pthread.h>
     10 #include <windowsx.h>
     11 #include "chinese_chess.h"
     12 #include "Server.h"
     13 #include "Client.h"
     14 
     15 
     16 #define WIDTH 600       //界面宽度
     17 #define HEIGHT 600      //界面高度
     18 #define ZERO_X 70       //棋盘左边界
     19 #define ZERO_Y 70       //棋盘上边界
     20 #define PIECE_BKCOLOR    RGB(195,163,109)   //棋子背景色
     21 #define PIECE_WH 45        //棋盘每个格子的宽度和高度
     22 
     23 HWND hwnd;               /* This is the handle for our window */
     24 char* ots_ip;           //存储对方IP地址的字符串
     25 int port;
     26 bool is_connect_alive=false;        //是否连接到对方
     27 Board * chess_board;          //棋盘
     28 Server *server;
     29 Client *client;
     30 int chess_sx=-1;        //移动起始位置的数组坐标
     31 int chess_sy=-1;
     32 int chess_dx=-1;        //移动目标位置的数组坐标
     33 int chess_dy=-1;
     34 
     35 
     36 
     37 
     38 /*  Declare Windows procedure  */
     39 LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);
     40 
     41 /*  Make the class name into a global variable  */
     42 TCHAR szClassName[ ] = _T("Chinese Chess");
     43 
     44 int WINAPI WinMain (HINSTANCE hThisInstance,
     45                     HINSTANCE hPrevInstance,
     46                     LPSTR lpszArgument,
     47                     int nCmdShow) {
     48     MSG messages;            /* Here messages to the application are saved */
     49     WNDCLASSEX wincl;        /* Data structure for the windowclass */
     50 
     51     /* The Window structure */
     52     wincl.hInstance = hThisInstance;
     53     wincl.lpszClassName = szClassName;
     54     wincl.lpfnWndProc = WindowProcedure;      /* This function is called by windows */
     55     wincl.style = CS_DBLCLKS;                 /* Catch double-clicks */
     56     wincl.cbSize = sizeof (WNDCLASSEX);
     57 
     58     /* Use default icon and mouse-pointer */
     59     wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
     60     wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
     61     wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
     62     wincl.lpszMenuName = NULL;                 /* No menu */
     63     wincl.cbClsExtra = 0;                      /* No extra bytes after the window class */
     64     wincl.cbWndExtra = 0;                      /* structure or the window instance */
     65     /* Use Windows's default colour as the background of the window */
     66     wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND;
     67 
     68     /* Register the window class, and if it fails quit the program */
     69     if (!RegisterClassEx (&wincl))
     70         return 0;
     71 
     72     /* The class is registered, let's create the program*/
     73     hwnd = CreateWindowEx (
     74                0,                   /* Extended possibilites for variation */
     75                szClassName,         /* Classname */
     76                _T("Chinese Chess"),       /* Title Text */
     77                WS_OVERLAPPEDWINDOW, /* default window */
     78                CW_USEDEFAULT,       /* Windows decides the position */
     79                CW_USEDEFAULT,       /* where the window ends up on the screen */
     80                WIDTH,                 /* The programs width */
     81                HEIGHT,                 /* and height in pixels */
     82                HWND_DESKTOP,        /* The window is a child-window to desktop */
     83                NULL,                /* No menu */
     84                hThisInstance,       /* Program Instance handler */
     85                NULL                 /* No Window Creation data */
     86            );
     87 
     88     /* Make the window visible on the screen */
     89     ShowWindow (hwnd, nCmdShow);
     90 
     91     /* Run the message loop. It will run until GetMessage() returns 0 */
     92     while (GetMessage (&messages, NULL, 0, 0)) {
     93         /* Translate virtual-key messages into character messages */
     94         TranslateMessage(&messages);
     95         /* Send message to WindowProcedure */
     96         DispatchMessage(&messages);
     97     }
     98 
     99     /* The program return-value is 0 - The value that PostQuitMessage() gave */
    100     return messages.wParam;
    101 }
    102 //把数组坐标转换为界面坐标
    103 void xy_to_pixel(int x,int y,int*pixelx,int *pixely) {
    104     *pixely=x*PIECE_WH+ZERO_Y;
    105     *pixelx=y*PIECE_WH+ZERO_X;
    106 }
    107 //把界面坐标转换为数组坐标
    108 void pixel_to_xy(int pixelx,int pixely,int*x,int *y) {
    109     int r=PIECE_WH/2;
    110     *y=(pixelx-(ZERO_X-r))/PIECE_WH;
    111     *x=(pixely-(ZERO_Y-r))/PIECE_WH;
    112 }
    113 //以数组坐标画线
    114 void draw_line(HDC hdc,int sx,int sy,int dx,int dy) {
    115     int psx,psy,pdx,pdy;
    116     xy_to_pixel(sx,sy,&psx,&psy);
    117     xy_to_pixel(dx,dy,&pdx,&pdy);
    118     MoveToEx (hdc, psx,psy, NULL) ;
    119     LineTo (hdc, pdx, pdy) ;
    120 }
    121 //以数组坐标画棋子
    122 void paint_piece(HDC hdc,int x,int y,int color,int type) {
    123     static HBRUSH  piece_brush =CreateSolidBrush (PIECE_BKCOLOR);    //棋子的背景色
    124     if(type==0||color==BLANK)return ;
    125     int px,py;
    126     xy_to_pixel(x,y,&px,&py);
    127     int r=PIECE_WH/2;
    128     SelectObject (hdc,piece_brush ) ;
    129     SelectObject (hdc, GetStockObject (NULL_PEN)) ;
    130     Ellipse(hdc,px-r,py-r,px+r,py+r);
    131     char *text=new char[5];
    132     switch(type) {
    133     case JU:
    134         strcpy(text,"");
    135         break;
    136     case MA:
    137         strcpy(text,"");
    138         break;
    139     case XIANG:
    140         if(color==BLACK)strcpy(text,"");
    141         else strcpy(text,"");
    142         break;
    143     case SHI:
    144         strcpy(text,"");
    145         break;
    146     case JIANG:
    147         if(color==BLACK)strcpy(text,"");
    148         else strcpy(text,"");
    149         break;
    150     case PAO:
    151         if(color==BLACK)strcpy(text,"");
    152         else
    153             strcpy(text,"");
    154         break;
    155     case ZU:
    156         if(color==BLACK)strcpy(text,"");
    157         else
    158             strcpy(text,"");
    159         break;
    160     default:
    161         strcpy(text,"");
    162     }
    163     SetBkColor(hdc,PIECE_BKCOLOR);//设置文字背景色
    164     if(color==BLACK) {
    165         SetTextColor(hdc,RGB(0,0,0));       //设置文字颜色
    166     } else {
    167         SetTextColor(hdc,RGB(255,255,255));
    168     }
    169     TextOut (hdc, px-r/2, py-r/2,text , strlen("")) ;
    170     delete text;
    171 }
    172 
    173 void* main_listen(void *) {
    174     server->listen_message();
    175     return 0;
    176 }
    177 //创建线程,使server开始监听
    178 bool  start_listen() {
    179     pthread_t listen_p;
    180     int ret;
    181     ret= pthread_create( &listen_p,  NULL, main_listen,NULL ); //
    182     if( ret != 0 ) { //创建线程成功返回0
    183         //printf("pthread_create error:error_code=%d\n",ret );
    184         handle_error(THREAD_ERROR,true,true);
    185         return false;
    186     }
    187     return true;
    188 }
    189 
    190 
    191 void* chess_connect(void *) {
    192     client->connect_to_ots();  //client开始连接对方server,连接成功后返回
    193     InvalidateRect(hwnd,NULL,true);
    194 }
    195 
    196 void init() {
    197     server=new Server();//创建Server对象
    198     client=new Client(); //创建Client对象,
    199     start_listen();             //创建线程,server开始监听
    200     Sleep(1000);
    201     pthread_t connect_p;
    202     int ret;
    203     ret= pthread_create( &connect_p,  NULL, chess_connect,NULL); //
    204     if( ret != 0 ) { //创建线程成功返回0
    205         //printf("pthread_create error:error_code=%d\n",ret );
    206         handle_error(THREAD_ERROR,true,true);
    207         return ;
    208     }
    209 }
    210 
    211 
    212 
    213 /*  This function is called by the Windows function DispatchMessage()  */
    214 
    215 LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
    216     static POINT mouse;
    217     static HDC hdc;
    218     static PAINTSTRUCT ps ;
    219     static int iofip=0;     //index of ots_ip
    220     switch (message) {                /* handle the messages */
    221     case WM_CREATE: {
    222         port=35536;
    223         ots_ip=new char[20];
    224         strcpy(ots_ip,"");
    225     }
    226     break;
    227     case WM_KEYDOWN://识别按键,显示输入的内容(对方IP地址)
    228         if(server!=NULL)break;
    229         if(wParam==13) {//如果是ENTER,则初始化server、client,并开始连接,连接成功后初始化board
    230             init();
    231             Sleep(100);
    232             InvalidateRect(hwnd,NULL,true);
    233         }
    234         if(wParam==VK_BACK) {//删除键
    235             if(iofip==0)return 0;
    236             iofip--;
    237             ots_ip[iofip]='\0';
    238         }
    239         if(wParam<106&&wParam>95) {//小键盘数字键
    240             wParam-=48;
    241         }
    242         if(wParam<58&&wParam>47) {//主键盘数字键
    243             ots_ip[iofip]='0'-48+wParam;
    244             iofip++;
    245             ots_ip[iofip]='\0';
    246         }
    247         if(wParam==110||wParam==229) {//小数点键,小键盘110,主键盘229
    248             ots_ip[iofip]='.';
    249             iofip++;
    250             ots_ip[iofip]='\0';
    251         }
    252         InvalidateRect(hwnd,NULL,true);
    253         break;
    254     case WM_PAINT: {
    255         static HBRUSH  bk_brush =CreateSolidBrush (RGB(240,240,240));    //棋子的背景色
    256         hdc=BeginPaint (hwnd,&ps) ;
    257         static HFONT hFont;
    258         LOGFONT lf;
    259         lf.lfHeight=PIECE_WH/2;
    260         lf.lfWidth=0;
    261         lf.lfEscapement=0;
    262         lf.lfOrientation=0 ;
    263         lf.lfWeight=5;
    264         lf.lfItalic=0 ;
    265         lf.lfUnderline=0 ;
    266         lf.lfStrikeOut=0 ;
    267         lf.lfCharSet=DEFAULT_CHARSET ;
    268         lf.lfOutPrecision=0 ;
    269         lf.lfClipPrecision=0 ;
    270         lf.lfQuality=0 ;
    271         lf.lfPitchAndFamily=0 ;
    272         lstrcpy (lf.lfFaceName, _T("楷体") );
    273         hFont = CreateFontIndirect (&lf) ;
    274         SelectFont(hdc,hFont);
    275         SelectObject(hdc,bk_brush);
    276         Rectangle(hdc,0,0,WIDTH,HEIGHT);
    277         SetBkColor(hdc,RGB(240,240,240));
    278         if(chess_board==NULL) {//显示输入的IP地址
    279             char tip[20]="请输入对方IP地址:";
    280             Rectangle(hdc,WIDTH/5,HEIGHT/2-10,WIDTH/5*4,HEIGHT/2+30);
    281             TextOut(hdc,WIDTH/5,HEIGHT/2-50,tip,strlen(tip));
    282             SetBkColor(hdc,RGB(240,240,240));
    283             TextOut(hdc,WIDTH/5+5,HEIGHT/2,ots_ip,strlen(ots_ip));
    284             if(server!=NULL) {             //board==NULL而server!=NULL表示正在连接过程中
    285                 char tip[20]="正在连接......";
    286                 SetBkColor(hdc,RGB(240,240,240));
    287                 TextOut(hdc,WIDTH/5,HEIGHT/2+50,tip,strlen(tip));
    288             }
    289             EndPaint(hwnd,&ps);
    290             break;
    291         }
    292         char text[10]="你的颜色:";
    293         if(chess_board->get_color()==BLACK) {
    294             strcat(text,"");
    295         } else {
    296             strcat(text,"");
    297         }
    298         TextOut (hdc, 5, 5,text , strlen(text)) ;
    299         int M=chess_board->get_M();
    300         int N=chess_board->get_N();
    301         //画棋盘
    302         for(int i=0; i<M; i++) {
    303             draw_line(hdc,i,0,i,N-1);
    304         }
    305         for(int i=0; i<N; i++) {
    306             draw_line(hdc,0,i,N/2,i);
    307         }
    308         for(int i=0; i<N; i++) {
    309             draw_line(hdc,N/2+1,i,N,i);
    310         }
    311         draw_line(hdc,0,3,2,5);
    312         draw_line(hdc,0,5,2,3);
    313         draw_line(hdc,9,3,7,5);
    314         draw_line(hdc,7,3,9,5);
    315         draw_line(hdc,4,0,5,0);
    316         draw_line(hdc,4,8,5,8);
    317         //画棋子
    318         for(int i=0; i<M; i++) {
    319             for(int j=0; j<N; j++) {
    320                 paint_piece(hdc,i,j,chess_board->get_color(i,j),chess_board->get_type(i,j));
    321             }
    322         }
    323         EndPaint(hwnd,&ps);
    324     }
    325     break;
    326     case WM_LBUTTONUP: {
    327         if(chess_board==NULL)break;
    328         if(!chess_board->is_my_turn())break;//当前没轮到自己下棋
    329         GetCursorPos(&mouse);//获取鼠标的屏幕坐标
    330         ScreenToClient(hwnd,&mouse);//转换为界面坐标
    331         int x,y;
    332         pixel_to_xy(mouse.x,mouse.y,&x,&y);//转换为数组坐标
    333         if(chess_board->get_color(x,y)==chess_board->get_color()) {//点击的是自己的棋子
    334             chess_sx=x;
    335             chess_sy=y;
    336             break;
    337         }
    338         if(chess_sx==-1||chess_sy==-1) {//起始坐标未赋值且点击的不是自己的棋子,则break
    339             break;
    340         }
    341         chess_dx=x;
    342         chess_dy=y;
    343         if(chess_board->my_move_piece(chess_sx,chess_sy,chess_dx,chess_dy)) { //如果移动棋子合法
    344             client->send_message("move",chess_sx,chess_sy,chess_dx,chess_dy);   //向对方发送移子信息
    345             InvalidateRect(hwnd,NULL,true);
    346             if(chess_board->get_is_win()==WIN) {
    347                 chess_board->init();//重新初始化棋盘,重下一盘
    348                 MessageBox(hwnd,"你赢了","获胜!",NULL);
    349                 InvalidateRect(hwnd,NULL,true);
    350             }
    351         }
    352         chess_sx=-1;
    353         chess_sy=-1;
    354         break;
    355     }
    356     case WM_DESTROY:
    357         if(server!=NULL)server->close();
    358         if(client!=NULL)client->close();
    359         PostQuitMessage (0);       /* send a WM_QUIT to the message queue */
    360         break;
    361     default:                      /* for messages that we don't deal with */
    362         return DefWindowProc (hwnd, message, wParam, lParam);
    363     }
    364 
    365     return 0;
    366 }

    chinese_chess.h

      1 #ifndef CHINESE_CHESS_H_INCLUDED
      2 #define CHINESE_CHESS_H_INCLUDED
      3 
      4 #define JU 1
      5 #define MA 2
      6 #define XIANG 3
      7 #define SHI 4
      8 #define JIANG 5
      9 #define PAO 6
     10 #define ZU 7
     11 #define BLANK 8 //空子
     12 
     13 #define BLACK -1
     14 #define WHITE 1
     15 
     16 #define WIN 1
     17 #define LOSE -1
     18 class Board {
     19 private:
     20     bool turn;   //是否轮到自己下棋
     21     int color;  //自己的颜色
     22     int M,N;        //棋盘行数、列数
     23     int **b;    //二维数组
     24     int is_win;     //是否胜利
     25 
     26     bool is_out(int x,int y) {//坐标是否出界
     27         return x>M||y>N||x<0||y<0;
     28     }
     29 
     30     bool is_same_color(int sx,int sy,int dx,int dy) {//源坐标与目的坐标是否是同一颜色
     31         return get_color(sx,sy)==get_color(dx,dy);
     32     }
     33     void swap_num(int & num1,int& num2) {//交换两个数
     34         num1+=num2;
     35         num2=num1-num2;
     36         num1=num1-num2;
     37     }
     38     int get_abs(int num) {//取得绝对值
     39         return num>=0?num:-num;
     40     }
     41     int num_of_not_blank_betweenn(int sx,int sy,int dx,int dy) {//返回在起始坐标和目的坐标之间棋子的个数
     42         if(!(sx==dx||sy==dy))return -1;
     43         int num=0;
     44         if(sy>dy)swap_num(sy,dy);
     45         if(sx>dx)swap_num(sx,dx);
     46         if(sx==dx) {
     47             for(int i=sy+1; i<dy; i++) {
     48                 if(b[sx][i]!=BLANK)num++;
     49             }
     50         }
     51         if(sy==dy) {
     52             for(int i=sx+1; i<dx; i++) {
     53                 if(b[i][sy]!=BLANK)num++;
     54             }
     55         }
     56         return num;
     57     }
     58     bool is_correct_move_JU(int sx,int sy,int dx,int dy) {
     59         return num_of_not_blank_betweenn(sx,sy,dx,dy)==0;
     60     }
     61     bool is_correct_move_MA(int sx,int sy,int dx,int dy) {
     62         int x=dx-sx,y=dy-sy;
     63         if(get_abs(x)==2&&get_abs(y)==1) {
     64             if(get_color(sx+x/2,sy)==BLANK)return true;//硌马蹄检测
     65         }
     66         if(get_abs(x)==1&&get_abs(y)==2) {
     67             if(get_color(sx,sy+y/2)==BLANK)return true;//硌马蹄检测
     68         }
     69         return false;
     70     }
     71     bool is_correct_move_XIANG(int sx,int sy,int dx,int dy) {
     72         int x=dx-sx,y=dy-sy;
     73         if(!(get_abs(x)==2&&get_abs(y)==2)) return false;
     74         if(get_color(sx+x/2,sy+y/2)==BLANK)return true;//硌象蹄检测
     75         return false;
     76     }
     77     bool is_correct_move_SHI(int sx,int sy,int dx,int dy) {
     78         int x=dx-sx,y=dy-sy;
     79         if(!(get_abs(x)==1&&get_abs(y)==1)) return false;
     80         if(dx<7)return false;
     81         if(dy<3||dy>5)return false;
     82         return true;
     83     }
     84     bool is_correct_move_JIANG(int sx,int sy,int dx,int dy) {
     85         int x=dx-sx,y=dy-sy;
     86         if(!((get_abs(x)==1&&get_abs(y)==0)||(get_abs(x)==0&&get_abs(y)==1))) return false;
     87         if(dx<7)return false;
     88         if(dy<3||dy>5)return false;
     89         for(int i=0; i<3; i++) {//明将检测
     90             if(get_type(i,dy)==JIANG) {
     91                 if(num_of_not_blank_betweenn(dx,dy,i,dy)==0) return false;
     92                 return true;
     93             }
     94         }
     95         return true;
     96     }
     97     bool is_correct_move_PAO(int sx,int sy,int dx,int dy) {
     98         int n=get_color(dx,dy)==BLANK?0:1;
     99         return num_of_not_blank_betweenn(sx,sy,dx,dy)==n;
    100     }
    101     bool is_correct_move_ZU(int sx,int sy,int dx,int dy) {
    102         if(dx>sx)return false;
    103         int x=dx-sx,y=dy-sy;
    104         if(get_abs(x)+get_abs(y)!=1)return false;
    105         if(sx>4&&get_abs(x)!=1)return false;//过河前只能向前走
    106         return true;
    107     }
    108 
    109     bool is_correct_move(int sx,int sy,int dx,int dy) {
    110         if(sx==dx&&sy==dy) {
    111             return false;
    112         }
    113         if(is_out(sx,sy)||is_out(dx,dy)) {
    114             return false;
    115         }
    116         if(get_color(sx,sy)!=color) {
    117             return false;
    118         }
    119         if(is_same_color(sx,sy,dx,dy)) {
    120             return false;
    121         }
    122         switch(get_type(sx,sy)) {
    123         case JU:
    124             return is_correct_move_JU(sx,sy,dx,dy);
    125         case MA:
    126             return is_correct_move_MA(sx,sy,dx,dy);
    127         case XIANG:
    128             return is_correct_move_XIANG(sx,sy,dx,dy);
    129         case SHI:
    130             return is_correct_move_SHI(sx,sy,dx,dy);
    131         case JIANG:
    132             return is_correct_move_JIANG(sx,sy,dx,dy);
    133         case PAO:
    134             return is_correct_move_PAO(sx,sy,dx,dy);
    135         case ZU:
    136             return is_correct_move_ZU(sx,sy,dx,dy);
    137         default:
    138             return false;
    139         }
    140     }
    141 
    142     void move_s_to_d(int sx,int sy,int dx,int dy) { //移动操作
    143         if(get_type(dx,dy)==JIANG) {    //如果目的棋子是将
    144             if(get_color(dx,dy)==color)set_win(LOSE);//如果是自己的将,则输
    145             else set_win(WIN);//如果是对方的将,则赢
    146         }
    147         b[dx][dy]=b[sx][sy];
    148         b[sx][sy]=BLANK;
    149         change_turn();
    150     }
    151 
    152     void init_pieces() {
    153         for(int i=0; i<M; i+=M-1) {//第一行和最后一行(即车马象士将士象马车)
    154             for(int index=0; index<N; index++) {
    155                 if(index<N/2+1)b[i][index]=index+1;
    156                 else b[i][index]=N-index;
    157             }
    158         }
    159         //卒所在的行
    160         for(int index=0; index<N; index+=2) {
    161             b[3][index]=ZU;
    162         }
    163         for(int index=0; index<N; index+=2) {
    164             b[6][index]=ZU;
    165         }
    166         b[2][1]=PAO;
    167         b[M-1-2][1]=PAO;
    168         b[2][N-1-1]=PAO;
    169         b[M-1-2][N-1-1]=PAO;
    170         int s,d;//存储起始行和终点行
    171         if(color==BLACK) {
    172             s=0;//从0行到M/2行,即棋盘上半部分
    173             d=M/2;
    174         } else {
    175             s=M/2;//棋盘下半部分
    176             d=M;
    177         }
    178         //从s行到d行,把非BLANK的值加BLANK,使小于BLANK的代表黑色棋,大于BLANK的代表白色棋
    179         for(int index=s; index<d; index++) {
    180             for(int j=0; j<N; j++) {
    181                 if(b[index][j]!=BLANK) {
    182                     b[index][j]+=BLANK;
    183                 }
    184             }
    185         }
    186     }
    187 
    188 public:
    189     Board(int c) {
    190         color=c;
    191         M=10;
    192         N=9;
    193         b=new int*[M];
    194         for(int i=0; i<M; i++) {
    195             b[i]=new int[N];
    196         }
    197         init();
    198     }
    199     void init() {//棋盘初始化
    200         is_win=0;
    201         turn=color==BLACK?true:false;
    202         for(int i=0; i<M; i++) {
    203             for(int j=0; j<N; j++) {
    204                 b[i][j]=BLANK;
    205             }
    206         }
    207         init_pieces();
    208     }
    209     int get_M() {
    210         return M;
    211     }
    212     int get_N() {
    213         return N;
    214     }
    215     int get_color() {//获取己方的颜色
    216         return color;
    217     }
    218     int get_color(int x,int y) {//获取棋盘某一坐标上棋子的颜色
    219         return b[x][y]>BLANK?WHITE:b[x][y]<BLANK?BLACK:BLANK;
    220     }
    221     int get_type(int x,int y) {//获取棋子类型(空、车、马、象、士、将、炮、卒)
    222         return b[x][y]!=BLANK?b[x][y]%BLANK:BLANK;
    223     }
    224     void set_win(int is) {
    225         is_win=is;
    226     }
    227     int get_is_win() {
    228         return is_win;
    229     }
    230     void change_turn() {
    231         turn=turn==true?false:true;
    232     }
    233     bool is_my_turn() {
    234         return turn;
    235     }
    236     void othside_move_piece(int sx,int sy,int dx,int dy) {//对方移子
    237         sx=M-1-sx;//先进行坐标转换,因对方视角与己方相反
    238         sy=N-1-sy;
    239         dx=M-1-dx;
    240         dy=N-1-dy;
    241         move_s_to_d(sx,sy,dx,dy);
    242     }
    243     bool my_move_piece(int sx,int sy,int dx,int dy) {       //己方主动移子
    244         if(!is_correct_move(sx,sy,dx,dy))return false;
    245         move_s_to_d(sx,sy,dx,dy);
    246         return true;
    247     }
    248 };
    249 
    250 #endif // CHINESE_CHESS_H_INCLUDED

    Server.h

      1 #ifndef SERVER_H_INCLUDED
      2 #define SERVER_H_INCLUDED
      3 #include<stdio.h>
      4 #include <stdlib.h>
      5 #include <errno.h>
      6 #include <winsock2.h>
      7 #include"chinese_chess.h"
      8 
      9 #define INIT_ERROR 1
     10 #define BIND_ERROR 2
     11 #define LISTEN_ERROR 3
     12 #define CONNECT_ERROR 4
     13 #define SEND_ERROR 5
     14 #define ACCEPT_ERROR 6
     15 #define ALIVE_ERROR 7
     16 #define THREAD_ERROR 8
     17 int error_num;
     18 extern HWND hwnd;
     19 extern Board* chess_board;
     20 extern char* ots_ip;
     21 extern int port;
     22 extern bool is_connect_alive;
     23 
     24 //线程参数结构体
     25 typedef struct server_args {
     26     SOCKET* Com_Sock;
     27     char * rebuf;
     28 } server_args;
     29 //校验检测,与客户端的添加校验是相反操作
     30 //最后一位之前的所有字符相加取模后,如果等于最后一个字符,则校验通过
     31 bool server_check(char * r) {
     32     int len=strlen(r);
     33     len--;
     34     int s=0;
     35     for(int i=0; i<len; i++) {
     36         s+=r[i];
     37     }
     38     if(r[len]==(s%5+'0')) {
     39         r[len]='\0';
     40         return true;
     41     }
     42     return false;
     43 }
     44 //错误处理,is_tell控制是否显示错误信息,is_exit控制是否退出程序
     45 int handle_error(int err,bool is_tell,bool is_exit) {
     46     error_num=err;
     47     if(!is_tell)return error_num;
     48     char error[30]="";
     49     switch(error_num) {
     50     case INIT_ERROR:
     51         strcpy(error,"初始化错误");
     52         break;
     53     case BIND_ERROR:
     54         strcpy(error,"绑定端口错误");
     55         break;
     56     case LISTEN_ERROR:
     57         strcpy(error,"监听错误");
     58         break;
     59     case ACCEPT_ERROR:
     60         strcpy(error,"接受连接错误");
     61         break;
     62     case CONNECT_ERROR:
     63         strcpy(error,"无法连接");
     64         break;
     65     case ALIVE_ERROR:
     66         strcpy(error,"连接已断开");
     67         break;
     68     case THREAD_ERROR:
     69         strcpy(error,"线程无法创建");
     70         break;
     71     case SEND_ERROR:
     72         strcpy(error,"发送错误");
     73     }
     74     char error_message[50];
     75     strcpy(error_message,"错误:");
     76     strcat(error_message,error);
     77     if(is_exit)strcat(error_message,"\n程序将退出。");
     78     MessageBox(hwnd,error_message,"错误",MB_OK);
     79     if(is_exit)exit(0);
     80     return error_num;
     81 }
     82 void* handle_message(void*ar) {
     83     server_args * serarg=(server_args * )ar;
     84     char *recv=serarg->rebuf;
     85     SOCKET* CommandSock=serarg->Com_Sock;
     86     if(server_check(recv)) {//校验通过发送okok(OK),不通过发送noto(NOTOK)
     87         send(*CommandSock,"okok",4,0);
     88     } else {
     89         send(*CommandSock,"noto",4,0);
     90         return ar;
     91     }
     92     if(strncmp(recv,"move",4)==0) {
     93         char * pch;
     94         //将recvBuf以逗号拆分
     95         pch = strtok (recv,",");
     96         pch = strtok (NULL,",");
     97         int xys[4];
     98         int index=0;
     99         while (pch != NULL) {
    100             xys[index]=atoi(pch);//char* 转换为int
    101             index++;
    102             pch = strtok (NULL, ",");
    103         }
    104         chess_board->othside_move_piece(xys[0],xys[1],xys[2],xys[3]);
    105         if(chess_board->get_is_win()==LOSE) {
    106             chess_board->init();//如果输了,则重新初始化棋盘,再下一盘
    107             MessageBox(hwnd,"你输了","失败!",NULL);
    108         }
    109         InvalidateRect(hwnd,NULL,true);
    110     }
    111     delete recv;
    112 }
    113 class Server {
    114 private:
    115     SOCKET Server_Sock;
    116     SOCKADDR_IN server_addr;
    117     SOCKADDR_IN client_addr;
    118     char recvBuf[20];
    119 
    120 public:
    121     Server() {
    122         WSADATA wsa;
    123         /*初始化socket资源*/
    124         if (WSAStartup(MAKEWORD(1,1),&wsa) != 0) {
    125             handle_error(INIT_ERROR,true,true);
    126             return;
    127         }
    128 
    129         if((Server_Sock = socket(AF_INET, SOCK_STREAM, 0))==-1) {
    130             handle_error(INIT_ERROR,true,true);
    131             return;
    132         }
    133         ZeroMemory((char *)&server_addr,sizeof(server_addr));
    134         server_addr.sin_family = AF_INET;
    135         server_addr.sin_port = htons(port);           /*本地监听端口*/
    136         server_addr.sin_addr.s_addr = htonl(INADDR_ANY); /*有IP*/
    137 
    138         if(bind(Server_Sock,(struct sockaddr *)&server_addr,sizeof(server_addr))==-1) {
    139             handle_error(BIND_ERROR,true,true);
    140             return;
    141         }
    142         if(listen(Server_Sock,5)==-1) { //其中第二个参数代表能够接收的最多的连接数
    143             handle_error(LISTEN_ERROR,true,true);
    144             return;
    145         }
    146         strcpy(recvBuf,"");
    147     }
    148 
    149     void listen_message() {
    150         int len=sizeof(SOCKADDR);
    151         while(true) {
    152             SOCKET Command_Sock  = accept(Server_Sock, (SOCKADDR*)&client_addr,&len);
    153             if(Command_Sock == INVALID_SOCKET) {
    154                 closesocket(Command_Sock);
    155                 handle_error(ACCEPT_ERROR,false,false);
    156                 continue;
    157             }
    158             if(client_addr.sin_addr.s_addr!=inet_addr(ots_ip)) {//如果接收的socket不是预期的对方的,则发送wron,继续等待
    159                 send(Command_Sock,"wron",4,0);
    160                 closesocket(Command_Sock);
    161                 continue;
    162             }
    163             send(Command_Sock,"righ",4,0);
    164             is_connect_alive=true;
    165             while(true) {
    166                 if(recv(Command_Sock,recvBuf,20,0)<=0) {//recv返回小于等于0的值,则连接已断开
    167                     handle_error(ALIVE_ERROR,true,true);
    168                     closesocket(Command_Sock);
    169                     close();
    170                     return ;
    171                 }
    172                 char *rbuf=new char[20];
    173                 strcpy(rbuf,recvBuf);
    174                 server_args serarg;
    175                 serarg.Com_Sock=&Command_Sock;
    176                 serarg.rebuf=rbuf;
    177                 pthread_t handle_m;
    178                 int ret;
    179                 ret= pthread_create( &handle_m,  NULL, handle_message,&serarg); //
    180                 if( ret != 0 ) { //创建线程成功返回0
    181                     // printf("pthread_create error:error_code=%d\n",ret );
    182                     handle_error(THREAD_ERROR,true,true);
    183                     return ;
    184                 }
    185                 strcpy(recvBuf,"");
    186             }
    187             closesocket(Command_Sock);
    188         }
    189     }
    190     void close() {
    191         closesocket(Server_Sock);
    192         WSACleanup();
    193     }
    194 };
    195 
    196 
    197 #endif // SERVER_H_INCLUDED

    Client.h

     1 #ifndef CLIENT_H_INCLUDED
     2 #define CLIENT_H_INCLUDED
     3 
     4 #include <stdio.h>
     5 #include <winsock2.h>
     6 
     7 #include"chinese_chess.h"
     8 
     9 //为字符串添加校验信息,对所有字符求和,模5之后转化为字符放在字符串最后
    10 void client_check(char* r) {
    11     int len=strlen(r);
    12     int s=0;
    13     for(int i=0; i<len; i++) {
    14         s+=r[i];
    15     }
    16     r[len]=s%5+'0';
    17     r[len+1]='\0';
    18 }
    19 class Client {
    20 private:
    21     SOCKET Client_Sock;
    22     SOCKADDR_IN server_addr;
    23     char sendBuf[20];
    24 public:
    25     Client() {
    26         WSADATA wsa;
    27         /*初始化socket资源*/
    28         if (WSAStartup(MAKEWORD(1,1),&wsa) != 0) {
    29             handle_error(INIT_ERROR,true,true);
    30             return;   //代表失败
    31         }
    32         if((Client_Sock = socket(AF_INET, SOCK_STREAM, 0))==-1) {
    33             handle_error(INIT_ERROR,true,true);
    34             return;   //代表失败
    35         }
    36         server_addr.sin_addr.S_un.S_addr=inet_addr(ots_ip);
    37         server_addr.sin_family=AF_INET;
    38         server_addr.sin_port=htons(port);
    39         strcpy(sendBuf,"");
    40     }
    41     void connect_to_ots() {
    42         while(connect(Client_Sock,(SOCKADDR*)&server_addr,sizeof(SOCKADDR)) ==-1) {
    43             handle_error(CONNECT_ERROR,false,false);
    44             Sleep(100);
    45             //printf( "%d ", WSAGetLastError());
    46         }
    47         char rec[5];
    48         recv(Client_Sock,rec,4,0);
    49         if(strncmp(rec,"wron",4)==0) {  //收到wrong,说明对方所输入的IP不是己方IP
    50             MessageBox(hwnd,"对方输入的IP不是你\n程序将退出","错误",NULL);
    51             exit(-1);
    52         }
    53         //谁先连接谁是黑色
    54         //如果server已经收到连接,则说明是对方先连接自己,则自己应为白色,否则自己是黑色
    55         if(is_connect_alive) {
    56             chess_board=new Board(WHITE);
    57         } else {
    58             chess_board=new Board(BLACK);
    59         }
    60     }
    61     void close() {
    62         closesocket(Client_Sock);
    63         WSACleanup();
    64     }
    65 
    66     int send_message(char * message) {
    67         strcpy(sendBuf,message);
    68         client_check(sendBuf);
    69         int len;
    70         int try_time=0;
    71         while(true) {
    72             len=send(Client_Sock,sendBuf,strlen(sendBuf)+1,0);
    73             if(len!=(strlen(sendBuf)+1)) {
    74                 handle_error(SEND_ERROR,false,false);
    75                 //printf( "%d ", WSAGetLastError());
    76             }
    77             char rec[5];
    78             recv(Client_Sock,rec,4,0);
    79             if(strncmp(rec,"okok",4)==0) {//收到OK说明数据已经正确被对方收到
    80                 break;
    81             }
    82             if(try_time>20) {   //尝试20次,数据仍无法正确送达,则退出
    83                 handle_error(SEND_ERROR,true,true);
    84             }
    85             try_time++;
    86         }
    87         return len;
    88     }
    89     int send_message(const char * message,int sx,int sy,int dx,int dy) {
    90         char* message_temp=new char[20];
    91         sprintf(message_temp,"%s,%d,%d,%d,%d,",message,sx,sy,dx,dy);
    92         int len=send_message(message_temp);
    93         delete message_temp;
    94         return len;
    95     }
    96 };
    97 
    98 
    99 #endif // CLIENT_H_INCLUDED

     

     

    该程序从2016.3.15晚开始,用了四天的空闲时间。

    END

  • 相关阅读:
    Sum Root to Leaf Numbers深度优先计算路径和
    Path Sum II深度优先找路径
    动态和静态链接库
    C/C++变量
    搜索
    基本格式
    随机数生成函数
    珍惜生命,我用Python 。今天开始学习Python
    在windows里hexo 博客创建步骤
    作为一个程序员,什么是脚本。必须要理解
  • 原文地址:https://www.cnblogs.com/maxuewei2/p/5297263.html
Copyright © 2011-2022 走看看