C语言实现斗地主游戏

我们先来实现主函数部分:

#include <windows.h>
#include <stdio.h>
#include <conio.h>
#include <string.h>
#include <dos.h>
#include <math.h>
#include <time.h>
#include <stdlib.h>

#define CLS system("cls")
#define PUS system("pause")
#define CLR system("color 0f")
#define PR printf
#define SC scanf
#define UNDEALT_PUKER -32 
#define EMPTY_CARD 63
#define GET fgets(FC,32,fp);sscanf

void gotoxy(HANDLE HDO, int x, int y);
void printSmallPuker(int who, int n);
void getClientInfo();
void printPuker();
void AI(int who);
void initial();
void deal();
void _deal();
void over();
void clearInfo();
int home();
int play();
int AIplay();
int getMouseEvent();
int daipai(int n, int cmd[32]);
int shunzi_liandui(int n, int cmd[32]);
int isTherePuker(int special, int n, int cmd[32]);
int comparePuker(int recSpecial, int special, int recN, int n, int rec[32], int cmd[32]);

char fBuffer[64];	
char space[32] = "  ";
char color[9] = "*&#%";
char table[16] = "3456789XJQKA2RR";
char playerLevel[8];	//玩家等级
char playerName[16];	//玩家名字
char player1[16];		//电脑名字
char player2[16];		//电脑名字
char consoleColor[32];	//窗口颜色
char consoleTitle[32];	//窗口标题
char dt[16];	//登录校验
char cd[64];	//存档校验
char FC[32];	//文件内容 fileContent
char LED[512];	//主页滚动显示
int col, line;	//窗口大小
int basis;		//底分
int extra[3];	//三张底牌
int LEDlength;	//主页 LED 数组长度
int AIcmdNum;	//AIcommandNumber,存储 AI 出牌数量用于打印,
int AIcmd[32];	//AIcommand,存储 AI 出的牌
int mouse[2];	//鼠标坐标
int mark;		//分数
int quit;
int atHome;

typedef struct{
	int num;   //扑克点数:0->12分别代表3->2,13为王
	int color; //花色:0 ?,1 ?,2 ?,3 ?.
	int owner; //归属,0为未发放
} puker_property;
typedef struct{
	int card[20]; //持有的牌
	int num;	  //扑克牌数
	int rank;	 //总赢盘数
	int isOver;   //是否已结束
} player_property;
typedef struct{
	int turn;		//回合统计
	int basis;		//回合倍数
	int who;		//出牌权
	int special;	//回合特殊牌型
	int record[3][32];	//农民玩家上回合记录
	int isPass[3];		//玩家是否出过牌
	int color;		//最后一张牌的花色,纯属用于装饰
	int hasPrinted;	//是否打印完成,用于防止循环不出
}pass_property;

puker_property puker[64];
player_property player[3];
pass_property pass;

INPUT_RECORD inRec;		// 返回数据记录 
DWORD numRead;			// 返回已读取的记录数
HANDLE HDO = GetStdHandle(STD_OUTPUT_HANDLE);	// 获得标准输出设备句柄
HANDLE HDI = GetStdHandle(STD_INPUT_HANDLE); 	// 获取标准输入设备句柄
HWND hwnd = FindWindow("ConsoleWindowClass", NULL); 	// 控制台窗口句柄 
COORD position;			// 存储使用Windows API获取的坐标。由于后面开始游戏那里要点击,所以定义为全局变量	
COORD size = {100, 32};	// 存储窗口大小

void gotoxy(HANDLE HDO, int x, int y) {		//光标转移
	position.X = x;
	position.Y = y;
	SetConsoleCursorPosition(HDO, position);
}
/*************	存档读取	**************/
void getClientInfo() {
	FILE *fp;	// 读取显示配置文件,具体参照 ACM 上的实验报告十三
    if ((fp = fopen("Data/client.ini", "r")) == NULL) { PR("存档丢失或被破坏, 请拷贝新存档或自己作假一个存档!\n"); PUS; exit(0); }
	GET(FC, "dt %s", dt);	// 读取登录校验
	GET(FC, "cd %s", cd);	// 读取存档校验
	GET(FC, "buffer %s", fBuffer);	// 缓冲行
	GET(FC, "player1 %s", player1);	// 电脑 1 的名字
	GET(FC, "player2 %s", player2); // 电脑 2 的名字
	fgets(consoleColor, 32, fp);		// 颜色属性
	GET(FC, "playerName %s", playerName);	// 玩家名字
	GET(FC, "basis %d", &basis);	// 底分
	GET(FC, "title %s", consoleTitle);	// 窗口标题
	fclose(fp);		// 关闭文件
	SetConsoleTitle(consoleTitle);	// 设置窗口标题
	SetConsoleScreenBufferSize(HDO, size);	// 设置缓冲区大小
	mark = atoi(cd);
	if (strlen(playerName) > 16 || strlen(player1) > 16 || strlen(player2) > 16) {
		CLS; PR("\n\t注意:\n\t有玩家的名字过长。请重新设置名字,使其小于八个汉字。\n\t");
		PR("Length of nick exceeds the limit. Reset to control within 16 Bytes.\n\t");
		PUS; exit(0);
	}
	if (basis > 1000 ) {
		CLS; PR("\n\t注意:\n\t底分过高。为创造良好的游戏体验,请调低底分。\n\t");
		PR("Base score exceeds limit. Please lower it. \n\t");
		PUS; exit(0);
	}
}
/*************	游戏初始化	**************/
void initial() {
	int i, j;
	CONSOLE_CURSOR_INFO cursor_info = {1, 0};	// 定义一个光标结构体
	SetConsoleCursorInfo(HDO, &cursor_info);	// 隐藏控制台光标
	getClientInfo();	//读取存档
	//初始化扑克牌
	for (i = 0; i < 13; i++)	
		for (j = 0; j < 4; j++) {
			puker[i * 4 + j].num = i;
			puker[i * 4 + j].color = j;
			puker[i * 4 + j].owner = UNDEALT_PUKER;
		}
	puker[53].num = 14;		// 大王赋值
	puker[52].num = 13;		// 小王赋值
	puker[53].color = puker[52].color = 0;
	puker[53].owner = puker[52].owner = UNDEALT_PUKER;	// 出过的、没发的牌都标记为 UNDEALT_PUKER
	puker[EMPTY_CARD].num = UNDEALT_PUKER;	// 空牌指定的位置也标记为 UNDEALT_PUKER
	//初始化玩家
	for (i = 0; i < 3; i++) {	
		player[i].num = 0;
		player[i].rank = 0;
		player[i].isOver = 0;
		for (j = 0; j < 20; j++)
			player[i].card[j] = EMPTY_CARD;
	}
	//初始化出牌全局变量
	pass.who = 0;
	pass.turn = 0;
	pass.basis = 1;
	pass.special = 0;
	pass.hasPrinted = 0;
	for (i = 0; i < 3; i++) {
		for (j = 0; j < 32; j++) pass.record[i][j] = EMPTY_CARD;		
		pass.isPass[i] = 0;
	}
}
/****************	自动发牌	***************/
void deal() {
	int i = 0, j, rnd = 0, temp;
	system(consoleColor);
	srand((unsigned)time(NULL));
	for (; i < 3; i++) {	//抽出三张底牌
		rnd = rand() % 54;
		while (puker[rnd].owner != UNDEALT_PUKER) rnd = rand() % 54;
		puker[rnd].owner = 0;
		extra[i] = rnd;
		PR("%d \n", extra[i]);
	}
	for (i = 0; i < 54; i++) {	//发掉所有牌
		if (puker[i].owner == UNDEALT_PUKER) {
			rnd = rand() % 3;	// 产生 [0,3) 的随机整数
			while (player[rnd].num > 16) rnd = rand() % 3; // 若该玩家牌满,则重新选择牌主
			puker[i].owner = rnd;
			player[rnd].card[player[rnd].num] = i;
			player[rnd].num++;
		} else continue;
	}
	for (i = 0; i < 3; i++) {	//将三张牌赋给地主
		player[0].card[17 + i] = extra[i];
		player[0].num++;
	}
	for (i = 0; i < 19; i++)	//冒泡理牌,大->小
		for (j = 0; j < 19 - i; j++) // j开始等于0,
			if (player[0].card[j] > player[0].card[j + 1]) {
				temp = player[0].card[j];
				player[0].card[j] = player[0].card[j + 1];
				player[0].card[j + 1] = temp;
			}
	printPuker();
}
/****************	调试发牌	***************/
void _deal() { int i = 0, rnd = 0; for (i = 0; i < 54; i++) { rnd = i > 19 ? i > 36 ? 2 : 1 : 0; puker[i].owner = rnd; player[rnd].card[player[rnd].num] = i; player[rnd].num++; } printPuker(); } // 只在调试环境下作用!
char levelStandard[23][7] = {"包身工","短工","长工","佃户","贫农","渔夫","猎人","中农","富农","掌柜","商人","衙役","小财主","大财主","小地主","大地主","知县","通判","知府","总督","巡抚","丞相","帝王"};
int  standard[23] = {0,1000,2500,4000,8000,14000,23000,36500,50000,70000,100000,150000,220000,300000,400000,550000,770000,1000000,1400000,2000000,3000000,4500000,7000000};
/****************	打印手牌	****************/
void printPuker() {
	CLS;
	char joker[4] = "王";
	char ch;
	int i = 0, j;
	int place;
	//-------=======	打印3张牌	======------//
	gotoxy(HDO, 0, 0); 
	PR("%35s┏━━┓┏━━┓┏━━┓\n", space);
	PR("%35s┃    ┃┃    ┃┃    ┃\n", space);
	PR("%35s┃    ┃┃    ┃┃    ┃\n", space);
	PR("%35s┃    ┃┃    ┃┃    ┃\n", space);
	PR("%35s┗━━┛┗━━┛┗━━┛", space);
	for (j = 0; j < 3; j++) {
		ch = table[puker[extra[j]].num];
		switch (ch) {
		case 'X':
			gotoxy(HDO, 37 + 8 * j, 1); PR("10");
			gotoxy(HDO, 39 + 8 * j, 3); PR("10");
			break;
		case 'R':
			gotoxy(HDO, 37 + 8 * j, 1);
			if (puker[extra[j]].num == 13) PR("小");
			else PR("大");
			gotoxy(HDO, 39 + 8 * j, 3); PR("王");
			break;
		default:
			gotoxy(HDO, 37 + 8 * j, 1); PR("%c", ch);
			gotoxy(HDO, 39 + 8 * j, 3); PR("%2c", ch);
		}
		gotoxy(HDO, 39 + 8 * j, 2);
		if (ch != 'R') PR("%c", color[puker[extra[j]].color]);
	}
	//-------=======	底分与倍数	======------//
	gotoxy(HDO, 68, 0); PR("底分:%d", basis);
	gotoxy(HDO, 68, 1); PR("倍数:%d", pass.basis);
	//-------=======	打印牌框	======------//
	if (player[0].num > 0) { 	//当手里有牌时执行
		gotoxy(HDO, 45 - 2 * player[0].num, 21);		// 将牌框按轴对称对齐
		for (i = 0; i < player[0].num; i++) PR("┏━");
		PR("━━━┓");
		for (j = 22; j < 28; j++) {
			gotoxy(HDO, 45 - 2 * player[0].num, j);
			for (i = 0; i < player[0].num; i++) PR("┃  ");
			PR("      ┃");
		}
		gotoxy(HDO, 45 - 2 * player[0].num, 28);
		for (i = 0; i < player[0].num; i++) PR("┗━");
		PR("━━━┛");
		//-------=======	打印牌面	======------//
		place = 19;
		for (i = player[0].num - 1; i >= 0; i--) {		// 将牌面按轴对称对齐
			gotoxy(HDO, 43 + 2 * player[0].num - 4 * i, 23);
			PR("%2c", color[puker[player[0].card[i]].color]);
			gotoxy(HDO, 43 + 2 * player[0].num - 4 * i, 22);
			while (player[0].card[place] == EMPTY_CARD) place--;
			ch = table[puker[player[0].card[place]].num];
			switch (ch) {
			case 'X': PR("10"); break;
			default:  PR("%2c", ch); break;
			case 'R': //判断是大王还是小王
				if (player[0].card[place] == 52) strcpy(space, "joker"); 
				else strcpy(space, "JOKER");
				for (j = 22; j < 27; j++) {
					gotoxy(HDO, 43 + 2 * player[0].num - 4 * i, j);
					PR("%2c", space[j - 22]);
				}
			}
			place--;
		}
		//打印最后一张牌的牌面
		gotoxy(HDO, 50 + 2 * player[0].num, 26); PR("%c",  color[puker[player[0].card[0]].color]);
		gotoxy(HDO, 49 + 2 * player[0].num, 27); PR("%2c", ch);
	}
	//-------=======	打印电脑	======------//
	strcpy(space, " "); gotoxy(HDO, 0, 7); PR(" ┏━━━━┓%73s┏━━━━┓\n", space);	// 打印,没什么借鉴意义
	for (j = 0; j < 6; j++) PR(" ┃┆    ┆┃%73s┃┆    ┆┃\n", space);
	PR(" ┗━━━━┛%73s┗━━━━┛\n", space);
	PR(" 农民:%6s%73s农民:%6s\n", player1, space, player2); PR(" 剩余: %2d 张%73s剩余: %2d 张\n", player[2].num, space, player[1].num);
	gotoxy(HDO,  3,  8); PR("┌┈┈┐"); 	gotoxy(HDO,  3, 13); PR("└┈┈┘"); 	gotoxy(HDO, 88,  8); PR("┌┈┈┐");	gotoxy(HDO, 88, 13); PR("└┈┈┘");
	gotoxy(HDO,  5, 10); PR("SIEE"); 	gotoxy(HDO, 90, 10); PR("SIEE"); 	gotoxy(HDO,  3, 11); PR("智慧信电"); gotoxy(HDO, 88, 11); PR("智慧信电");
	gotoxy(HDO, 25, 30); PR("地主:%s", playerName); 	gotoxy(HDO, 25, 31); PR("剩余:%2d 张", player[0].num);
	gotoxy(HDO, 60, 30); PR("等级:%s", playerLevel);	gotoxy(HDO, 60, 31); PR("积分:%d", mark);
	//for (i = 2; i > 0; i--) {gotoxy(HDO, 20, 33 - i);for (j = 16; j >= 0; j--) {PR("%c", color[puker[player[i].card[j]].color]);PR("%c ", table[puker[player[i].card[j]].num]); }PR("\n");}	//  电脑手牌,仅在调试环境下生效
	//-------=======	打印上回合记录	======------//
	if (pass.turn != 0 ) for (j = 1; j < 3; j++) {
		if (pass.isPass[j] == 1 ) {
			gotoxy(HDO, 144 - 64 * j, 11);
			PR("不出");
		} else {
			for (i = 1; i < 32; i++)
				if (pass.record[j][i] == EMPTY_CARD) {
					place = i;
					break;
				}
			printSmallPuker(j, place);
		}
	}	
	// 行列显示,仅在调试环境下作用
	//for (i = 0; i < 90; i++) { gotoxy(HDO, i, 0);  if (i % 10 )PR("%d", i % 10); } for (i = 0; i < 31; i++) { gotoxy(HDO, 0, i);  PR("%d", i); }
}
/**********************		玩家出牌		**************************/
int play() {
	char _cmd[32] = "";
	int cmd[32];
	int cmdNum = 0; // 记录每次出几张牌
	int recNum = 0;	// 记录上一回合玩家出了几张牌
	int i = 0, j = 0, CtoI = 0;	// CtoI 是字符转整形的临时变量
	int special = 0; // 记录特殊牌类型:具体含义如何映射在后文会有注释
	pass.isPass[0] = 0;	// 初始化出牌标记
	for (; i < 32; i++) cmd[i] = EMPTY_CARD;	// 初始化 cmd
	for (; j < 32; j++) pass.record[0][j] = EMPTY_CARD;		// 初始化 record
	CLS;
	printPuker();
	gotoxy(HDO, 0, 0);
	PR("控制台\n\n");
	PR("输入出牌:");
	//-------=======	获取指令	======------//
	if (!pass.who) gets(_cmd);
	cmdNum = strlen(_cmd);	
	if (!cmdNum && pass.hasPrinted) {		// 如果出牌数为 0 ,且上家都出完牌,则可以确定玩家选择了不出牌
		if (!pass.turn || pass.isPass[1] && pass.isPass[2]) {
			PR("你不能不出牌!小老弟\n"); PUS;
			return play();
		}
		gotoxy(HDO, 46, 19); PR("不出");
		pass.isPass[0] = 1;		// 标记该玩家为不出
		for (j = 0; j < 32; j++) pass.record[0][j] = pass.record[2][j];		// 传递 record
		pass.who++;
		return AIplay();
	}
	i = j = 0;
	while (i < cmdNum) {
		if ((_cmd[i] < '1' || _cmd[i] > '9') && _cmd[i] != 'J' && _cmd[i] != 'Q' && _cmd[i] != 'K' && _cmd[i] != 'A' && _cmd[i] != 'j' && _cmd[i] != 'q' && _cmd[i] != 'k' && _cmd[i] != 'a' && _cmd[i] != '-' && _cmd[i] != '=') {
			PR("错误:请输入正确的指令!\n"); PUS;
			return play();
		}
		//-----=====	扑克点数转换为数值	  ====----//
		switch (_cmd[i]) {
			case '1': cmd[j] = 7; i++; break;
			case 'J': case 'j': cmd[j] = 8; break;
			case 'Q': case 'q': cmd[j] = 9; break;
			case 'K': case 'k': cmd[j] = 10; break;
			case 'A': case 'a': cmd[j] = 11; break;
			case '2': cmd[j] = 12; break;
			case '-': cmd[j] = 13; break;
			case '=': cmd[j] = 14; break;
			default: CtoI = (int)_cmd[i]; if (CtoI > 50 && i < 58) cmd[j] = CtoI - 51; break;
		}
		i++, j++;
	}
	cmdNum = j; //单次出牌张数
	//------------============		判断指令是否可执行		============------------//
	//	特殊牌类型:0无效值,1单牌,2一对,3三张,4炸,5顺子,6连对,7飞机,8三带一,9三带一对,10四带二,11四带两对,12飞机带N,13飞机带N对,14王炸
	//	1.	判断是否为特殊牌型
	special = daipai(cmdNum, cmd);	// 判断是否为带牌牌型
	if (!special) special = shunzi_liandui(cmdNum, cmd);	// 判断是否为顺子、连对、飞机
	if (cmdNum == 2 && cmd[0] > 12 && cmd[1] > 12) special = 14;	//出王炸不校验出牌顺序
	isTherePuker(special, cmdNum, cmd);		// 判断手上是否有足够的牌
	//	2. 当1 ~ 4张牌时定义 special 类型
	if (!special && cmdNum > 0 && cmdNum < 5) {
		for (i = 0; i < cmdNum - 1; i++)
			if (cmd[i] != cmd[i + 1]) {
				PR("出牌不符合规则,请重新出牌!\n");
				PUS; return play();
			}
		special = cmdNum;
	}
	//	3. 判断出牌是否符合出牌规则
	if (!special) {
		PR("出牌不符合规则,请重新出牌!\n");
		PUS; return play();
		}
	if (pass.isPass[1] + pass.isPass[2] < 2 && pass.turn) {		// 若其余玩家出过牌
		for (i = 0; i < 32; i++) if (pass.record[2][i] == EMPTY_CARD) {
			recNum = i;
			break;
		}
		if (!comparePuker(pass.special, special, recNum, cmdNum, pass.record[2], cmd)) {
			PR("出牌不能大过上家,请重新出牌%d!\n", special);
			PUS; return play();
		}
	}
	pass.special = special;
	if (pass.special == 4 || pass.special == 14) {	
		pass.basis *= 2; 
		gotoxy(HDO, 68, 0); PR("底分:%d", basis);
		gotoxy(HDO, 68, 1); PR("倍数:%d", pass.basis);
	}
	//	4. 抽出扑克牌,刷新页面
	for (i = 0; i < cmdNum; i++)
		for (j = 0; j < 20; j++)
			if (puker[player[0].card[j]].num == cmd[i]) {
				if (!i) pass.color = puker[player[0].card[j]].color;
				puker[player[0].card[j]].owner = UNDEALT_PUKER;
				player[0].card[j] = EMPTY_CARD;
				player[0].num--;
				break;
			}
	pass.who ++;	//传递出牌权
	if (pass.isPass[1] + pass.isPass[2] == 2 || !pass.turn) pass.special = special;		//告知本次牌型
	for (i = 0; i < 32; i++) pass.record[0][i] = cmd[i];	//传递存储 cmd
	printPuker();
	printSmallPuker(0, cmdNum);	
	pass.hasPrinted = 1;	// 出牌指令挂起,防止误不出牌
	// 5. 判断牌是否出完
	if (!player[0].num){
		player[0].isOver = 1;
		Sleep(800);
		for(i = 0; i < 3; i++) {
			gotoxy(HDO, 42, 11); PR("            ");
			//Sleep(500);
			gotoxy(HDO, 42, 11); PR("地 主 胜 利");
			//Sleep(500);
		}
		gotoxy(HDO, 38, 12); PUS;
		over();
	} else return AIplay();
	//PR("%d ", pass.special);PUS;
	return home();
}
/************************		判断玩家出牌是否合法		******************************/
int comparePuker(int recSpecial, int special, int recN, int n, int rec[32], int cmd[32]) {
	if (special > 0 && special < 14 && special != 4) { // 当牌型不为炸时,只需判断第一张牌谁大谁小
		if (recSpecial == special && rec[0] < cmd[0]) return 1;
	} else if (special == 4) { 		// 当牌型为 4 炸时,判断谁大谁小
		if (recSpecial != 4 && recSpecial != 14 || recSpecial == 4 && rec[0] < cmd[0]) return 1;
	} else if (special == 14) return 1;		// 王炸碾压芸芸众生!!
	return 0;
}
/*******************	判断是否有牌	**********************/
int isTherePuker(int special, int n, int cmd[32]) {
	int paiXu[32];	//临时牌序数组paiXu[]
	int i, j, temp;
	//	判断指令牌序
	if (special < 8) {
		for (i = 0; i < n - 1; i++) {
			if (cmd[i] > cmd[i + 1]) {
				PR("请按大小顺序出牌!\n"); PUS;
				return play();
			}
		}
	}
	//	3. 判断是否有牌
	//为避免带牌乱序,先排序 (临时牌序数组paiXu[])
	for (i = 0; i < 32; i++) paiXu[i] = EMPTY_CARD;
	for (i = 0; i < n; i++) paiXu[i] = cmd[i];
	for (i = 0; i < n; i++)
		for (j = 0; j < n - i; j++) // j开始等于0,
			if (paiXu[j] > paiXu[j + 1]) {
				temp = paiXu[j];
				paiXu[j] = paiXu[j + 1];
				paiXu[j + 1] = temp;
			}
	i = j = 0;
	while (i < n && j < 20)
		while (j < 20) {
			if (puker[player[0].card[j]].num == paiXu[i]) {
				i++, j++;
				break;
			}
			j++;
		}
	if (i < n) {
		PR("请在已有牌基础上出牌!\n");PUS;
		return play();
	}
	return 0;
}
/**************************		判断顺子、连对或飞机	 	**************************/
int shunzi_liandui(int n, int cmd[32]) {
	int k;
	int _bool = 0;
	for (k = 0; k < n - 1; k++)	//非连续, 或存在 2 和 joker, 直接 return
		if (cmd[k] + 1 < cmd[k + 1]) return 0;
	for (k = 0; k < n; k++)
		if (cmd[k] > 11) return 0;
	if (n >= 5) {	//顺子, 判断方法:各相邻牌是否相差且都相差 1 。
		k = 0;
		while (k < n - 1)
			if (cmd[k] + 1 == cmd[k + 1]) k++;
			else break;
		if (k == n - 1) return 5;
	}
	if (n >= 6 && n % 2 == 0) {	//连对, 判断方法:是否两两相连。
		k = 0;
		while (k < n - 2)
			if (cmd[k] == cmd[k + 1] && cmd[k] + 1 == cmd[k + 2]) k += 2;
			else break;
		if (k == n - 2) {
			if (cmd[k] == cmd[k + 1]) return 6;
			else return 0;
		}
	}
	if (n >= 6 && n % 3 == 0) {	//飞机, 判断方法:是否三三相连。
		k = 0;
		while (k < n - 3)
			if (cmd[k] == cmd[k + 1] && cmd[k + 1] == cmd[k + 2] && cmd[k] + 1 == cmd[k + 3]) k += 3;
			else return 0;
		if (k == n - 3) {
			if (cmd[k] == cmd[k + 1] && cmd[k + 1] == cmd[k + 2]) return 7;
			else return 0;
		}
	}
	return 0;
}
/***********	判断三带一,三带一对,四带二,四带两对,飞机带 N,飞机带 N 对	 ***********/
int daipai(int n, int cmd[32]) {
	int i;
	if (cmd[0] == cmd[1] && cmd[1] == cmd[2]) {		//先判断前三张是否一样
		if (n == 4 && cmd[2] != cmd[3]) return 8;	//三带一
		if (n == 5 && cmd[3] == cmd[4]) return 9;	//三带二
		if (cmd[2] == cmd[3]) {		//若第四张和第三张一样则晋升为四张
			if (n == 6 && cmd[4] != cmd[5]) return 10;	//四带一
			if (n == 8 && cmd[4] == cmd[5] && cmd[6] == cmd[7] && cmd[5] != cmd[6]) return 11;//四带二
		}
		if (n > 4 && n % 4 == 0) {	//判断飞机带 N 张
			i = 3;
			while (i < n - n / 4) {
				if (cmd[i] < 12 && cmd[i] == cmd[i + 1] && cmd[i + 1] == cmd[i + 2] && cmd[i - 1] + 1 == cmd[i]) i += 3;
				else return 0;
			}
			if (i == n - n / 4) {
				if (cmd[i] == cmd[n - 1]) return 0;
				else return 12;
			} 
		}
		if (n > 5 && n % 5 == 0) {	//判断飞机带 N 对
			i = 3;
			while (i < n - 2 * (n / 5)) {
				if (cmd[i] < 12 && cmd[i] == cmd[i + 1] && cmd[i + 1] == cmd[i + 2] && cmd[i - 1] + 1 == cmd[i]) i += 3;
				else return 0;
			}
			if (i == n - 2 * (n / 5)) {
				while (i < n) {
					if (cmd[i] == cmd[i + 1] && cmd[i - 1] != cmd[i]) i += 2;
					else return 0;
				}
			}
			if (i == n) return 13;
		}
	}
	return 0;
}
/*******************************		打印出牌缩略图	 	*********************************/
void printSmallPuker(int who, int n) {
	int i, j, temp;
	char ch;
	char flower[4];
	int smallPuker[32];
	int borderY, borderX, contentX;
	//根据不同出牌者定义打印坐标
	//以下是显示配置,无太大借鉴意义
	sw
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值