井字棋源码(网络线程池版)

源码链接:game

效果可能没有那么好,大家可以给点建议。

效果展示 

game.h

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define ROW 3
#define COL 3

void InitBoard(char board[ROW][COL], int row, int col)
{
	int i = 0;
	for (i = 0; i < row; i++)
	{
		int j = 0;
		for (j = 0; j < col; j++)
		{
			board[i][j] = ' ';
		}
	}
}


void DisplayBoard(char board[ROW][COL], int row, int col)
{
	int i = 0;
	for (i = 0; i < row; i++)
	{
		//打印数据
		int j = 0;
		for (j = 0; j < col; j++)
		{
			printf(" %c ", board[i][j]);
			if (j < col - 1)
				printf("|");
		}
		printf("\n");
		//打印分割的行
		if (i < row - 1)
		{
			for (j = 0; j < col; j++)
			{
				printf("---");
				if (j < col - 1)
					printf("|");
			}
			printf("\n");
		}
	}
}

void player_move(char board[ROW][COL], int row, int col)
{
	int x = 0;
	int y = 0;
	printf("玩家下棋\n");
	while (1)
	{
		printf("请输入坐标:>");
		scanf("%d %d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			//下棋
			if (board[x - 1][y - 1] == ' ')
			{
				board[x - 1][y - 1] = '*';
				break;
			}
			else
			{
				printf("该坐标被占用,请重新输入\n");
			}
		}
		else
		{
			printf("坐标非法,请重新输入\n");
		}
	}
}

void computer_move(char board[ROW][COL], int row, int col)
{
	int x = 0;
	int y = 0;
	printf("电脑下棋:>\n");
	while (1)
	{
		x = rand() % row;//0~2
		y = rand() % col;//0~2
		if (board[x][y] == ' ')
		{
			board[x][y] = '#';
			break;
		}
	}
}

static int if_full(char board[ROW][COL], int row, int col)
{
	int i = 0;
	for (i = 0; i < row; i++)
	{
		int j = 0;
		for (j = 0; j < col; j++)
		{
			if (board[i][j] == ' ')
			{
				return 0;//没满
			}
		}
	}
	return 1;//满了
}

char is_win(char board[ROW][COL], int row, int col)
{
	int i = 0;
	//判断行
	for (i = 0; i < row; i++)
	{
		if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][1] != ' ')
		{
			return board[i][1];
		}
	}
	//判断列
	for (i = 0; i < col; i++)
	{
		if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[1][i] != ' ')
		{
			return board[1][i];
		}
	}
	//对角线
	if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[1][1] != ' ')
	{
		return board[1][1];
	}
	if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[1][1] != ' ')
	{
		return board[1][1];
	}

	//判断平局
	if (if_full(board, row, col) == 1)
	{
		return 'Q';
	}

	//继续
	return 'C';
}

tcp_client.cc

#include <iostream>
#include <string>
#include <cstring>
#include <cstdio>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include "game.h"

void menu()
{
    printf("********************************\n");
    printf("*********  1. play     *********\n");
    printf("*********  0. exit     *********\n");
    printf("********************************\n");
}

void game()
{
    char ret = 0;
    // 存放下棋的数据
    char board[ROW][COL] = {0};
    // 初始化棋盘为全空格
    InitBoard(board, ROW, COL);
    // 打印棋盘
    DisplayBoard(board, ROW, COL);
    while (1)
    {
        // 玩家下棋
        player_move(board, ROW, COL);
        DisplayBoard(board, ROW, COL);
        // 判断输赢
        ret = is_win(board, ROW, COL);
        if (ret != 'C')
        {
            break;
        }
        // 电脑下棋
        computer_move(board, ROW, COL);// 随机下棋
        DisplayBoard(board, ROW, COL);
        ret = is_win(board, ROW, COL);
        if (ret != 'C')
        {
            break;
        }
    }
    if (ret == '*')
    {
        printf("恭喜你赢了\n");
    }
    else if (ret == '#')
    {
        printf("很遗憾你输了\n");
    }
    else
    {
        printf("平局\n");
    }
}

void Usage(std::string proc)
{
    std::cout << "\nUsage: " << proc << " serverIp serverPort\n"
              << std::endl;
}

void Print(int &sock, std::string &line)
{
    ssize_t s = send(sock, line.c_str(), line.size(), 0);
    if (s > 0)
    {
        char buffer[1024];
        ssize_t s = recv(sock, buffer, sizeof(buffer) - 1, 0);
        if (s > 0)
        {
            buffer[s] = 0;
            std::cout << "server 回应# " << buffer << std::endl;
        }
        else if (s == 0)
        {
            close(sock);
        }
    }
    else
    {
        close(sock);
    }
}

int main(int argc, char *argv[])
{
    if (argc != 3)
    {
        Usage(argv[0]);
        exit(1);
    }
    std::string serverip = argv[1];
    uint16_t serverport = atoi(argv[2]);

    int sock = 0;
    std::string line;

    sock = socket(AF_INET, SOCK_STREAM, 0);
    if (sock < 0)
    {
        std::cerr << "socket error" << std::endl;
        exit(2);
    }
    struct sockaddr_in server;
    memset(&server, 0, sizeof(server));
    server.sin_family = AF_INET;
    server.sin_port = htons(serverport);
    server.sin_addr.s_addr = inet_addr(serverip.c_str());

    if (connect(sock, (struct sockaddr *)&server, sizeof(server)) < 0) // 连接服务器
    {
        std::cerr << "connect error" << std::endl;
        exit(3);
    }

    std::cout << "connect success" << std::endl;

    int input = 0;
    srand((unsigned int)time(NULL));
    do
    {
        menu();
        printf("请选择:>");
        scanf("%d", &input);
        switch (input)
        {
        case 1:
            line = "start";
            Print(sock, line);
            game(); // 游戏
            break;
        case 0:
            line = "quit";
            Print(sock, line);
            break;
        default:
            printf("选择错误\n");
            break;
        }
    } while (input);
    if (line == "quit")
    {
        exit(0);
    }

    return 0;
}

tcp_server.cc

#include "tcp_server.hpp"
#include <memory>

static void Usage(std::string proc)
{
    std::cout << "\nUsage" << proc << " port\n" << std::endl;
}

int main(int argc, char* argv[])
{
    if(argc != 2)
    {
        Usage(argv[0]);
        exit(1);
    }
    uint16_t port = atoi(argv[1]);
    std::unique_ptr<Tcp_Server> svr(new Tcp_Server(port));
    svr->InitServer();
    svr->Start();
    return 0;
}

tcp_server.hpp

#pragma once

#include <iostream>
#include <string>
#include <cstring>
#include <strings.h>
#include <assert.h>
#include <unistd.h>
#include <signal.h>
#include <memory>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <pthread.h>
#include <sys/wait.h>
#include "threadPool/log.hpp"
#include "threadPool/thread.hpp"
#include "threadPool/threadPool.hpp"
#include "threadPool/Task.hpp"
#include "game.h"

static void play(int sock, const std::string &clientip, const uint16_t &clientport, const std::string &thread_name)
{
    char buffer[1024];
    while (true)
    {
        ssize_t s = read(sock, buffer, sizeof(buffer) - 1);
        std::string message;
        if (s > 0)
        {
            buffer[s] = 0;
            std::cout << thread_name << "|" << clientip << ":" << clientport << "# " << buffer << std::endl;
            if (strcmp(buffer, "start") == 0)
            {
                message = "玩家请开始游戏";
            }
            if (strcmp(buffer, "quit") == 0)
            {
               message = "玩家退出游戏成功";
               
            }
            write(sock, message.c_str(), message.size());
        }
        else if (s == 0) // 对端关闭连接
        {
            logMessage(NORMAL, "%s:%d 玩家已退出游戏,我也退出", clientip.c_str(), clientport);
            break;
        }
        else
        {
            logMessage(ERROR, "read socket error, %d:%s", errno, strerror(errno));
            break;
        }
    }
    close(sock);
}

class Tcp_Server
{
private:
    const static int gbacklog = 20;

public:
    Tcp_Server(uint16_t port, std::string ip = "")
        : _port(port), _ip(ip), listensock(-1), _threadpool_ptr(ThreadPool<Task>::getThreadPool())
    {
    }
    ~Tcp_Server()
    {
    }

    void InitServer()
    {
        // 1.创建socket
        listensock = socket(AF_INET, SOCK_STREAM, 0);
        if (listensock < 0)
        {
            // 创建socket失败
            logMessage(FATAL, "create socket error, %d:%S", errno, strerror(errno));
            exit(2);
        }
        logMessage(NORMAL, "create socket success, listensock:%d", listensock);

        // 2.bind
        struct sockaddr_in local;
        memset(&local, 0, sizeof local);
        local.sin_family = AF_INET;
        local.sin_port = htons(_port);
        local.sin_addr.s_addr = _ip.empty() ? INADDR_ANY : inet_addr(_ip.c_str()); // INADDR_ANY:任意IP
        if (bind(listensock, (struct sockaddr *)&local, sizeof(local)) < 0)
        {
            // bind失败
            logMessage(FATAL, "bind error, %d:%s", errno, strerror(errno));
            exit(3);
        }

        // 3.建立连接
        if (listen(listensock, gbacklog) < 0)
        {
            // 建立连接失败
            logMessage(FATAL, "listen error, %d:%s", errno, strerror(errno));
            exit(4);
        }

        logMessage(NORMAL, "init server success");
    }

    void Start()
    {
        _threadpool_ptr->run();
        while (true)
        {
            // 4.获取连接
            struct sockaddr_in src;
            socklen_t len = sizeof(src);
            int servicesock = accept(listensock, (struct sockaddr *)&src, &len);
            // 获取连接失败
            if (servicesock < 0)
            {
                logMessage(ERROR, "accept error, %d:%s", errno, strerror(errno));
                continue;
            }
            // 获取连接成功
            uint16_t client_port = ntohs(src.sin_port);
            std::string client_ip = inet_ntoa(src.sin_addr);
            logMessage(NORMAL, "link success, servicesock: %d | %s : %d |\n", servicesock, client_ip.c_str(), client_port);

            // 5.开始通信
            // 线程池版
            Task t(servicesock, client_ip, client_port, play);
            _threadpool_ptr->pushTask(t);
        }
    }

private:
    uint16_t _port;
    std::string _ip;
    int listensock;
    std::unique_ptr<ThreadPool<Task>> _threadpool_ptr;
};

相关推荐

  1. (免费

    2024-04-25 18:56:02       9 阅读
  2. Nginx线剖析

    2024-04-25 18:56:02       21 阅读
  3. 三子/(C语言)

    2024-04-25 18:56:02       24 阅读
  4. C++EasyX之

    2024-04-25 18:56:02       43 阅读
  5. 使用Python创建游戏

    2024-04-25 18:56:02       16 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-04-25 18:56:02       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-04-25 18:56:02       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-04-25 18:56:02       19 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-04-25 18:56:02       20 阅读

热门阅读

  1. 多网卡IP配置netplan

    2024-04-25 18:56:02       39 阅读
  2. 前端实现批量下载并打包成ZIP文件

    2024-04-25 18:56:02       11 阅读
  3. Xshell常用命令大全

    2024-04-25 18:56:02       14 阅读
  4. tryhackme

    tryhackme

    2024-04-25 18:56:02      10 阅读
  5. 【测试开发学习历程】异常处理

    2024-04-25 18:56:02       12 阅读
  6. 深交所发布独董履职手册,规范独董履职行为

    2024-04-25 18:56:02       11 阅读
  7. CVE-2022-0543 Redis沙盒逃逸漏洞复现(CVE-2022-0543)

    2024-04-25 18:56:02       14 阅读