SDL2 游戏开发日记(九) 单机麻将
单机麻将的基本功能其实年前已经完成了,只是写文档麻烦,再加上懒癌和重度拖延症,就一直拖着没更新。今天周末一个人没什么事干,抽空把它更新了。
麻将的表示
用数组表示,int card[136];值分别是 0-135;
值/4
0-8:表示万,9-17:表示饼,18-26:表示条,27-33:表示东南西北中发白
class MahjongCard : public Renderable{
private :
int mCardNumber; //牌值,0-135
bool mIsSelected; //是否被选中的状态,玩家鼠标选择出牌时用
Vector2I mOffset; //选中后的位置偏移量,鼠标选择出牌时用
public :
void SetCardNumber(int cardNumber){
mCardNumber = cardNumber;
}
int GetCardNumber(){
return mCardNumber;
}
bool IsSelected(){
return mIsSelected;
}
void SetSelected(bool bSelected){
mIsSelected = bSelected;
}
void SetOffset(int xOffset, int yOffset){
mOffset.x = xOffset;
mOffset.y = yOffset;
}
Vector2I &GetOffset(){
return mOffset;
}
};
麻将算法
分为胡牌算法和出牌ai
胡牌算法:声明一个辅助数组 int cardAssists[38],用0填充。如果是判断自摸,则遍历手上的牌并根据index的值填充辅助数组。如果是判断吃胡,则遍历手上的牌和最后一张打出的牌。并根据index的值填充辅助数字。
index = 具体的牌值/4:如果值小于等于8,cardAssists[index+1] ++;即cardAssists数组的1-9表示万,
如果index的值大于等于9并且小于等于17,cardAssists[index+2] ++;即11-19表示饼
如果index的值大于等于18并且小于等于26,cardAssists[index+3]++;即21-29表示条。
如果index的值大于等于27,cardAssists[index+4] ++;即31-37表示字牌。
class MahjongAI{
//递归调用
bool IsHu(){
int sum = 0;
for (int i = 0; i < 38; i++){
sum += mCardAssistArray[i];
}
if (sum == 0){
//匹配完了,如果有找到将牌,表示可以胡牌了。
if (mIsFindJiang)
return true;
else return false;
}
int index = 0;
//跳过没有的牌
for (index = 0; index < 38 && mCardAssistArray[index] == 0; index++);
//如果是一刻,把这一刻去掉
if (mCardAssistArray[index] >= 3){
mCardAssistArray[index] -= 3;
//再判断剩下的牌是否胡牌。
if (IsHu()){
return true;
}
//没有胡牌,把这一刻加回去
mCardAssistArray[index] += 3;
}
//如果是一对,并且还未找到将牌,
if (mCardAssistArray[index] >= 2 && !mIsFindJiang){
mIsFindJiang = true;
mCardAssistArray[index] -= 2;
//去掉,并判断剩下的牌能不能胡
if (IsHu()){
return true;
}
mIsFindJiang = false;
//不能胡,加回去
mCardAssistArray[index] += 2;
}
//索引大于30的不判断顺子
if (index > 30)
return false;
//判断如果能组成顺子,把顺子牌拿掉,
if (mCardAssistArray[index + 1] >= 1 && mCardAssistArray[index + 2] >= 1){
mCardAssistArray[index] --;
mCardAssistArray[index + 1] --;
mCardAssistArray[index + 2] --;
//判断剩下的牌能不能胡牌
if (IsHu()){
return true;
}
//不能胡牌,加回数组中
mCardAssistArray[index] ++;
mCardAssistArray[index + 1] ++;
mCardAssistArray[index + 2] ++;
}
return false;
}
}
出牌ai:判断有没有单独的字牌和单独的牌->拆掉那些不是对子并且不是顺子的牌->判断最佳的听牌组合->经过上面的方法还选不出来该出的牌?那就随机出牌。
MahjongCard *MahjongAI::GetBestOutCard(){
MahjongCard *card = NULL;
QueryInCards();
vector<MahjongCard*> randomCardList,allCardList;
CardMap &inHandcard = mPlayer->GetInHandCard();
printf("inhandcard size:%d\n",inHandcard.size());
CardMap::reverse_iterator iter = inHandcard.rbegin();
while (iter != inHandcard.rend()){
int cardIndex = GetCardIndex(iter->second);
if (cardIndex > 30){
if (mCardAssistArray[cardIndex] == 1){
//printf("单独的字牌:%d\n", cardIndex);
randomCardList.push_back(iter->second);
}
}
else{
if (mCardAssistArray[cardIndex] == 1){
if (mCardAssistArray[cardIndex - 1] == 0 && mCardAssistArray[cardIndex+1] == 0){
//printf("单独的牌:%d\n", cardIndex);
randomCardList.push_back(iter->second);
}
}
}
allCardList.push_back(iter->second);
iter++;
printf("%d,",cardIndex);
}
printf("\n");
if (randomCardList.size() == 0){
printf("不知道打什么牌1:进一步选择");
while (iter != inHandcard.rend()){
int cardIndex = GetCardIndex(iter->second);
if (cardIndex > 30){
break;
}
else{
if (mCardAssistArray[cardIndex] == 1){
if (mCardAssistArray[cardIndex - 1] >= 1 && mCardAssistArray[cardIndex + 1] >= 1){
iter++;
continue;
}
else if (mCardAssistArray[cardIndex + 1] >= 1 && mCardAssistArray[cardIndex + 2] >= 1){
iter++;
continue;
}
else{
if (cardIndex % 10>2){
if (mCardAssistArray[cardIndex - 2] >= 1 && mCardAssistArray[cardIndex - 1] >= 1){
iter++;
continue;
}
}
}
card = iter->second;
printf(":%d\n", GetCardIndex(card));
break;
}
}
}
}
else{
int index = rand() % randomCardList.size();
card = randomCardList[index];
}
if (card == NULL){
printf("进一步选择失败,判断ting\n");
int assistArray[38];
int bestIndex = -1, bestTingCount = -1;
for (int i = 0; i < 38; i++){
if (mCardAssistArray[i] == 0)
continue;
mCardAssistArray[i] --;
memcpy(assistArray, mCardAssistArray, sizeof(assistArray));
int tingCount = TingCount(assistArray);
if (tingCount > 0){
printf_s("Ting:%d,cardIndex:%d\n",tingCount,i);
if (tingCount > bestTingCount){
bestTingCount = tingCount;