目录
1. 玩法说明
2. 分析和设计
3. 代码实现
4. 游戏演示
1. 玩法说明
一副54张牌,3最小,两个王最大,其实是2,和上面一样从大到小排列
2. 分析和设计
2.1 分析和设计
常量和变量设计
一副牌有54张,有牌的数值和花色,可以分别用两个数组来存储,card为卡牌表示的数值,color为它的花色
卡牌创建好要进行游戏,需要将牌分给玩家,那么玩家也需要存储这些卡牌,玩家一般由三人,但也不确定,每个人有一副卡牌,所以适合用二维数组存储
PLAYER: 玩家数量,默认为3
PLAYCARDS: 底牌为3,所以每个玩家申请的数组大小是54减去三张底牌除以玩家数量,然后考虑加入底牌的情况,数字大小再加3
lord记录地主的下标
函数设计
菜单显示函数
void menu();
卡牌初始化赋值函数
void InitCard(int num[],int numcolor[],int len);
考虑到需要比较卡牌的大小,从1开始赋值,1为最小的牌,通过下面的转换函数,将1转换为最小牌3的ascii码输出,花色每4个一轮,红心从3开始赋值,大小王单独赋值为14和15
转换字符函数
char ChangeCard(int num);
将牌的大小转换为对应大小的ascii码输出
显示卡牌函数
由于10是两个字符,一个字符放不下,所以单独判断输出,大小王没有花色,也单独输出,17个一换行
洗牌函数
void RandomCard(int num[], int numcolor[], int len);
传入牌的数组和花色,思路是先从1-53下标找一个和0下标交换,之后从2-53找一个和1下标交换,从3-53找一个和2下标交换。数值和花色都需要交换,这里需要随机数函数,在主程序先置一个随机数种子
发牌函数
void SendCard(int num[], int numcolor[],
int playnum[][PLAYCARDS],int playcolor[][PLAYCARDS],
int len);
由于玩家是二维数组,而卡牌是一维数组,所以需要一些计算。当第一个玩家,也就是i=0的时候,循环17次,一人17张手牌,所以赋值的卡牌下标就是0-16,当第二个玩家是,下标从17-33,当i=1时,卡牌数组num中括号里的值需要是17,所以用i 乘玩家卡牌常量PLAYCARDS,再减去多余的3张地主牌,就是 1*(20-3)+0,然后把底牌手牌也输出
选地主函数
void LandLord(int num[], int numcolor[],
int playnum[][PLAYCARDS], int playcolor[][PLAYCARDS],
int len,int *lord);
遍历玩家数组,找到红心4的拥有者,选为地主,传入地主变量的地址,接收地主编号,将地主玩家的手牌中加入底牌
开始出牌显示
void PlayShow(int playnum[][PLAYCARDS], int playcolor[][PLAYCARDS],int len,int lord);
这时分农民和地主的显示,大致和ShowCard函数的逻辑一致,只是加入了地主和农民的分辨
3. 代码实现
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <windows.h>#define PLAYER 3 //玩家数量
#define PLAYCARDS (54-3)/PLAYER+3 //玩家申请数量void InitCard(int num[],int numcolor[],int len) {printf("初始化卡牌...\r\n");Sleep(1000);//牌的大小赋值,从1开始,依次累加int index = 0; //牌大小int color = 3; //牌花色for (int i = 0; i < len-2; i++) {if (i % 4 == 0) {index++;color = 3;}num[i] = index;numcolor[i] = color;color++;}num[52] = 14;num[53] = 15; }void RandomCard(int num[], int numcolor[], int len) {int index = 0;for (int i = 1; i < len; i++) {//1 1-53 2 2-53 3 3-53//从后面随机一个,先和0下标交换,不断往后移index = rand() % (len-i) + i;int temp = num[i-1];int tempcolor = numcolor[i - 1];num[i - 1] = num[index];numcolor[i - 1] = numcolor[index];num[index] = temp;numcolor[index] = tempcolor;}
}char ChangeCard(int num) {switch (num % 16){case 1:return '3';case 2:return '4';case 3:return '5';case 4:return '6';case 5:return '7';case 6:return '8';case 7:return '9';case 8:return '0';case 9:return 'J';case 10:return 'Q';case 11:return 'K'; case 12:return 'A';case 13:return '2';case 14:return '\x1';case 15:return '\x2';default:break;}
}
void ShowCard(int num[],int numcolor[], int len) {for (int i = 0; i < len; i++) {//大小王和10单独显示if (num[i] == 14 || num[i] == 15) {printf("%c ", ChangeCard(num[i]));}else if (num[i] == 8) {printf("%c%d ", numcolor[i],10);}else {printf("%c%c ", numcolor[i], ChangeCard(num[i]));}if ((i+1) % 17 == 0) {printf("\r\n");}}printf("\r\n");
}//参数,卡牌数组和花色数组,玩家卡牌数组和花色数组,卡牌长度,玩家数量
void SendCard(int num[], int numcolor[],int playnum[][PLAYCARDS],int playcolor[][PLAYCARDS],int len) {system("cls");printf("发牌中...");Sleep(1000);system("cls");for (int i = 0; i < PLAYER; i++) {for (int j = 0; j < PLAYCARDS-3; j++) {playnum[i][j] = num[i * (PLAYCARDS-3) + j];playcolor[i][j] = numcolor[i * (PLAYCARDS - 3)+j];}}printf("\r\n");//显示手牌for (int i = 0; i < PLAYER; i++) {printf("play%d:\r\n", i + 1);ShowCard(playnum[i], playcolor[i], PLAYCARDS - 3);}//显示底牌printf("底牌:\r\n");for (int i = len- PLAYER; i < len; i++) {printf("%c%c ", numcolor[i], ChangeCard(num[i]));}printf("\r\n");
}void LandLord(int num[], int numcolor[], int playnum[][PLAYCARDS], int playcolor[][PLAYCARDS],int len,int *lord) {for (int i = 0; i < PLAYER; i++) {for (int j = 0; j < PLAYCARDS - 3; j++) {//红心4为地主if (playnum[i][j] == 2 && playcolor[i][j] == 3) {*lord = i;printf("地主是play%d\r\n", *lord +1);goto NEXT;}}}NEXT:Sleep(3000);//地主加入底牌playnum[*lord][17] = num[51];playcolor[*lord][17] = numcolor[51];playnum[*lord][18] = num[52];playcolor[*lord][18] = numcolor[52];playnum[*lord][19] = num[53];playcolor[*lord][19] = numcolor[53];}void PlayShow(int playnum[][PLAYCARDS], int playcolor[][PLAYCARDS],int len,int lord) {system("cls");printf("开始出牌...\r\n");Sleep(1000);//显示手牌for (int i = 0; i < PLAYER; i++) {if (i == lord) {printf("(地主)play%d:\r\n", i + 1);}else {printf("(农民)play%d:\r\n", i + 1);}for (int j = 0; j < len; j++) {//大小王和10单独显示if (playnum[i][j] == 14 || playnum[i][j] == 15) {printf("%c ", ChangeCard(playnum[i][j]));}else if(playnum[i][j] == 8){printf("%c%d ", playcolor[i][j], 10);}else {printf("%c%c ", playcolor[i][j], ChangeCard(playnum[i][j]));}}printf("\r\n");}printf("\r\n");
}
void menu() {system("cls");printf("********************\r\n");printf("*****1.开始游戏*****\r\n");printf("*****0.退出游戏*****\r\n");printf("********************\r\n");
}
int main()
{srand((unsigned int)time(NULL));//创建卡牌数组int card[54] = { 0 };int color[54] = { 0 };//创建玩家数组int playcard[PLAYER][PLAYCARDS] = {0};int playcolor[PLAYER][PLAYCARDS] = {0};//卡牌长度int len = sizeof(card) / sizeof(card[0]);//地主int lord = 0;int sel; //获取用户选择menu();do{scanf("%d", &sel);switch (sel) {case 1:system("cls");//初始化卡牌InitCard(card, color, len);//洗牌RandomCard(card, color, len);//ShowCard(card, color, len);//发牌SendCard(card, color, playcard, playcolor, len);//选地主LandLord(card, color, playcard, playcolor, len,&lord);//开始出牌PlayShow(playcard, playcolor, PLAYCARDS,lord);break;case 0:printf("退出游戏\r\n");return;break;default:menu();printf("输入错误\r\n"); break;}} while (1);return 0;
}
4. 游戏演示
需要将控制台右键属性切换为点阵字体,显示ascii符号
- 开始游戏
- 初始化卡牌
3. 选完地主显示
4. 出牌显示
后续功能等待开发…