您的位置:首页 > 其它

德州扑克 2015 华为软件精英挑战赛

2015-08-01 21:24 218 查看
概述

华为2015软件挑战赛比赛总结,跟队友当时奋斗了15天吧,最后差点进32强了,第三轮遇到的对手太厉害,止步64强了。这次官方提供 Ubuntu 纯命令行镜像和庄家 Server,选手编写德州扑克选手机器人程序互相 PK(8人一组)500轮后钱多者胜出。运行只要运行华为提供的ne">dist_check_and_run.sh
脚本 即可,里面会给自动运行每个game程序.最近快要找工作了一些项目还是要总结一下的,感觉欠缺的地方还是有很多的,下面进入正题。

梳理一下主干主要这次比赛项目主要分为一下几大块:



1、Socket注册

开始pk选手向庄家Sever注册自己的信息,这里官方给出的信息作品的运行入口统一命名为game,
支持5个参数( 牌桌程序IP,牌桌程序端口好,牌手程序绑定的IP,牌手程序绑定的端口号,牌手的ID)

调用形式如下:

./game 192.168.0.1 1024 192.168.0.2 2048 6001

因此注册socket采用4参数的,输出字符流采用PrintWrite

// Socket link
Socket socket = new Socket(args[0], Integer.parseInt(args[1]),
InetAddress.getByName(args[2]), Integer.parseInt(args[3]));
// OutputStream
OutputStream os = socket.getOutputStream();
PrintWriter pw = new PrintWriter(os);
pw.write("reg: " + args[4] + " xsfelvis \n");
pw.flush();


这里PrintWriter提供了PrintStream的所有打印方法,其方法也从不抛出IOException。与PrintStream的区别:作为处理流使用时,PrintStream只能封装OutputStream类型的字节流,而PrintWriter既可以封装OutputStream类型的字节流,还能够封装Writer类型的字符输出流并增强其功能。这样我们就成功的跟Sever服务器通信上了,(但是不要立马关闭socekt,需要接受Sever后续消息,读取到game
over消息时关闭)迈出了第一步

2、解析消息

这里庄家Sever都会在一定的时候向选手发出公共消息,这个在比赛给出的程序通信协议中均有给出,主要包括

"seat/
" 座次

"blind/ "盲注

"hold/ "手牌

"flop/ "公牌

"turn/ "转牌

"river/ "河牌

"inquire/ "询问消息(即是否出牌/check)

"showdown/ "摊牌消息

"pot-win/ " 彩池信息

这些消息都需要进行正确提取作为自己判断的依据,主要先用hashmap将这些信息进行映射,以便于switch对应的信息元素;存储消息采用了StringBuffer,

这些消息都是每一轮的临时消息,但是需要再每一轮结束时都要清空(/pot-win),确保这是最新的一轮最新消息,否则会影响出牌判断。解析消息代码如下

final HashMap<String, Integer> MsgCommand = new HashMap<String, Integer>();
MsgCommand.put("seat/ ", 1);// seat flag
MsgCommand.put("blind/ ", 2);// bind flag
MsgCommand.put("hold/ ", 3);// hold flag
MsgCommand.put("flop/ ", 4);// flop flag
MsgCommand.put("turn/ ", 5);// turn flag
MsgCommand.put("river/ ", 6);// river flag
MsgCommand.put("inquire/ ", 7);// inquire flag
MsgCommand.put("showdown/ ", 8);// showdown flag
MsgCommand.put("pot-win/ ", 9);// pot flag
int ServerCommand;
try {
// Socket link
Socket socket = new Socket(args[0], Integer.parseInt(args[1]),
InetAddress.getByName(args[2]), Integer.parseInt(args[3]));
// OutputStream 向Sever发送注册消息
OutputStream os = socket.getOutputStream();
PrintWriter pw = new PrintWriter(os);
pw.write("reg: " + args[4] + " xsfelvis \n");
pw.flush();
// InputStream 接受Sever的消息
InputStream is = socket.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
// define Msg StringBuffer 存储消息
StringBuffer SeatMsg = new StringBuffer("");
StringBuffer BlindMsg = new StringBuffer("");
StringBuffer CardsMsg = new StringBuffer("");
StringBuffer InquireMsg = new StringBuffer("");
StringBuffer ShowdownMsg = new StringBuffer("");
StringBuffer PotWinMsg = new StringBuffer("");
String info;
String ActMsg;
int Seat_num = 0;
//开始消息解析存储到对应的StringBuffer中
while (true) {
info = br.readLine();// get a line of info
ServerCommand = MsgCommand.get(info);// get hashmap value
switch (ServerCommand) {
case 1: {
while (info != null) {
info = br.readLine();
if (info.equals("/seat "))
break;
Seat_num++;
SeatMsg.append(info);
}
break;
}
case 2: {
while (info != null) {
info = br.readLine();
if (info.equals("/blind "))
break;
BlindMsg.append(info);
}
break;
}
case 3: {
while (info != null) {
info = br.readLine();
if (info.equals("/hold "))
break;
CardsMsg.append(info);
}
break;
}
case 4: {
while (info != null) {
info = br.readLine();
if (info.equals("/flop "))
break;
CardsMsg.append(info);
}
break;
}
case 5: {
while (info != null) {
info = br.readLine();
if (info.equals("/turn "))
break;
CardsMsg.append(info);
}
break;
}
case 6: {
while (info != null) {
info = br.readLine();
if (info.equals("/river "))
break;
CardsMsg.append(info);
}
break;
}
case 7: {
while (info != null) {
info = br.readLine();
if (info.equals("/inquire "))
break;
InquireMsg.append(info);
}
break;
}
case 8: {
while (info != null) {
info = br.readLine();
if (info.equals("/showdown "))
break;
ShowdownMsg.append(info);
}
break;
}
case 9: {
while (info != null) {
info = br.readLine();
if (info.equals("/pot-win "))
break;
PotWinMsg.append(info);
}
break;
}
default:
break;
}
if (info.equals("/inquire ")) {
//出牌算法 核心所在!
ActMsg = Alg(CardsMsg.toString(), InquireMsg.toString(),
args[4], Seat_num);
InquireMsg = new StringBuffer("");
pw.write(ActMsg);
pw.flush();
}
if (info.equals("/pot-win ")) {
Seat_num = 0;
SeatMsg = new StringBuffer("");
BlindMsg = new StringBuffer("");
CardsMsg = new StringBuffer("");
ShowdownMsg = new StringBuffer("");
PotWinMsg = new StringBuffer("");
}
if (info.equals("game-over ")) {
br.close();
isr.close();
pw.close();
os.close();
socket.close();
break;
}
}

} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}


补充:

这里由于Sever每次发送
一串字符串,开头和结尾都有特定的标志,而且都是双方约定好的字符串,因而无需考虑TCP的粘包问题。

3
、算法部分

用一句话总结一下就是“只玩大牌,小牌能check就check,不能则fold”所谓的大牌主要参考了百度一篇《德州扑克最佳技巧》

德州扑克最佳技巧

感觉算法部分不是很好没有做太多的优化,也没有基于对手建立相应的数学模型或者是加入博弈论的知识,就不展示了

详细代码下载
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: