写在前面(由于本人对知识产权法律常识的欠缺,不知道写类型的开发经验与原理是否侵权):
如果涉及到侵犯网狐公司权益,请优快云删帖,请勿公开,谢谢。
德州扑克机器人功能,我介绍的有点零散,只是开发时代经验。
一.文件介绍
下面几个文件主要添加机器人功能时用到
AndroidUserItemSink.h
AndroidUserItemSink.cpp
---------------类CAndroidUserItemSink
(文件名望文生义:机器人用户条目陷阱)
作用:与机器人相关的事件会落到该陷阱中,该陷阱内设有响应机制,触发相应的动作,发送传递消息等。
GameLogic.h
GameLogic.cpp
---------------类CGameLogic
(游戏逻辑文件)
作用:定义游戏的扑克数量、游戏玩法规则、牌型比较、牌值大小等功能
TableFrameSink.h
TableFrameSink.cpp
----------------类CTableFrameSink
(桌子框架陷阱)
作用:游戏桌面相关的事件都逃不出这个陷阱,该陷阱内设有响应机制,触发相应的动作,发送传递消息等。
CMD_DZShowHand.h
(消息定义文件)
作用:定义客户端与服务端通讯格式预订,常量定义等
下面第四条,类CAndroidUserItemSink与CTableFrameSink 数据传送做了举例说明。
二.机器人实现原理
CAndroidUserItemSink类,获取游戏场景消息。
包括游戏开始、用户加注、用户放弃、发牌消息、游戏结束等。
捕获此类消息后,
一种通过调用定时器处理函数实现相应动作。
另一种在捕获消息后,通过相应动作函数实现预期动作,在该动作函数中调用了定时器处理函数。
我们的机器人实现是通过后一种实现的。动作处理函数要获取许多预知的数据条件。
动作处理函数需要逻辑类CGameLogic的支持,逻辑类里在CAndroidUserItemSink类中被实例化了为m_GameLogic,即逻辑接口。
具体实现:
策划提出的机器人实现方案,主要是对牌型的判断决定机器人动作。现实中人的出牌出了对牌型的判断外,还有对对手玩家性格与局势的观察、一些细节等综合决定下注等动作,需要玩几轮积累经验。
但机器人不可能做到人的经验积累。
把机器人动作触发事件主要有:
1)游戏开始
首轮开始,机器人判断是否为当前玩家,如果是,机器人根据手牌牌型与牌值,决定下注或放弃情况。下注值的参考的几个基本数据与牌值。类CTableFrameSink会传来。
2)用户加注
前一人下注后,机器人判断是否是当前玩家,如果是,机器人同样按牌型与牌值,并参考桌面上是否有公牌存在,如果公牌没发,即按游戏开始的情况一致下注。
如果有公牌,判断公牌是3 、4 、5几张?
通过手牌与公牌的组合,选出最佳牌型,参考牌值、桌面注额,进行下注。
3)发牌消息
发公牌后机器判断自己是否为当前玩家,如果是,判断公牌数量,组合出最佳牌型,参考桌面注额与当前第几轮发牌决定下注。
三.机器人实现代码添加说明,以下是我的代码实现代码构架片段,大家如果感兴趣就看看,不能公布详细代码很抱歉。
1. AndroidUserItemSink.h
主要在机器人类中添加了需要获知的数据变量 与 实现具体功能的函数
//机器人类
class CAndroidUserItemSink
//游戏变量
protected:
BYTE m_cbHandCard[MAX_COUNT]; //用户手牌
BYTE m_cbCardType; //牌类型
BYTE cbFirstValue; //手牌值
BYTE cbSecondValue; //手牌值
//机器人动作
protected:
bool PreFlopAction(); //底牌权/前翻牌圈
bool FlopRoundAction(); //翻牌圈
bool TurnRoundAction(); //转牌圈
函数定义详细见AndroidUserItemSink.cpp
2. AndroidUserItemSink.cpp
主要增加了需要添加动作的定时器(如下),以及在OnEventTimer()函数中定义动作定时器的消息发送细节。以及对AndroidUserItemSink.h中 机器人动作函数的实现。
#define IDI_USER_ADD1_GOLD //加倍注定时器
#define IDI_USER_ADD2_GOLD //加倍注定时器
#define IDI_USER_FOLLOW_GOLD //跟注定时器
#define IDI_USER_PASS //过牌定时器
#define IDI_USER_SHOW_HAND //梭哈定时器
//时间消息
bool __cdecl CAndroidUserItemSink::OnEventTimer(UINT nTimerID)
3. GameLogic.h
增加所要用的扑克类型:
//扑克类型
#define HCT_SINGLE 11 //手牌单类型
#define HCT_PAIR 12 //手牌对类型
#define HCT_WILL_STRAIGHT 13 //手牌小顺类型
#define CT_LESS_STRAIGHT 14 //差一张顺子类型
增加函数:
//获取手牌类型
BYTE GetHandCardType();
//获取手牌+翻牌圈牌类型
BYTE GetFlopRoundCardType( );
//6返 获取手牌+转牌圈牌类型中最大牌型 BYTE FiveFromSix();
4. GameLogic.cpp
主要添加了对GameLogic.h文件中 添加函数的定义。
5. TableFrameSink.cpp
未增加新代码。
四.类CAndroidUserItemSink 与 类CTableFrameSink 通讯 简述
两个类之间是紧密联系,相互通讯。可以把类CAndroidUserItemSink看做是一个没有显示功能的游戏客户端。
下面只写文件名,相应的类名同过看文件名也能了解。
以开始游戏时代数据传输为例介绍:
TableFrameSink.cpp
//游戏开始
TableFrame.cpp
//发送数据
AttemperEngineSink.cpp
//发送数据
AndroidUserManager.cpp
//发送数据
AndroidUserItem.cpp
//网络消息
//游戏消息
AndroidUserItemSink.cpp
//游戏消息
//游戏开始
以下为详细代码片段:
TableFrameSink.cpp
//游戏开始
bool __cdecl CTableFrameSink::OnEventGameStart()
m_pITableFrame->SendTableData(i,SUB_S_GAME_START,&GameStart,sizeof(GameStart));
TableFrame.cpp
//发送数据
bool __cdecl CTableFrame::SendTableData(WORD wChairID, WORD wSubCmdID, void * pData, WORD wDataSize)
m_pIGameServiceFrame->SendData(m_pIUserItem[wChairID],MDM_GF_GAME,wSubCmdID,pData,wDataSize);
AttemperEngineSink.cpp
//发送数据
bool __cdecl CAttemperEngineSink::SendData(IServerUserItem * pIServerUserItem, WORD wMainCmdID, WORD wSubCmdID, void * pData, WORD wDataSize)
m_AndroidUserManager.SendDataToClient(dwID,wMainCmdID,wSubCmdID,pData,wDataSize);
AndroidUserManager.cpp
//发送数据
bool __cdecl CAndroidUserManager::SendDataToClient(DWORD dwAndroidID, WORD wMainCmdID, WORD wSubCmdID, VOID * pData, WORD wDataSize)
if (pAndroidUserItem->OnSocketRead(wMainCmdID,wSubCmdID,pData,wDataSize)==false)
AndroidUserItem.cpp
//网络消息
bool CAndroidUserItem::OnSocketRead(WORD wMainCmdID, WORD wSubCmdID, VOID * pData, WORD wDataSize)
//游戏消息
if ((wMainCmdID==MDM_GF_GAME)||(wMainCmdID==MDM_GF_FRAME))
{
return OnSocketGameMessage(wMainCmdID,wSubCmdID,pData,wDataSize);
}
//游戏消息
bool CAndroidUserItem::OnSocketGameMessage(WORD wMainCmdID, WORD wSubCmdID, VOID * pData, WORD wDataSize)
return m_pIAndroidUserItemSink->OnEventGameMessage(wSubCmdID,pData,wDataSize);
AndroidUserItemSink.cpp
//游戏消息
bool __cdecl CAndroidUserItemSink::OnEventGameMessage(WORD wSubCmdID, void * pData, WORD wDataSize)
switch (wSubCmdID)
{
case SUB_S_GAME_START: //游戏开始
{
return OnSubGameStart(pData,wDataSize);