德州扑克牌手程序

我参加了2015华为软件精英挑战赛,在独立完成代码编写和调试的过程中,自己的编程能力也有了一些进步。现把所有代码分享如下,希望大家能批评指正。

项目简介:依据德州扑克规则,使用C++编写牌手程序,参加扑克比赛。
程序语言:C++ 通讯方式:TCP socket通讯
开发工具:g++ 开发环境:Linux操作系统Ubuntu
完成内容:
在linux下,实现了与服务器程序的TCP socket通信
处理粘包问题,实现了文本消息的无差错提取
完成牌型判断,对手加注风格分析等程序设计
完成了加注策略的算法设计及其C++实现
为了提交代码方便,我把所有子文件都整理到一个文件中:

#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
//以上是linux下socket的头文件
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <iostream>
#include <map>
#include<cstring>
#include <cstdlib>
#include <fstream>//读写文件的头文件
using namespace std;
typedef multimap<int,int> MMAP; 
MMAP mycard;


//  5个子函数声明   ////////////////////////////////////////////////////////////////////////////////
int hold_msg(MMAP& mycard, char* buffer,int& mycard_score,int& handcard_color,int& handcard_point1,int& handcard_point2);
int flop_msg(MMAP& mycard, char* buffer,int& mycard_score,int handcard_color,int handcard_point1,int handcard_point2);
int turn_msg(MMAP& mycard, char* buffer,int& mycard_score,int handcard_color,int handcard_point1,int handcard_point2);
int river_msg(MMAP& mycard, char* buffer,int& mycard_score,int handcard_color,int handcard_point1,int handcard_point2);
int inquire_msg(char* buffer,int& mybet,int& allfold,MMAP mycard,int hand_num,int& raise_pid_num,int& jijing);
////////////////////////////////////////////////////////////////////////////////
int mycard_score = 0;//手牌分数
int mybet = 1100;//离我最近的第一个没fold的人的本手牌累计投注额,意味着我要继续玩下去,一共要投入的钱
int allfold = 0;//1表示我前面的人都弃牌了
int parameter1=70;//起始赌注界限,是否大小盲注决定
int allmybet[100];//记录赌注是否曾经了,用来判断是不是不需要下赌注就可以混下去
int betnum=1;//数组allmybet的计数器
int bet_increase=1;//1表示赌注有增加
int handcard_color=1;//0表示两张手牌颜色不同,这时同花没有意义
int handcard_point1=0;
int handcard_point2=1;
int jijing=1;//1表示有激进者存在
int raise_pid_num=0;
int hand_num=1;//当前是第几局
////////////////////////////////////////////////////////////////////////////////
//////////  下面开始socket连接通信  //////////////////////////////////////////
int mysocket_id = -1;//初始化为-1
/*ipparameter_num是命令行总的参数个数  
   ip_parameter[]是ipparameter_num个参数,其中第0个参数是程序的全名,以后的参数  
   命令行后面跟的用户输入的参数
示例./game  192.168.0.1  1024  192.168.0.2  2048  6001
其中 192.168.0.1 是牌桌程序IP, 1024 是牌桌程序端口号
其中 192.168.0.2 是牌手程序绑定的IP, 2048是牌手程序绑定的端口号
其中 6001 是用来向牌桌注册的ID
*/  
int main(int ipparameter_num, char *ip_parameter[])//指针数组
{
    in_addr_t server_ip = inet_addr(ip_parameter[1]);//其中 192.168.0.1 是牌桌程序IP
    in_port_t server_port = htons(atoi(ip_parameter[2]));//1024 是牌桌程序端口号//htons():主机字节顺序转换为网络字节顺序(对无符号短型进行操作 4 bytes)
    in_addr_t my_ip = inet_addr(ip_parameter[3]);//其中 192.168.0.2 是牌手程序绑定的IP
    in_port_t my_port = htons(atoi(ip_parameter[4]));//2048是牌手程序绑定的端口号
    int my_id = atoi(ip_parameter[5]);//其中 6001 是用来向牌桌注册的ID


    /* 创建socket */
    mysocket_id = socket(AF_INET, SOCK_STREAM, 0);//AF_INET表示ipv4协议,AF_INET决定了要用ipv4地址(32位的)与端口号(16位的)的组合
    if(mysocket_id < 0)/*  如果发生错误,socket()函数返回  – 1 */
    {
        printf("init socket failed!\n");
        return -1;
    }
    /* 设置socket选项,地址重复使用,防止程序非正常退出,下次启动时bind失败 */
    int rep = 1;
    setsockopt(mysocket_id, SOL_SOCKET, SO_REUSEADDR, (const char*)&rep, sizeof(rep));//(const char*)
    /*struct sockaddr_in {   //ipv4的地址结构
    short int sin_family;   Internet地址族
    unsigned short int sin_port;   端口号
    struct in_addr sin_addr;   Internet地址
    unsigned char sin_zero[8];   添0(和struct sockaddr一样大小)
    }*/
    struct sockaddr_in my_addr;//sockaddr_in是在头文件中定义的结构体
    bzero(&my_addr, sizeof(my_addr));//把 sin_zero 全部设成零值
    my_addr.sin_family = AF_INET;//给ipv4地址结构的三个量赋值
    my_addr.sin_addr.s_addr = my_ip;
    my_addr.sin_port = my_port;
    //当你使用socket()函数得到一个套接字描述符,你也许需要将 socket绑定上一个你的机器上的端口。
    if(bind(mysocket_id, (struct sockaddr*)&my_addr, sizeof(my_addr)))//bind()函数把一个地址族中的特定地址赋给socket描述符
    {
    printf("bind failed!\n"); 
    return -1;
    }


    /* 连接server */
    struct sockaddr_in server_addr;
    bzero(&server_addr, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = server_ip;
    server_addr.sin_port = server_port;
    //connect函数,客户端通过调用connect函数来建立与TCP服务器的连接。
    while(connect(mysocket_id, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0)
    {
        usleep(100*1000); /* sleep 100ms, 然后重试,保证无论server先起还是后起,都不会有问题 */
    }//usleep功能把进程挂起一段时间,单位是微秒; sleep()里面的单位是秒,而不是毫秒


    /* 向server注册 */
    char send_msg[50] = {
  
  '\0'};
    snprintf(send_msg, sizeof(send_msg)-1, "reg: %d %s \n", my_id, "fuliguo"); 
    send(mysocket_id, send_msg, strlen(send_msg)+1, 0);


    /* 接收server消息,进入游戏 */
//*************************************************************************************************************************************************************/
//********                                        *************************************************************************************************************/
//********   下面是我的判断和动作                 *************************************************************************************************************/
//********                                        *************************************************************************************************************/
//*************************************************************************************************************************************************************/
    while(1)
    {
        //接收buffer
        char buffer[1024] = {
  
  '\0'};
        int length = recv(mysocket_id, buffer, sizeof(buffer)-1, 0);
        //printf("buffer:\n\n%s\n\n",buffer);
        fflush(stdout);
        //buffer有值
        if(length > 0)
        {   //if(strstr(buffer,"win")) {mycard.clear();}//在river里面清空可能更合适,注意win可能和hold消息在一个buffer里,
                //如果win和river在一起怎么办,也不能在river里清空,因为有的局没有river.river和hold会连一起
            ///////////////////从收到的字符串中拆解出有用的几个信息//////////////////////////////////////
            //首先要解决上一局的turn,river,win和这一局的seat,hold连起来的情况,因为这样会凑成4,7,8,9张牌,很容易出大牌而犯allin的大错误
            if((strstr(buffer,"hold"))&&(strstr(buffer,"river"))&&(strstr(buffer,"win"))&&(strstr(buffer,"seat")))
            {
                //seat_msg(buffer,my_id,raise_pid_num,hand_num,changfold_flag,changcheck_flag,jijing); 
                mycard.clear();//在hold的一开始把mycard清空
                hold_msg(mycard,buffer,mycard_score,handcard_color,handcard_point1,handcard_point2);
                memset(allmybet,1,100);
                betnum=1;
                bet_increase=1;
            }
            else
            {
                if(strstr(buffer,"hold"))    //在hold的一开始把mycard清空
                {
                    mycard.clear();
                    hold_msg(mycard,buffer,mycard_score,handcard_color,handcard_point1,handcard_point2);
                    memset(allmybet,1,100);
                    betnum=1;
                    bet_increase=1;
                }
                if(strstr(buffer,"flop"))    
                {
                    flop_msg(mycard,buffer,mycard_score,handcard_color,handcard_point1,handcard_point2);
                    //flop_score=mycard_score;
                }
                if(strstr(buffer,"turn"))    
                {
                    turn_msg(mycard,buffer,mycard_score,handcard_color,handcard_point1,handcard_point2);
                    //turn_score=mycard_score;
                }
                if(strstr(buffer,"river"))   
                {
                    river_msg(mycard,buffer,mycard_score,handcard_color,handcard_point1,handcard_point2);
                    //river_score=mycard_score;
                }
            }
            //////////////////////////////////////////////////////////////////////////////////////  
            if(strstr(buffer,"inquire"))
            {
                inquire_msg(buffer,mybet,allfold,mycard,hand_num,raise_pid_num,jijing);//截取消息,获得我继续玩将要投下的赌注总数
                //设置个存放mybet的数组,每局清空一次,用来判断这次的mybet是否比上次增加了,要是没增加,就说明check就可以,不用下注,就没必要弃牌了
                if(betnum>99)betnum=1;
                else betnum += 1;
                allmybet[betnum]=mybet;
                if(allmybet[betnum]==allmybet[betnum-1]) bet_increase=0;
                else bet_increase=1;
                //if(betnum>50)betnum=0;else betnum += 1;


                // 现在有手牌的分数了,根据 分数 和 mybet 两个参数做出action
                //send_msg[50] = {'\0'};
                memset(send_msg,'\0',50);
                if(allfold==1) snprintf(send_msg,sizeof(send_msg) - 1,"check");
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
                else if(jijing==0)
                {
                    if(mycard.size()==2)
                    {
                        if(mybet>300)
                        {
                            if(bet_increase==0) snprintf(send_msg,sizeof(send_msg) - 1,"check");
                            else snprintf(send_msg,sizeof(send_msg) - 1,"fold");
                        }
                        else if(mybet>200)
                        {
                            if(mycard_score>3) snprintf(send_msg,sizeof(send_msg) - 1,"check");
                            else if(bet_increase==0) snprintf(send_msg,sizeof(send_msg) - 1,"check");
                            else snprintf(send_msg,sizeof(send_msg) - 1,"fold");
                        }
                        else if(mybet>79)
                        {
                            if(mycard_score>2) snprintf(send_msg,sizeof(send_msg) - 1,"check");
                            else if(bet_increase==0) snprintf(send_msg,sizeof(send_msg) - 1,"check");
                            else snprintf(send_msg,sizeof(send_msg) - 1,"fold");
                        }
                        else
                        {
                            if(mycard_score>2) snprintf(send_msg,sizeof(send_msg) - 1,"raise 43");
                            else if(mycard_score>0) snprintf(send_msg,sizeof(send_msg) - 1,"check");
                            else if(bet_increase==0) snprintf(send_msg,sizeof(send_msg) - 1,"check");
                            else snprintf(send_msg,sizeof(send_msg) - 1,"fold");
                        }
                    }
                    else
                    {
                        if(mybet>2000)
                        {
                            if(mycard_score>8) snprintf(send_msg,sizeof(send_msg) - 1,"check");//一定要有上限
                            else if(bet_increase==0) snprintf(send_msg,sizeof(send_msg) - 1,"check");
                            else snprintf(send_msg,sizeof(send_msg) - 1,"fold");
                        }
                        else if(mybet>1000)
                        {
                            if(mycard_score>5) snprintf(send_msg,sizeof(send_msg) - 1,"check");//一定要有上限
                            else if(bet_increase==0) snprintf(send_msg,sizeof(send_msg) - 1,"check");
                            else snprintf(send_msg,sizeof(send_msg) - 1,"fold");
                        }
                        else if(mybet>800)
                        {
                            if(mycard_score>4) snprintf(send_msg,sizeof(send_msg) - 1,"check");
                            else if(bet_increase==0) snprintf(send_msg,sizeof(send_msg) - 1,"check");
                            else snprintf(send_msg,sizeof(send_msg) - 1,"fold");
                        }
                        else if(mybet>300)
                        {
                            if(mycard_score>7) snprintf(send_msg,sizeof(send_msg) - 1,"raise 301");//一定要有上限
                            else if(mycard_score>5) snprintf(send_msg,sizeof(send_msg) - 1,"raise 43");
                            else if(mycard_score>3) snprintf(send_msg,sizeof(send_msg) - 1,"check");
                            else if(bet_increase==0) snprintf(send_msg,sizeof(send_msg) - 1,
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值