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语言能够有所帮助。

(0)

相关推荐

  • C语言实现二叉树的搜索及相关算法示例

    本文实例讲述了C语言实现二叉树的搜索及相关算法.分享给大家供大家参考,具体如下: 二叉树(二叉查找树)是这样一类的树,父节点的左边孩子的key都小于它,右边孩子的key都大于它. 二叉树在查找和存储中通常能保持logn的查找.插入.删除,以及前驱.后继,最大值,最小值复杂度,并且不占用额外的空间. 这里演示二叉树的搜索及相关算法: #include<stack> #include<queue> using namespace std; class tree_node{ public

  • 基于C语言实现的迷宫算法示例

    本文实例讲述了基于C语言实现的迷宫算法.分享给大家供大家参考,具体如下: 利用c语言实现迷宫算法,环境是vc++6.0. #include<stdio.h> #include<time.h> #include<cstdlib> int visit(int,int); void setmaze(); int maze[11][11]= { {0,0,2,2,2,2,2,2,2,2}, {2,0,2,2,0,2,0,2,0,2}, {2,0,2,0,0,0,0,0,0,2}

  • C语言数据结构算法之实现快速傅立叶变换

    C语言数据结构算法之实现快速傅立叶变换 本实例将实现二维快速傅立叶变换,同时也将借此实例学习用c语言实现矩阵的基本操作.复数的基本掾作,复习所学过的动态内存分配.文件操作.结构指针的函数调用等内容. 很久以来,傅立叶变换一直是许多领域,如线性系统.光学.概率论.量子物理.天线.数字图像处理和信号分析等的一个基本分析工具,但是即便使用计算速度惊人的计算机计算离散傅立叶变换所花费的时间也常常是难以接受的,因此导致了快速傅立叶变换(FFT)的产生. 本实例将对一个二维数组进行正.反快速傅立叶变换.正傅

  • C语言实现的猴子吃桃问题算法解决方案

    本文实例讲述了C语言实现的猴子吃桃问题.分享给大家供大家参考,具体如下: 问题: 猴子第一天摘下N个桃子,当时就吃了一半,还不过瘾,就又吃了一个.第二天又将剩下的桃子吃掉一半,又多吃了一个.以后每天都吃前一天剩下的一半零一个.到第10天在想吃的时候就剩一个桃子了,求第一天共摘下来多少个桃子? 解析: ① 从最后一天的x=1个,倒推出前一天的个数x,需要注意的是表达式为x=2(x+1),而不是x=2x+1,注意两者之间的区别,想清楚为什么第二种不正确. ② 将该表达式作为循环9次的循环体,并在该语

  • C语言实现魔方阵算法(幻方阵 奇魔方 单偶魔方实现)

    例如三阶魔方阵为: 魔方阵有什么的规律呢? 魔方阵分为奇幻方和偶幻方.而偶幻方又分为是4的倍数(如4,8,12--)和不是4的倍数(如6,10,14--)两种.下面分别进行介绍. 2 奇魔方的算法 2.1 奇魔方的规律与算法 奇魔方(阶数n = 2 * m + 1,m =1,2,3--)规律如下: 数字1位于方阵中的第一行中间一列:数字a(1 < a  ≤ n2)所在行数比a-1行数少1,若a-1的行数为1,则a的行数为n:数字a(1 < a  ≤ n2)所在列数比a-1列数大1,若a-1的列

  • C语言实现运筹学中的马氏决策算法实例

    本文实例讲述了C语言实现运筹学中的马氏决策算法.分享给大家供大家参考,具体如下: 一.概述 马氏决策(Markov decision)是马尔可夫决策过程(Markov Decision Processes,简记为MDP)的简称,是研究随机序贯决策问题的一门重要理论.马氏决策是一类可连续进行观察的随机动态系统的最优化决策,它将(确定性)动态规划与马尔可夫过程相结合,是随机离散事件动态系统惟一的动态控制方法. 关于马氏决策的具体说明可参考百度百科:https://baike.baidu.com/it

  • C语言使用广度优先搜索算法解决迷宫问题(队列)

    本文实例讲述了C语言使用广度优先搜索算法解决迷宫问题.分享给大家供大家参考,具体如下: 变量 head 和 tail 是队头和队尾指针, head 总是指向队头, tail 总是指向队尾的下一个元素.每个点的 predecessor 成员也是一个指针,指向它的前趋在 queue 数组中的位置.如下图所示: 广度优先是一种步步为营的策略,每次都从各个方向探索一步,将前线推进一步,图中的虚线就表示这个前线,队列中的元素总是由前线的点组成的,可见正是队列先进先出的性质使这个算法具有了广度优先的特点.广

  • C语言经典算法例题求100-999之间的“水仙花数

    题目:打印出所有的 "水仙花数 ",所谓 "水仙花数 "是指一个三位数,其各位数字立方和等于该数本身. 例如:153是一个 "水仙花数 ",因为153=1的三次方+5的三次方+3的三次方. 实现代码如下 #include <iostream> #include <Cmath> using namespace std; /* 求100-999之间的水仙花数 */ int main() { int number,hun,ten

  • C语言使用深度优先搜索算法解决迷宫问题(堆栈)

    本文实例讲述了C语言使用深度优先搜索算法解决迷宫问题.分享给大家供大家参考,具体如下: 深度优先搜索 伪代码 (Pseudocode)如下: 将起点标记为已走过并压栈; while (栈非空) { 从栈顶弹出一个点p; if (p这个点是终点) break; 否则沿右.下.左.上四个方向探索相邻的点 if (和p相邻的点有路可走,并且还没走过) 将相邻的点标记为已走过并压栈,它的前趋就是p点; } if (p点是终点) { 打印p点的坐标; while (p点有前趋) { p点 = p点的前趋;

  • 详解约瑟夫环问题及其相关的C语言算法实现

    约瑟夫环问题 N个人围成一圈顺序编号,从1号开始按1.2.3......顺序报数,报p者退出圈外,其余的人再从1.2.3开始报数,报p的人再退出圈外,以此类推.   请按退出顺序输出每个退出人的原序号 算法思想 用数学归纳法递推. 无论是用链表实现还是用数组实现都有一个共同点:要模拟整个游戏过程,不仅程序写起来比较烦,而且时间复杂度高达O(nm),若nm非常大,无法在短时间内计算出结果.我们注意到原问题仅仅是要求出最后的胜利者的序号,而不是要读者模拟整个过程.因此如果要追求效率,就要打破常规,实

  • 基于C语言实现的aes256加密算法示例

    本文实例讲述了基于C语言实现的aes256加密算法.分享给大家供大家参考,具体如下: aes256.h: #ifndef uint8_t #define uint8_t unsigned char #endif #ifdef __cplusplus extern "C" { #endif typedef struct { uint8_t key[32]; uint8_t enckey[32]; uint8_t deckey[32]; } aes256_context; void aes

  • C语言实现的猴子分桃问题算法解决方案

    本文实例讲述了C语言实现的猴子分桃问题算法.分享给大家供大家参考,具体如下: 问题: 海滩上有一堆桃子,五只猴子来分.第一只猴子把这堆桃子凭据分为五份,多了一个,这只猴子把多的一个扔入海中,拿走了一份.第二只猴子把剩下的桃子又平均 分成五份,又多了一个,它同样把多的一个扔入海中,拿走了一份,第三.第四.第五只猴子都是这样做的,问海滩上原来最少有多少个桃子? 程序: #include<stdio.h> int divided(int n, int m) //注意该递归函数的定义 { if(n/5

随机推荐