標籤:華為
概述
華為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 linkSocket socket = new Socket(args[0], Integer.parseInt(args[1]),InetAddress.getByName(args[2]), Integer.parseInt(args[3]));// OutputStreamOutputStream 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 flagMsgCommand.put("blind/ ", 2);// bind flagMsgCommand.put("hold/ ", 3);// hold flagMsgCommand.put("flop/ ", 4);// flop flagMsgCommand.put("turn/ ", 5);// turn flagMsgCommand.put("river/ ", 6);// river flagMsgCommand.put("inquire/ ", 7);// inquire flagMsgCommand.put("showdown/ ", 8);// showdown flagMsgCommand.put("pot-win/ ", 9);// pot flagint ServerCommand;try {// Socket linkSocket 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 infoServerCommand = MsgCommand.get(info);// get hashmap valueswitch (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”所謂的大牌主要參考了百度一篇《德州撲克最佳技巧》
德州撲克最佳技巧
感覺演算法部分不是很好沒有做太多的最佳化,也沒有基於對手建立相應的數學模型或者是加入博弈論的知識,就不展示了
詳細代碼下載
著作權聲明:本文為博主原創文章,未經博主允許不得轉載。
德州撲克 2015 華為軟體精英挑戰賽