井字棋Socket编程

  • 服务器端为电脑
  • 客户端为人,可以选择先后手
  • 编程环境为xcode,linux可运行,注意不要using namespac std,std::bind会与bind冲突
  • 通过结构体Move交互,Move的masg字段存储终局信息,客户端根据这一字段是否为空判断是否结束游戏
  • 电脑使用极小值极大值算法,至少平局,输赢局势判断都在服务器端,传状态给客户端
  • 其中AbstractBoard.h 为基类
  • 练手小玩意,其他棋牌可以用这种思想,客户端也可以进行输赢判断。

代码如下:

  1. AbstractBoard.h
//
//  AbstractBoard.h
//  TicTacToeServer
//
//  Created by Tusko on 2017/4/10.
//  Copyright © 2017年 Tusko. All rights reserved.
//

#ifndef AbstractBoard_h
#define AbstractBoard_h

#define EMPTY 0
#define COM -1
#define MAN  1
#define DRAW 0
#define STEP 9
#define ROW 3
#define COL 3
#define BUFFER_SIZE   1024

typedef struct  _Move
{
    int x  ;
    int y  ;
    char mesg[50] ;

    _Move()
    {
        x = -1 ;
        y = -1 ;
        memset(mesg,0,sizeof(mesg));
    }

    _Move(int x,int y)
    {
        this->x = x ;
        this->y = y ;
    }

    void setMessage(int state)
    {
        if(MAN == state)
        {
            memcpy(mesg, "you win!\n", sizeof(mesg));
            std::cout<<"man win"<<std::endl;
        }
        else if(COM == state)
        {
            memcpy(mesg, "computer win!\n", sizeof(mesg));
            std::cout<<"computer"<<std::endl;
        }
        else
        {
            memcpy(mesg, "draw !\n", sizeof(mesg));
            std::cout<<"draw"<<std::endl;
        }

    }

}Move;


class AbstractBoard {

public:

    AbstractBoard():currentDepth(9),step(1),manFirst(false)
    {}

    virtual~AbstractBoard(){}

    int player ;
    int currentDepth  ;
    int step ;
    bool manFirst ;
    int board[3][3] = {0};

    virtual bool manPlay() = 0;
    virtual bool comPlay() = 0;

    void printBoard() {
        int i, j;

        if(player == COM)
        {
            std::cout<<"man plays:"<<std::endl;
        }
        else if(player == MAN)
        {
            std::cout<<"computer plays:"<<std::endl;
        }

        for (i = 0; i < COL; i++)
        {
            printf("-------------\n");
            for (j = 0; j < ROW; j++)
            {
                if (board[i][j] == COM)
                {
                    printf("| X ");
                }
                else if (board[i][j] == MAN)
                {
                    printf("| O ");
                }
                else
                {
                    printf("|   ");
                }

            }
            printf("|\n");
        }
        printf("-------------\n");

    }

    Move recvMove(int &clnt_sock)
    {

        Move result ;
        char buffer[BUFFER_SIZE] = {0} ;


        while (1) {
            if(recv(clnt_sock, buffer, BUFFER_SIZE, 0))
            {
                break ;
            }
        }

        memcpy(&result,buffer,sizeof(Move));

        return result ;
    }

    void sendMove(const Move &m,int &clnt_sock)
    {

        char buffer[BUFFER_SIZE] = {0} ;
        memcpy(buffer,&m,sizeof(Move));
        send(clnt_sock,buffer,sizeof(Move),0);

    }

};

#endif /* AbstractBoard_h */

2.Server

//
//  Board.hpp
//  TicTacToeServer
//
//  Created by Tusko on 2017/4/9.
//  Copyright © 2017年 Tusko. All rights reserved.
//

#ifndef Board_hpp
#define Board_hpp

#include <stdio.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string>
#include "AbstractBoard.h"

#define MAX_NUM 1000;





class TTTServer :public AbstractBoard {


public:
    TTTServer(){
        ServSocket();
    }

    ~TTTServer(){}

    int tempBoard[3][3] = {0};


private:

    int serv_sock ;
    int clnt_sock ;


    Move bestMove ;

    void ServSocket()
    {
        serv_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

        struct sockaddr_in serv_addr ;
        bzero(&serv_addr, sizeof(serv_addr));

        serv_addr.sin_family = AF_INET;

        serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");

        serv_addr.sin_port = htons(6666);


        bind(serv_sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr));

        listen(serv_sock, 20);


        struct sockaddr_in clnt_addr;
        socklen_t clnt_addr_size = sizeof(clnt_addr);
        clnt_sock = accept(serv_sock, (struct sockaddr*)&clnt_addr, &clnt_addr_size);

        char str[] = "connect TTTserver successfully\n";
        write(clnt_sock, str, sizeof(str));


        char buffer[BUFFER_SIZE] = {0};
        read(clnt_sock, buffer, sizeof(buffer) - 1);

        printf("Message form TTTclient: %s\n", buffer);


        setFirst();

        startPlay();

    }

    void startPlay()
    {
        if(manFirst)
        {
            player = MAN;
            while (1) {
                if(!manPlay())
                {
                    break ;
                }
                printBoard();
                if (!comPlay())
                {

                    break ;
                }
                printBoard();
            }
            printBoard();
        }
        else
        {
            player = COM;
            while (1) {

                if(!comPlay())
                {

                    break ;
                }
                printBoard();

                if (!manPlay())
                {

                    break ;
                }
                printBoard();


            }
            printBoard();
        }

        sleep(2);
        disconnect();

    }




    //set who plays first
    void setFirst()
    {
        char buffer[BUFFER_SIZE];
        read(clnt_sock, buffer, sizeof(buffer) - 1);


        if(buffer[0] == 'm')
        {
            manFirst = true ;
        }

    }


    int isWin() {
        for (int i = 0; i < COL; i++)
        {
            if (board[i][0] + board[i][1] + board[i][2] == 3)
                return 1;
            else if (board[i][0] + board[i][1] + board[i][2] == -3)
                return -1;
        }
        for (int j = 0; j < ROW; j++)
        {
            if (board[0][j] + board[1][j] + board[2][j] == 3)
                return 1;
            else if (board[0][j] + board[1][j] + board[2][j] == -3)
                return -1;
        }
        if (board[0][0] + board[1][1] + board[2][2] == 3 || board[0][2] + board[1][1] + board[2][0] == 3)
            return 1;
        else if (board[0][0] + board[1][1] + board[2][2] == -3 || board[0][2] + board[1][1] + board[2][0] == -3)
            return -1;

        else  return 0;

    }

    //评估函数
    int evaluteMap() {


        int i, j;

        if (isWin() == COM)
        {
            return MAX_NUM;
        }

        if (isWin() == MAN)
        {
            return -MAX_NUM;
        }


        int count = 0;

        for (i = 0; i < ROW; i++)
            for (j = 0; j < COL; j++)
            {
                if (board[i][j] == EMPTY)
                    tempBoard[i][j] = COM;
                else
                    tempBoard[i][j] = board[i][j];
            }


        for (i = 0; i < ROW; i++)
            count += (tempBoard[i][0] + tempBoard[i][1] + tempBoard[i][2]) / 3;
        for (i = 0; i < COL; i++)
            count += (tempBoard[0][i] + tempBoard[1][i] + tempBoard[2][i]) / 3;

        count += (tempBoard[0][0] + tempBoard[1][1] + tempBoard[2][2]) / 3;
        count += (tempBoard[2][0] + tempBoard[1][1] + tempBoard[0][2]) / 3;


        for (i = 0; i < ROW; i++)
            for (j = 0; j < COL; j++)
            {
                if (board[i][j] == EMPTY)
                    tempBoard[i][j] = MAN;
                else tempBoard[i][j] = board[i][j];
            }


        for (i = 0; i < 3; i++)
            count += (tempBoard[i][0] + tempBoard[i][1] + tempBoard[i][2]) / 3;
        for (i = 0; i < 3; i++)
            count += (tempBoard[0][i] + tempBoard[1][i] + tempBoard[2][i]) / 3;
        count += (tempBoard[0][0] + tempBoard[1][1] + tempBoard[2][2]) / 3;
        count += (tempBoard[2][0] + tempBoard[1][1] + tempBoard[0][2]) / 3;



        return count;
    }


    void makeMove(const Move &curMove)
    {
        board[curMove.x][curMove.y] = player;
        player = (player == COM) ? MAN : COM;
    }

    void unMakeMove(Move curMove) {
        board[curMove.x][curMove.y] = 0;
        player = (player == COM) ? MAN : COM;
    }

    //get empty place
    int getMoveList(Move moveList[]) {
        int moveCount = 0;
        int i, j;
        for (i = 0; i < COL; i++)
        {
            for (j = 0; j < ROW; j++)
            {
                if (board[i][j] == 0)
                {
                    moveList[moveCount].x = i;
                    moveList[moveCount].y = j;
                    moveCount++;
                }

            }
        }
        return moveCount;
    }


    int miniMaxsearch(int depth)
    {
        int value;
        int bestValue = 0;
        int moveCount = 0;
        int i;

        Move moveList[9];

        if (isWin() == COM || isWin() == MAN)
        {
            return evaluteMap();
        }

        //if depth equal zero,return value
        if (depth == 0)
        {
            return evaluteMap();
        }


        if (COM == player) {
            bestValue = -MAX_NUM;
        }
        else if (MAN == player)
        {
            bestValue = MAX_NUM;
        }


        moveCount = getMoveList(moveList);

        for (i = 0; i < moveCount; i++)
        {
            Move curMove = moveList[i];

            makeMove(curMove);
            value = miniMaxsearch(depth - 1);
            unMakeMove(curMove);

            if (player == COM)
            {
                if (value > bestValue)
                {
                    bestValue = value;
                    if (depth == currentDepth)
                    {
                        bestMove = curMove;
                    }
                }
            }
            else if (player == MAN)
            {
                if (value < bestValue)
                {
                    bestValue = value;
                    if (depth == currentDepth)
                    {
                        bestMove = curMove;
                    }
                }
            }

        }

        return bestValue;
    }

    virtual bool manPlay()
    {
        Move move = recvMove(clnt_sock);
        board[move.x][move.y] = MAN;
        step++;
        currentDepth--;

        if (player == isWin()) {
            bestMove.setMessage(MAN);
            sendMove(bestMove, clnt_sock);


            return false ;
        }
        else if(10 == step)
        {
            bestMove.setMessage(DRAW);
            sendMove(bestMove, clnt_sock);

            return false ;

        }
        player = (player == COM) ? MAN : COM;
        return true ;
    }



    virtual bool comPlay()
    {
        miniMaxsearch(currentDepth);
        board[bestMove.x][bestMove.y] = COM;
        step++;
        currentDepth--;

        if (player == isWin()) {
            bestMove.setMessage(COM);
            sendMove(bestMove, clnt_sock);
            return false ;
        }

        else if(10 == step)
        {
            bestMove.setMessage(DRAW);
            sendMove(bestMove, clnt_sock);
            return false;
        }

        sendMove(bestMove, clnt_sock);
        player = (player == COM) ? MAN : COM;
        return true ;

    }


    void disconnect()
    {
        close(serv_sock);
        close(clnt_sock);
    }


};



#endif /* Board_hpp */

Server main.cpp

//
//  main.cpp
//  TicTacToeServer
//
//  Created by Tusko on 2017/4/9.
//  Copyright © 2017年 Tusko. All rights reserved.
//

#include <iostream>
#include "Board.hpp"

int main(int argc, const char * argv[]) {

    TTTServer TTTserv ;
    return 0;
}

3.Client

//
//  Board.hpp
//  TicTacToeServer
//
//  Created by Tusko on 2017/4/9.
//  Copyright © 2017年 Tusko. All rights reserved.
//

#ifndef Board_hpp
#define Board_hpp

#include <stdio.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <iostream>
#include <string>
#include "AbstractBoard.h"
#define X -1
#define O  1
#define BUFFER_SIZE   1024



class TTTClient : public AbstractBoard{


public:
    TTTClient(){
        ClntSocket();
    }

private:


    int clnt_sock ;

    void ClntSocket()
    {

        clnt_sock = socket(AF_INET, SOCK_STREAM, 0);

        struct sockaddr_in serv_addr;
        bzero(&serv_addr, sizeof(serv_addr));

        serv_addr.sin_family = AF_INET;
        serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
        serv_addr.sin_port = htons(6666);


        connect(clnt_sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr));

        char buffer[BUFFER_SIZE] = {0};

        while (1) {

            if ( read(clnt_sock, buffer, sizeof(buffer) - 1) )
            {
                printf("Message form TTTserver: %s\n", buffer);

                char str[] = "connect TTTClient successfully\n";
                write(clnt_sock, str, sizeof(str));
                break ;
            }
        }



        std::cout<<"Who plays first? m - man(O) , c - computer(X)"<<std::endl ;
        std::cout<<"Enter your select:"<<std::endl ;

        char ch[20] = {0};
        std::cin>>ch;

        while ( !( ch[0]  == 'c' || ch[0] == 'm') || strlen(ch) > 1) {
            std::cout<<"Select wrong,enter again:"<<std::endl ;
            std::cin>>ch;
        }

        if(ch[0] == 'm')
        {
            manFirst = true ;
        }

        write(clnt_sock,ch, sizeof(ch));

        startPlay();
    }

    void startPlay()
    {
        printBoard();

        if(manFirst)
        {
            player = MAN;
            while (1)
            {
                manPlay();
                if(!comPlay())
                {
                    break ;
                }
            }
        }
        else
        {
            player = COM;
            while (1) {
                if(!comPlay())
                {
                    break ;
                }
                manPlay();
            }

        }

        sleep(3);
        disconnect();
    }

    virtual bool manPlay()
    {

        Move move ;
        int x, y;
        printf("请输入位置坐标  e.g :(0 0)为左上角 (2,2)为右下角 \n");
        scanf("%d", &x);
        scanf("%d", &y);

        while (x < 0 || x > 2 || y < 0 || y > 2)
        {
            printf("您输入的坐标错误,请重新输入:x:(0~2) , y:(0~2)\n");
            scanf("%d", &x);
            scanf("%d", &y);
        }
        while (board[x][y] != 0)
        {
            printf("该位置已有棋,请重新输入:\n");
            scanf("%d", &x);
            scanf("%d", &y);
        }
        move.x = x ;
        move.y = y ;

        board[move.x][move.y] = MAN;

        sendMove(move, clnt_sock);

        return true ;
    }



    virtual bool comPlay()
    {

        Move move = recvMove(clnt_sock);

        if(strlen(move.mesg) > 0)
        {
            if(-1 !=move.x)
            {
                board[move.x][move.y] = COM;
                printBoard();
            }

            std::cout<<move.mesg<<std::endl;

            return false;
        }

        board[move.x][move.y] = COM;

        printBoard();

        return true ;
    }


    void disconnect()
    {
        close(clnt_sock);
    }

};


#endif /* Board_hpp */

Client main.cpp

//
//  main.cpp
//  TicTacToe_Client
//
//  Created by Tusko on 2017/4/9.
//  Copyright © 2017年 Tusko. All rights reserved.
//

#include <iostream>

#include "Board.hpp"

int main(int argc, const char * argv[]) {


    TTTClient TTTclnt ;

    return 0;
}
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值