#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; j++){
cont += mtmp[j];
for (int k = 0; k<mtmp[j]; k++){
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; 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 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<i + len; 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 + len; i++){
mtmp[i] -= var;
kk = 0;
while (kk++<var)
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<cnt && (fcntres == cnt || 0 == res)));
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 || i>mpos){
if (mtmp[i] >= res){
for (int kk = 0; kk<mtmp[i]; kk += res){
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<tt; i++){
for (int k = 0; k<res; 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; i++){
if (cod[i]<rtmp[i])
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;
}