鬥地主機器出牌核心代碼
運行展示
完整代碼
#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>閱讀更多 C語言基礎 的文章