簡單AI之鬥地主電腦出牌C語言實現篇,日常裝逼日常飛,飛到垃圾堆

鬥地主機器出牌核心代碼

簡單AI之鬥地主電腦出牌C語言實現篇,日常裝逼日常飛,飛到垃圾堆

更多精彩,關注私信“代碼”驚喜

運行展示

簡單AI之鬥地主電腦出牌C語言實現篇,日常裝逼日常飛,飛到垃圾堆

更多精彩,關注私信“代碼”驚喜

完整代碼

#define _CRT_SECURE_NO_WARNINGS

#include<stdio.h>

#include<string.h>

#include<stdlib.h>

#include<time.h>

#define Arr_Len(arr) (sizeof(arr)/sizeof(arr[0]))

#define maxn 18

/*

1.出牌方式 以-1結束

一對8的出發:8 8 -1

*/

int cod[maxn] = { 0 };

int mycod[maxn];

int chu[maxn];

int rtmp[maxn] = { 0 }, mtmp[maxn] = { 0 };

int mx, mn;

struct LianD

{

int en; //連對結尾的牌號

int du; //最接近的度數

int cnt; //連對的個數

int tem; //臨時存儲的結尾牌號

//複製值函數

void copfun(struct LianD *Ld){

Ld->cnt = cnt;

Ld->du = du;

Ld->en = en;

Ld->tem = tem;

}

//初始化

void init(){

en = du = cnt = tem = 0;

}

};

enum AlgTyNn{

ShunZi = 1,

LianDui

};

int cmp(const void * arg, const void * brg){

int * ar = (int *)arg;

int * br = (int *)brg;

return *ar - *br;

}

void init(){

int i, hopg, cnt = 0;

memset(mycod, 0, sizeof(mycod));

mycod[cnt] = 17;

for (i = 3; i<16; i++)

cod[i] = 4;

cod[16] = 1; //一對王

cod[17] = 1;

srand(time(NULL));

while (cnt<maxn>

hopg = rand() % maxn;

if (hopg>0 && cod[hopg] > 0){

cod[hopg]--;

mycod[++cnt] = hopg;

}

}

qsort(mycod + 1, cnt - 1, sizeof(mycod - 1), cmp);

}

//對方輸出

void inputs(){

int cnt = 0;

memset(chu, 0, sizeof(chu));

while (1){

scanf("%d", &chu[++cnt]);

if (chu[cnt]<0) break;

}

chu[0] = cnt - 1; //最開頭放置紙牌的數目

}

//打印剩餘

void output(){

printf("\n 剩牌系: \n");

//剩餘牌系

int cont = 0;

for (int j = 3; j<maxn>

cont += mtmp[j];

for (int k = 0; k<mtmp>

printf("%d ", j);

}

}

mtmp[0] = cont;

printf("\t剩牌數: [ %d ]", mtmp[0]);

puts("");

}

//計數排序

void connt(int *tmp, const int ss[]){

//memset(tmp ,0 ,sizeof(tmp));

tmp[0] = ss[0];

for (int i = 1; i <= ss[0]; i++)

tmp[ss[i]]++; //計數排序

}

//判斷是否有炸彈或者王炸

void ZhaDan(){

for (int i = 3; i<maxn>

if (mtmp[i] == 4){

printf("%d %d %d %d ", i, i, i, i);

mtmp[i] -= 4;

output();

return;

}

if (mtmp[16] == 1 && mtmp[17] == 1){

printf("%d %d ", 16, 17);

mtmp[16] = mtmp[17] = 0;

output();

return;

}

puts("沒有牌能壓過!");

return;

}

//如果是連對處理方案

void AlgLDOrShZi(int var){

int i = mn + 1, len = mx - mn + 1, kk = 0;

struct LianD Ld, Tmpld;

Ld.init();

//時間複雜度為0(n^2)

for (i = mn + 1; i<15; i++){

Tmpld.init();

Tmpld.tem = i;

for (int j = i; j

if (mtmp[j] >= var){

if (mtmp[j] == var){

Tmpld.du++;

}

Tmpld.cnt++;

}

else{

Tmpld.init();

Tmpld.tem = j + 1;

}

if (Tmpld.cnt == len){

Tmpld.en = Tmpld.tem;

if (Ld.en == 0 || Ld.du<tmpld.du>

Tmpld.copfun(&Ld);

break;

}

}

}

if (Ld.cnt == len){

puts("提示:");

for (i = Ld.en; i<ld.en>

mtmp[i] -= var;

kk = 0;

while (kk++

printf("%d ", i);

}

output();

}

else{

//尋求炸彈或者王炸

ZhaDan();

}

}

//三帶的處理情況

void AlgShanDai(){

int pos = 0, cnt = 0, res = 0, fcnt = 0;

int mcnt = 0, mpos = 0;

//分析牌型

for (int i = mn; i <= mx; i++){

if (rtmp[i] == 3){

pos = i;

cnt++;

}

else if (rtmp[i]>0){

res += rtmp[i]; //統計剩餘牌的數量

fcnt++;

}

}

if ((fcnt == cnt&&res%cnt == 0) || (fcnt

else{

puts("輸出的牌不符合規則!請重新輸出:");

return;

}

res /= cnt;

for (int i = pos - cnt + 2; i <= pos; i++){

if (rtmp[i] != 3){

puts("輸出的牌不符合規則!請重新輸出:");

return;

}

}

//如果為三帶情況 即 cnt =1

for (int i = pos - cnt + 2; i<17; i++){

if (mtmp[i] == 3){

mpos = i;

mcnt++;

}

else

mcnt = 0;

if (mcnt == cnt) break;

}

//查詢副牌是否能夠滿足

if (mcnt == cnt){

//說明有解決方案

int stpos = mpos - cnt + 1;

int src[maxn] = { 0 }, tt = 0;

bool tag = false;

for (int i = 3; i<17; i++){

//滿足不再連續範圍之內的即可333444不能為3,4

if (i<stpos>mpos){/<stpos>

if (mtmp[i] >= res){

for (int kk = 0; kk<mtmp>

src[tt++] = i;

if (tt == cnt){

tag = true;

break;

}

}

}

}

if (tag) break;

}

if (tt == cnt){

//則解決方案為

int mstpos = mpos - cnt + 1;

for (int i = mstpos; i <= mpos; i++){

printf("%d %d %d ", i, i, i);

mtmp[i] -= 3;

}

//打印副牌

for (int i = 0; i

for (int k = 0; k

printf("%d ", src[i]);

}

mtmp[src[i]] -= res;

}

output(); //打印剩餘牌

}

}

else{

//查詢是否有炸彈

ZhaDan();

}

}

//四帶情況

void AlgSiDai(){

if (chu[0]>4) ZhaDan();

else{

for (int i = chu[1] + 1; i<15; i++){

if (mtmp[i] == 4){

printf("%d %d %d %d ", i, i, i, i);

mtmp[i] -= 4;

output();

return;

}

}

if (mtmp[16] == 1 && mtmp[17] == 1){

printf("%d %d ", 16, 17);

mtmp[16] = mtmp[17] = 0;

output();

return;

}

puts("沒有牌能壓過!");

return;

}

}

//對子的情況

void AlgDuiZi(){

for (int i = chu[1] + 1; i<16; i++)

{

if (mtmp[i]>1 && mtmp[i]<4){

printf("%d %d \n", i, i);

mtmp[i] -= 2;

output();

return;

}

}

ZhaDan();

}

//對於個子的情況

void AlgGreZi(){

for (int i = chu[1] + 1; i<18; i++)

{

if (mtmp[i]>0 && mtmp[i]<4){

printf("%d \n", i);

mtmp[i] -= 1;

output();

return;

}

}

ZhaDan();

}

//查詢對應的方案

//對子

bool IsDuiZi(){

if (chu[0] == 2) //則必定是對子

return true;

return false;

}

//個子

bool IsGreZi(){

if (chu[0] == 1) //則必定是對子

return true;

return false;

}

//判斷是否是順子

bool IsShunZi(){

//順子的條件

if (chu[0]>4){

if ((mx - mn + 1 == chu[0]) && mx<15)

return true;

}

return false;

}

//判斷是否是連對

bool IsLianDui(){

if (chu[0]>5 && mx<15){

for (int i = mn; i <= mx; i++)

if (rtmp[i] != LianDui)

return false;

return true;

}

return false;

}

//判斷是否是三帶

bool IsShanDai(){

for (int i = mn; i <= mx; i++)

if (rtmp[i] == 3)

return true;

return false;

}

//判斷是否是四帶或者炸彈

bool IsSiDai(){

for (int i = mn; i <= mx; i++)

if (rtmp[i] == 4)

return true;

return false;

}

//統計判斷

void AlgMxn(){

//求最大值,最小值

for (int i = 3; i <= 17; i++)

if (rtmp[i]>0){

mn = i;

break;

}

for (int i = 17; i >= 3; i--)

if (rtmp[i]>0){

mx = i;

break;

}

}

void print(){

int i;

for (i = 1; i<17; i++)

printf("%d ", mycod[i]);

printf("%d\n", mycod[17]);

}

//檢測出牌方

bool checked(){

for (int i = 1; i<maxn>

if (cod[i]<rtmp>

return false;

}

if (IsGreZi()

|| IsDuiZi()

|| IsShunZi()

|| IsSiDai()

|| IsShanDai()){

for (int i = 1; i <= chu[0]; i++){

cod[chu[i]]--;

}

}

return true;

//如果為一對王

if (chu[0] == 2 && mtmp[16] == 1 && mtmp[17] == 1)

return true;

return false;

}

int main(int argc, char * argv)

{

init();

memset(mtmp, 0, sizeof(mtmp));

connt(mtmp, mycod);

print();

while (true){

printf("請出牌:\n");

while (1){

inputs();

memset(rtmp, 0, sizeof(rtmp));

connt(rtmp, chu);

AlgMxn();

if (checked()) break;

else

puts("輸出的牌不符合規則!請重新輸出:");

}

//如果滿足順子

if (IsGreZi())

AlgGreZi();

else

if (IsDuiZi())

AlgDuiZi();

else

if (IsShunZi())

AlgLDOrShZi(ShunZi);

else

if (IsLianDui())

AlgLDOrShZi(LianDui); //對於連對的情況

else

if (IsShanDai())

AlgShanDai();

else

if (IsSiDai())

AlgSiDai();

if (mtmp[0]<1){

puts("恭喜你,win!");

break;

};

}

return 0;

}

/<rtmp>

/<maxn>

/<mtmp>

/<ld.en>

/<tmpld.du>

/<maxn>

/<mtmp>

/<maxn>

/<maxn>


分享到:


相關文章: