C语言实现斗地主的核心算法

数据结构只选择了顺序表,没有选择链表,灵活性和抽象性不足,不能普适。

head.h

#ifndef __HEAD_H__

#define __HEAD_H__

#define MAXLEVEL 15

typedef struct CARD{

int number;

int level;

char *flower;

char point;

}card;//卡

typedef struct DECK{

int top;

int arr[55];

}deck;//牌堆

typedef struct PLAYERS{

int id;

int status;

card handcard[21];

int size;

}players;//玩家

typedef struct GAMES{

int type;

int level;

int sum;

int who;

int count;

int arr[16];

}games;//桌面

typedef struct BUFFERS{

int arr[16];

int brr[20];

int sum;

}buffers;//出牌缓冲区

/*--------------------------------*/

void game_init();

void turning();

void handcard_sort();

void print();

int win();

void turn_switch();

#endif

op.c

#include<stdio.h>

#include<stdlib.h>

#include"head.h"

#include<string.h>

static int type_buffer();

static char point[]={'0','3','4','5','6','7','8','9','X','J','Q','K','A','2','w','W'};

static char *farr[]={"方片","梅花","红桃","黑桃"};

static char* type_arr[]={"弃权","单张","对子","王炸","骷髅","骷髅单","炸弹","骷髅对","炸带单","顺子","炸带一对","飞机不带","连对","飞机单","飞机带对"};

static char* sta_arr[2]={"农民","地主"};

static players player[3];//玩家

static games game;

/*洗牌堆*/

static deck* deck_init(){

int i,j;

srand(time(0));

deck *p_deck=(deck*)malloc(sizeof(deck));

if(!p_deck){

printf("分配内存失败\n");

return NULL;

}

for(i=1;i<=54;i++){

p_deck->arr[i]=rand()%54;

for(j=1;j<i;j++){

if(p_deck->arr[i]==p_deck->arr[j]){

i--;

break;

}

}

}

p_deck->top=54;

return p_deck;

}

/*初始化玩家(洗牌,id,身份 手牌,总数)*/

static void player_init(){

int i,j;

for(j=0;j<3;j++){

for(i=1;i<=20;i++){

player[j].handcard[i].number=100;

player[j].handcard[i].level =0;

}

}

deck *p=deck_init();

if(!p){

printf("没有牌堆\n");

return ;

}

int which=0;

which=rand()%3;

game.who=which;

for(i=0;i<3;i++){

player[i].id=i;

if(i==which){//地主

player[i].status=1;

for(j=1;j<=20;j++){

player[i].handcard[j].number=p->arr[(p->top)--];

}

player[i].size=20;

}

else{//农民

player[i].status=0;

for(j=1;j<=17;j++){

player[i].handcard[j].number=p->arr[(p->top)--];

}

player[i].size=17;

}

}

free(p);

p=NULL;

}

/*手牌信息补完*/

static void handcard_init(){

int i,j;

for(i=0;i<3;i++){

for(j=1;j<=20;j++){

int number=player[i].handcard[j].number;

int *p_level=&(player[i].handcard[j].level);

char **pp_flower=&(player[i].handcard[j].flower);

char *p_point=&(player[i].handcard[j].point);

if(number>=0&&number<=51){

*p_level=number/4+1;

*p_point=point[number/4+1];

*pp_flower=farr[number%4];

}

else if(number==52){

*p_level=14;

*p_point='w';

*pp_flower="小王";

}

else if(number==53){

*p_level=15;

*p_point='W';

*pp_flower="大王";

}

else {

*p_level=0;

*p_point=' ';

*pp_flower=" ";

}

}

}

}

/*打印当前玩家手牌*/

void print(){

int i,j;

for(i=0;i<3;i++){

if (i!=game.who) continue;

for(j=1;j<=player[i].size;j++){

//printf("======");

if(player[i].handcard[j].number == 100){

printf(" ");

}

else {

char *p_tmp=player[i].handcard[j].flower;

printf("%s ",p_tmp);

}

}

printf("\n");

for(j=1;j<=player[i].size;j++){

if(player[i].handcard[j].number == 100){

printf(" ");

}

else {

printf(" %c ",player[i].handcard[j].point);

}

}

}

printf("\n");

for(j=1;j<=player[game.who].size;j++){

if(! (j>9))

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

else

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

}

printf("\n");

}

/*游戏初始化*/

void game_init(){

game.count=2;//弃权次数

player_init();//洗牌 发牌

handcard_init();//手牌信息补完

}

int fcmp(const void *pa,const void *pb){//升序

return *(int*)pa-*(int*)pb;

}

static void rehandcard_sort(players *p_player,int* p_number){//真正的排序函数

int *base=p_number;

size_t nmemb=p_player->size;

size_t size= sizeof(card);

qsort(base,20,size,fcmp);

}

void handcard_sort(){//外壳排序函数

rehandcard_sort(&player[0],&(player->handcard[1].number));

rehandcard_sort(&player[1],&((player+1)->handcard[1].number));

rehandcard_sort(&player[2],&((player+2)->handcard[1].number));

}

/*询问是否出牌*/

static int require(){ //1表示出牌 0表示弃权

if(game.type == 3 ){

if(game.count != 2){

printf("要不起!\n");

return 0;

}

else

return 1;

}

if(game.count !=2){

printf("出牌吗?(y表示出牌,n弃权):");

char choice;

scanf("%c",&choice);

scanf("%*[^\n]");

scanf("%*c");

if(choice == 'n' || choice == 'N'){

return 0;

}

else return 1;

}

else {

printf("继续出牌\n");

return 1;

}

}

buffers buffer={};//出牌缓冲区

/*清空出牌缓冲区*/

static void reset(){

int a;

for(a=0;a<16;a++)

buffer.arr[a]=0;

for(a=0;a<20;a++)

buffer.brr[a]=0;

buffer.sum=0;

}

/*放牌进入缓冲区*/

static void buffer_put(){

char intput[40]={};//把字符串转换为数字

int brr[20]={};

int i=0;

int j;

int sum;

int flag=0;

while(1){

reset();

sig: printf("请输入要放的牌...:");

fgets(intput,40,stdin);

if(strlen(intput)==39&&intput[38]!='\n'){

scanf("%*[^\n]");

scanf("%*c");

}

for(j=0,i=0,sum=0;i<strlen(intput);i++){//记录出牌下标

if(intput[i]>='0'&&intput[i]<='9'){

sum=sum*10+(intput[i]-'0');

flag=1;

}

else {

if(flag)

brr[j] = sum;

sum=0;

j++;

flag=0;

}

}

int k;

printf("要出: ");

for(k=0;brr[k];k++)

printf("%d ",brr[k]);

printf("号牌\n");

int who = game.who;

players* p_player=&(player[who]);

int index;

for(i=0;brr[i];i++){//记录出的牌是什么

index=brr[i];

if(index>(p_player->size) || index<=0 ){//输入的字符串范围有误

printf("输入内容超出范围,重新输入\n");

goto sig;

}

else{

int level=p_player->handcard[index].level;

++(buffer.arr[level]);

buffer.brr[i] =brr[i];

}

}

for(i=1;i<=15;i++)//记录出了多少张牌

buffer.sum+=buffer.arr[i];

char aff= 'N';

int type = type_buffer();

if(type != -1)

printf("要出的类型是:%s\n\n",type_arr[type]);

else {

printf("不存在此类型的牌\n\n");

reset();

return;

}

printf("确定要这样出吗?(确定输入y,否则按其它)");

scanf("%c",&aff);

scanf("%*[^\n]");

scanf("%*c");

if(aff == 'y' || aff =='Y')

break;

}

}

static void turnstart(){

char u;

printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n==============================================================斗地主======================================================\n\n\n\n\n");

printf("轮到下一家");

scanf("%c",&u);

int i;

printf("\n\n\n\n\n\n\n牌面张数为%d张\n",game.sum);

printf("牌面类型为: %s%c\n",type_arr[game.type],point[game.level]);

printf("=============================================================%s的回合==========================================================\n\n",sta_arr[player[game.who].status]);

printf("现在轮到玩家%d",game.who+1);

printf(" 玩家1(%s)手牌%d ",sta_arr[player[0].status],player[0].size);if(game.who==0) printf("<=====\n");else printf("\n");

printf(" 玩家2(%s)手牌%d ",sta_arr[player[1].status],player[1].size);if(game.who == 1) printf("<=====\n"); else printf("\n");

printf(" 玩家3(%s)手牌%d ",sta_arr[player[2].status],player[2].size);if(game.who == 2) printf("<=====\n"); else printf("\n");

}

/*判断是否连续*/

static int continuum(int num,int total){

int i,count=0;

int flag=0;//有值则标记为1

int sig=0;//从 有到无 改标记为1

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

if(buffer.arr[i]==num){

if(sig)

return 0;//非连续

count++;

if(count==total)

return 1;//连续

flag=1;

}else {

if (flag)

sig=1;

}

}

}

/*获取缓冲区牌类类型*/

static int type_buffer(){

int i, one=0,pair=0,triple=0,quattuor=0,zero=0;

for(i=1;i<=15;i++){//统计单张,对子,三同,四同各有多少

if(buffer.arr[i] == 1)

one++;

else if(buffer.arr[i] == 2)

pair ++;

else if(buffer.arr[i] == 3)

triple ++;

else if(buffer.arr[i] == 4)

quattuor ++;

else zero++;

}

//printf("单%d 对%d 三%d 四%d 零%d,sum%d===\n",one,pair,triple,quattuor,zero,buffer.sum);

if(!(buffer.sum)){

return -1;//非法

}

else if(buffer.sum<=5){//1~5

if(one == 1 && !pair && !triple && !quattuor)//单张

return 1;

else if(pair == 1 && !one && !triple && !quattuor)//对子

return 2;

else if(one == 2 &&buffer.arr[14]&&buffer.arr[15])//王炸

return 3;

else if(triple == 1 && !one && !pair && !quattuor) //骷髅

return 4;

else if(one ==1 && !pair && triple == 1 && !quattuor )//骷髅单

return 5;

else if(!one && !pair && !triple && quattuor == 1)//炸

return 6;

else if(!one && pair == 1 && triple == 1 && !quattuor)//骷髅对

return 7;

else if(one == 1 && !pair && !triple && !quattuor){//炸带单

return 8;

}

else if(!pair && !triple && !quattuor && (!buffer.arr[14] && !buffer.arr[15])&& buffer.sum == 5){//顺子

if( continuum(1,one))//所有1连续

return 9;

else {

return -1;

}

}

else return -1;

}

else if(buffer.sum>=6){

if((!one) && (pair == 1) && (!triple) && (quattuor == 1) )//炸带对

return 10;

else if(!one && !pair && !quattuor){//只有2个以上个三张相同 飞机不带

if(continuum(3,triple))//所有3连续

return 11;

else return -1;

}

else if(!one && !triple && !quattuor){//连对

if(continuum(2,pair))

return 12;

else return -1;

}

else if(buffer.sum == 4*triple){//飞机单

if(continuum(3,triple))

return 13;

else return -1;

}

else if((buffer.sum == 5*triple) && (triple == pair)){//飞机对

if(continuum(3,triple))

return 14;

else return -1;

}

else if(!pair && !triple && !quattuor &&(!buffer.arr[14] && !buffer.arr[15])){

if(continuum(1,one))

return 9;

else return -1;

}

else return -1;

}

}

/*最大下标*/

static int maxindex(int count){

int i;

for (i=15;i>=1;i--){

if(buffer.arr[i] == count)

return i;

}

}

/*获取缓冲区牌类等级*/

static int level_buffer(int type){

switch(type){

case 1:

return maxindex(1);

break;

case 2:

return maxindex(2);

break;

case 3:

return 15;

break;

case 4:

return maxindex(3);

break;

case 5:

return maxindex(3);

break;

case 6:

return maxindex(4);

break;

case 7:

return maxindex(3);

break;

case 8:

return maxindex(4);

break;

case 9:

return maxindex(1);

break;

case 10:

return maxindex(4);

break;

case 11:

return maxindex(3);

break;

case 12:

return maxindex(2);

break;

case 13:

return maxindex(3);

break;

case 14:

return maxindex(3);

break;

}

}

/*消减手牌*/

static void annealation(){

int i=1;

int j=0;

int who=game.who;

for(i = 1,j=0;buffer.brr[j];i++,j++){

int index = buffer.brr[j];

player[who].handcard[index].number = 100;

player[who].size = player[who].size - 1;

}

game.sum=buffer.sum;

game.count=0;

handcard_sort();

//printf("出牌成功\n");

}

/*回合进行中*/ //这个模块有很大的修改空间 例如return 改为break...

void turning(){

turnstart(); /* 开始阶段 */

handcard_sort();

print();

int level= 0;

while(1){

if(!require()){

printf("\n\n\n\n\n\n\n\n不要\n");

game.count++;

if(game.count == 2){

game.type=0;

game.level=0;

game.sum=0;

}

return ; /* 开始阶段 */

}

buffer_put(); /* 出牌阶段在这函数判断是否弃权比较好 */

int type = type_buffer();

int level=level_buffer(type);

if(type == -1){

printf("牌类非法!-----\n");

continue;

}

if(type == 3){//王炸

printf("\n\n\n\n\n王炸!!\n");

annealation();

game.type=3;

game.level=MAXLEVEL;

return ;

}

else if(type == 6){//炸弹

if(game.type != 6){

printf("\n\n\n\n炸弹\n");

annealation();

game.type = 6;

game.level = level_buffer(type);

return;

}

else {

if(level > game.level){

printf("\n\n\n\n\n压死\n");

annealation();//消减手牌

game.type = 6;

game.level = level;

return;

}

else if(level < game.level||level == game.level){

printf("牌的等级不够大\n");

continue;

}

}

}

else if(game.count == 2 ){//两家弃权

annealation();

game.type = type;

game.level = level;

return ;

}

else {//除了炸弹 两家弃权 王炸 非法 以外的合理牌类

if(type != game.type){ //不对应

printf("类型不对应\n");

continue;

}

else { //对应

if(buffer.sum != game.sum){

printf("数量不对应\n");

continue;

}

if(level < game.level|| level==game.level){

printf("牌的等级不够大\n");

continue;

}

else if(level > game.level){

printf("\n\n\n\n\n压死\n");

annealation();

game.type = type;

game.level = level;

return ;

}

}

}

}

}

/*0 1 2 3判断是否是谁胜利 0表示没有 1表示玩家一*/

int win(){

int now = game.who;

if(!player[now].size)

return now;

else return 0;

}

/*切换当前玩家为下家*/

void turn_switch(){

int who = game.who;

who++;

game.who = who%3;

}

main.c

#include<stdio.h>

#include"head.h"

int main(){

while(1){

int which;

game_init();//初始化游戏

while(1){

turning();//回合进行中

printf("\n\n\n");

if(which=win())//是否产生胜者

break;

turn_switch();//切换出牌方

}

printf("胜负已出!胜利者是玩家%d\n",which+1);

printf("是否重新游戏?(y为继续,其它退出程序):");

char choice;

scanf("%c",&choice);

scanf("%*[^\n]");

scanf("%*c");

if(choice == 'y'||choice =='Y')

continue;

break;

}

printf("谢谢试玩\n");

}

以上所述就是本文的全部内容了,希望对大家熟练应用C语言能够有所帮助。

以上是 C语言实现斗地主的核心算法 的全部内容, 来源链接: utcz.com/z/345126.html

回到顶部