博主17年開始從事棋牌遊戲開發,開始接觸賴子算法時,當時互聯網找不到任何資料,於是自己琢磨了三天開始寫出第一個算法,到目前爲止已經自己寫過三款不同的賴子算法,分別爲:
1. 遞歸法 (<1ms級 , 複雜度爲:最好O(n),最差O(n^3) )
2.優化型遞歸法代入法 ( us級 , 複雜度爲:最好O(n),最差O(n^2) )
3 查表法 (us級 , 複雜度爲:O(1) )
以上所有版本均支持多賴子,哪怕手牌是23張,全是賴子,均不影響複雜度,差異甚小
在徵得源項目老闆的同意下,分享第一種算法給遊戲愛好者們學習與進步,廢話少說,直接上代碼如下:
-----------------------------------------------------------------------------------------------------------------------
//會牌核心算法遞歸版本, 由原胡牌算法演進而來,檢測更全面 by iori 2017/1/10
bool laizi_hupai_base(int *pi_mj, int i_num, int *pi_select,int laizi_val)
{
//pi_select[]用於在遞歸調用時記錄已經訪問過的牌
int i,j,k;
int i_max,i_min,i_mid;
int i_mark1,i_mark2;
int i_have3=0 ,laizi_num = 0;
for(i=0; i<i_num; i++)
{
if( pi_select[i] )
continue;
else
i_mark1 = i;
for( j=i+1; j<i_num; j++)
{
if( i == j )
continue;
if(pi_select[j])
continue;
else
i_mark2 = j;
for( k=j+1; k<i_num; k++)
{
if( i==k || j==k )
continue;
if( pi_select[k] )
continue;
i_have3 = 1;
laizi_num = 0;
i_max = std::max(pi_mj[i], std::max(pi_mj[j], pi_mj[k]));
i_min = std::min(pi_mj[i], std::min(pi_mj[j], pi_mj[k]));
i_mid = (i_max + i_min) / 2;
//判斷選中的是否爲賴子,這裏傳入多個val,可以支持多賴
if (pi_mj[i] == laizi_val) laizi_num++;
if (pi_mj[j] == laizi_val) laizi_num++;
if (pi_mj[k] == laizi_val) laizi_num++;
if (laizi_num >= 2) //能成有會刻或者順,默認刻
{
// do something 根據你的項目需求可以保存數據
}
else
if( (pi_mj[i] == pi_mj[j] && pi_mj[i] == pi_mj[k]) || (laizi_num == 1 && (pi_mj[i] == pi_mj[j] || pi_mj[j] == pi_mj[k] || pi_mj[i] == pi_mj[k])) ) //表示能組成刻子
{
// do something
}
else if (laizi_num == 1)//判斷是否能成有會順
{
if(pi_mj[i] == laizi_val)
{
if(pi_mj[j] - pi_mj[k] != -1 && pi_mj[j] - pi_mj[k] != -2 && pi_mj[j] - pi_mj[k] != 1 && pi_mj[j] - pi_mj[k] != 2 )
continue;
//這裏根據項目不同的牌值區分 中發白與風牌過濾掉,博主這個項目沒有,就不補上了
}else if(pi_mj[j] == laizi_val)
{
if(pi_mj[i] - pi_mj[k] != -1 && pi_mj[i] - pi_mj[k] != -2 && pi_mj[i] - pi_mj[k] != 1 && pi_mj[i] - pi_mj[k] != 2 )
continue;
}else if(pi_mj[k] == laizi_val)
{
if(pi_mj[i] - pi_mj[j] != -1 && pi_mj[i] - pi_mj[j] != -2 && pi_mj[i] - pi_mj[j] != 1 && pi_mj[i] - pi_mj[j] != 2 )
continue;
}
}else
if( i_max-i_min == 2 && ( pi_mj[i] == i_mid || pi_mj[j] == i_mid || pi_mj[k] == i_mid)) //表示能組成順子
{
// do something
}else
continue;
//記錄下來 下面遞歸
pi_select[i] = pi_select[j] = pi_select[k] = 1;
if( !laizi_hupai_base(pi_mj, i_num, pi_select,laizi_val) )
{
pi_select[i] = pi_select[j] = pi_select[k] = 0; //遞歸一次結束,返回
continue;
}
//選擇的3張成刻、順,而剩下的和了
return true;
}
//只剩兩張牌, 相等 或者 其中一張爲癩子時,滿足牌型
if( (i_have3 == 0) &&( pi_mj[i_mark1] == pi_mj[i_mark2] || pi_mj[i_mark1] == laizi_val || pi_mj[i_mark2] == laizi_val ))
{
return true; //這裏不退出,可以保存下來計算出所有能胡的牌型
}
}
}
return false;
}
------------------------------------------------------------------ end by Iori
算法好不好,跑一跑就知道,打上time log就明瞭,如有疑問,歡迎留言,支持原創,支持開源,如有轉載,請與博主聯繫授權 !