点滴记录总结,一天一打鸡血。
2015年5月华为组织了一次软件精英挑战赛,赛题是德州扑克手牌AI~
环境及测试说明:http://pan.baidu.com/s/1dD2dL0P
基本流程很基本:手牌收到服务器消息,辨识出消息并作出响应(也有可能不需要,比如手牌消息、结束消息等)。
服务器发给手牌的消息有以下几种(server –> player):
- 座次消息,以 seat/ \n 开始,/seat \n结尾的字符串;
- 游戏结束消息,形为game-over \n的字符串;
- 盲注消息,以 blind/ \n 开始,/blind \n结尾的字符串;
- 手牌消息,以 hold/ \n 开始,/hold \n结尾的字符串;
- 询问消息,以 inquire/ \n 开始,/inquire \n结尾的字符串;
- 公牌消息,以 flop/ \n 开始,/flop \n结尾的字符串;
- 转牌消息,以 turn/ \n 开始,/turn \n结尾的字符串;
- 河牌消息,以 river/ \n 开始,/river \n结尾的字符串;
- 摊牌消息,以 showdown/ \n 开始,/showdown \n结尾的字符串;
- 彩池分配消息,以 pot-win/ \n 开始,/pot-win \n结尾的字符串;
- 通知消息,以 notify/ \n 开始,/notify \n结尾的字符串,这个手牌注册指定才会收到这样的消息。
手牌每次收到询问消息必须做出回答,超时不回或回的东西不符合规范会被视为掉线,累积十次视为离线,然后就没有然后了。。。
也就是手牌除了向服务器发送注册消息之后,当且仅当收到inquire消息进行回复,可以是fold/raise xx/call/check/all_in。
一次游戏玩到结束有四个押注圈,分别是Pre-flop 前翻牌圈(我定义为HOLD)、翻牌圈(FLOP)、转牌圈(TURN)、河牌圈(RIVER)。除了最后一圈(RIVER),每个押注圈押注之后(所有未弃牌玩家押相同金额,除了all-in),都会发公牌,这时就需要设计识牌程序、分析手牌公牌、计算牌力大小、估计对手牌力等一系列模块。
下面是我的消息循环处理部分代码,rt所述。
while (strstr(buffer, "game-over") == NULL) {
//每次收到消息都更新玩家数、盲注信息、弃牌数、加的筹码数等信息
UpdateGameInfo(buffer);
//下面是跟新没个押注圈的公牌信息
if ((bufInfo = strstr(buffer, "flop/")) != NULL)
UpdateCards(bufInfo, FLOP);
if((bufInfo = strstr(buffer, "turn/")) != NULL)
UpdateCards(bufInfo, TURN);
if((bufInfo = strstr(buffer, "river/")) != NULL)
UpdateCards(bufInfo, RIVER);
//如果是询问消息,就要作出决响应咯~
if (strstr(buffer, "inquire/") != NULL) {
memset(buffer, '\0', BUF_SIZE);
decision = Decision(game_circle);//每个押注圈的决策时不同滴
//decision
//WriteLog(client_log, decision, -2);
strcpy(buffer, decision);
strcat(buffer, " \n");
send(sockfd, buffer, strlen(buffer), 0);//这里要注意不能把strlen(buffer)写死为SIZE什么的,服务器不懂,会掉线的~
usleep(1000);
//gameInfo
//WriteLog(client_log, buffer, -1);
}
memset(buffer, '\0', BUF_SIZE);
recv(sockfd, buffer, BUF_SIZE, 0) ;
//WriteLog(client_log, buffer, ++num);
}
这一节就写基本流程了,下一节主要介绍数据结构的设计。