《信任的进化》游戏简易版逻辑算法的实现(C语言)

简介: 《信任的进化》游戏简易版逻辑算法的实现(C语言)

信任的进化网址:>信任的进化 (dccxi.com)

本文是讲解如何用C语言实现《信任的进化》此游戏的逻辑算法(游戏有趣引人深思,建议游玩后再看本文章)

游戏规则:首先分别输入每种角色的数量,和比赛次数,之后每个角色都会和除自己之外的角色进行信任比赛,每场比赛后,硬币最少的将被删去,硬币最高的将会被复制一个并补上被删除的最低分角色的位置。整个游戏直到比赛次数到了才会停止,除此之外不会停下。

比赛规则:比赛的双方角色会进行信任选择,如果选择了合作,角色将消耗一个硬币。如果双方都选择了合作,则会获得3个硬币,除去消耗的硬币净收入为2个。如果有一方选择了欺骗,则被欺骗的那一方将什么都不会获得,而欺骗对方的角色将会获得3个硬币。

一.每种角色的初始化并打印菜单

首先,游戏中有五个角色,分别复读机,小红,油条,黑帮和福尔摩斯

五个角色行动逻辑分别为:

复读机:第一回合会合作,之后会一直模仿对方上一轮的行动。

小红:会一直和对方合作。

油条:会一直欺骗对方。

黑帮:一开始会和对方合作,如果遭受到欺骗则会一直欺骗对方。

福尔摩斯:前四轮分别会合作,欺骗,合作,合作。如果在前四轮之内遭受对方的欺骗,则四轮之后将会变成复读机,如果前四轮之内没有遭受欺骗,则四轮之后将会变成油条 。

所以,每个角色应该包含的数据有:名字,硬币数量,角色的选择,因为福尔摩斯前四轮和之后的轮数行动逻辑不一样,所以还应该加入轮数的数据。

因此,这里我选择用结构体来存储每个角色的数据。

首先,为了文件里的代码不特别杂乱,我先分别1个头文件用来声明函数

7个源文件,分别为执行文件,函数文件,和5个分别存储各自角色代码的文件。

如下图

image.gif编辑

在头文件中,我先定义了结构体

再在不同角色的文件里写下各自的初始化函数

struct player
{
  int score;//硬币的数量
  int choice;//每个人的选择,1为合作,0为欺骗
  int n;//轮数
  char name[100];//用来存储自己的名字
};

image.gif

复读机

//初始化复读机
void InitFuduji(struct player* Fuduji)
{
  Fuduji->choice = 1;
  Fuduji->score = 0;
  Fuduji->n = 0;
  strcpy(Fuduji->name, "Fuduji");
}

image.gif

小红

//对小红进行初始化
void Initxiaohong(struct player* xiaohong)
{
  xiaohong->choice = 1;
  xiaohong->score = 0;
  xiaohong->n = 0;
  strcpy(xiaohong->name, "xiaohong");
}

image.gif

黑帮

//对黑帮进行初始化
void Initheibang(struct player* heibang)
{
  heibang->choice = 1;
  heibang->score = 0;
  heibang->n = 0;
  strcpy(heibang->name, "heibang");
}

image.gif

福尔摩斯

//初始化福尔摩斯
void Initfuer(struct player* fuer)
{
  fuer->choice = 1;
  fuer->score = 0;
  fuer->n = 1;//福尔摩斯需要记录轮数,所以初始化轮数为1
  strcpy(fuer->name, "fuer");
}

image.gif

在执行文件xiangmu.c中,我首先定义了5种角色,并将其初始化,且输入每种角色的数量

//打印游戏的开头
    printf("欢迎来到信任游戏模拟\n");
  struct player Fuduji;
  struct player xiaohong;
  struct player youtiao;
  struct player heibang;
  struct player fuer;
    //初始化每种角色
  InitFuduji(&Fuduji);
  Initxiaohong(&xiaohong);
  Inityoutiao(&youtiao);
  Initheibang(&heibang);
  Initfuer(&fuer);
  printf("注意,人数请不要输入负数,否则游戏会退出\n");
  printf("请输入复读机的数量:>");
  int Fuduji_num = 0;
  scanf("%d", &Fuduji_num);
  printf("请输入小红的数量:>");
  int xiaohong_num = 0;
  scanf("%d", &xiaohong_num);
  printf("请输入油条的数量:>");
  int youtiao_num = 0;
  scanf("%d", &youtiao_num);
  printf("请输入黑帮的数量:>");
  int heibang_num = 0;
  scanf("%d", &heibang_num);
  printf("请输入福尔摩斯的数量:>");
  int fuer_num = 0;
  scanf("%d", &fuer_num);
  //判断人数输入是否有误
  if (fuer_num < 0 || xiaohong_num < 0 || youtiao_num < 0 || heibang_num < 0 || Fuduji_num < 0)
  {
    printf("输入人数错误,游戏退出\n");
    exit(-1);
  }
  if (fuer_num==0 && xiaohong_num == 0 && youtiao_num==0 && heibang_num==0 &&Fuduji_num== 0)
  {
    printf("游戏结束!\n");
    exit(-1);
  }

image.gif

之后便开始打印游戏的菜单,显示每种角色的人数。

void menu(struct player* Fuduji, struct player* xiaohong, struct player* youtiao, struct player* heibang, struct player* fuer, int Fuduji_num, int xiaohong_num, int youtiao_num, int heibang_num, int fuer_num)
{
  printf("------------------------------------------------------------\n");
  printf("-----复读机:%d --------------------小红:%d----------------\n",Fuduji_num,xiaohong_num);
  printf("-----油条:%d ----------------------黑帮:%d------------------\n",youtiao_num,heibang_num);
  printf("-----福尔摩斯:%d -------------------------------------------\n",fuer_num);
  printf("------------------------------------------------------------\n");
}

image.gif

二.比赛的逻辑

重头戏,就是比赛时的逻辑

首先我们要知道,每个角色都要和除自己之外的角色比赛,所以即使我们每种角色只初始化了一个人,也可以完成比赛的整个流程。

首先我们先写下比赛判断双方选择的函数

void isscore(struct player* p1, struct player* p2)//判断胜负的函数
{
  if (p1->choice == 1 && p2->choice == 0)
  {
    p2->score += 3;
    p1->score -= 1;
  }
  if (p2->choice == 1 && p1->choice == 0)
  {
    p1->score += 3;
    p2->score -= 1;
  }
  if (p1->choice == 1 && p2->choice == 1)
  {
    p2->score += 2;
    p1->score += 2;
  }
}

image.gif

之后,再写下双方比赛时如何选择的函数,首先,因为我们在初始化每种角色的时候将角色的对应名字定义到各自结构体的char name[]中,所以在双方比赛时我们可以通过比较结构体字符数组中的名字来认清各自的身份。

复读机,黑帮可以在先用isscore函数比较一次后,在进行判断,这样相当于第一轮比赛结束。

isscore(p1, p2);
  //实现复读机的函数
  if (strcmp(p1->name, "Fuduji") == 0)
  {
    p1->choice = p2->choice;
  }
  if (strcmp(p2->name, "Fuduji") == 0)
  {
    p2->choice = p1->choice;
  }
  //实现黑帮老大的函数
  if ((strcmp(p1->name, "heibang") == 0) && (p2->choice == 0))
  {
    p1->choice = 0;
  }
  if ((strcmp(p2->name, "heibang") == 0) && (p1->choice == 0))
  {
    p2->choice = 0;
  }

image.gif

小红与油条可以一直不用变,直接比较就行。

而福尔摩斯才是最麻烦的,为了判断前四轮是否有反击,所以我们可以创建一个int变量,如果反击则为1,不反击则为0,因为要前四轮要有不同的选择,所以要在isscore函数之前就已经判断先,并在比赛结束之后将轮数加1。

所以,福尔摩斯的代码如下:>

//注:int fuerp=0;已经在比赛函数之外定义了,因为之后还有别的函数需要用到
  //实现福尔摩斯函数
  //判断是否反击
  if ((strcmp(p1->name, "fuer") == 0) && ((p1->n == 2) || (p1->n == 3) || (p1->n == 4) || (p1->n == 1)))
  {
    if (p2->choice == 0)
    {
      fuerp = 1;
    }
  }
  if ((strcmp(p2->name, "fuer") == 0) && ((p2->n == 2) || (p2->n == 3) || (p2->n == 4) || (p2->n == 1)))
  {
    if (p1->choice == 0)
    {
      fuerp = 1;
    }
  }
    //在不同轮数做出不同选择
  if ((strcmp(p1->name, "fuer") == 0) && p1->n == 2)
  {
    p1->choice = 0;
  }
  if ((strcmp(p2->name, "fuer") == 0) && p2->n == 2)
  {
    p2->choice = 0;
  }
  if ((strcmp(p2->name, "fuer") == 0) && ((p2->n == 3) || (p2->n == 4)))
  {
    p2->choice = 1;
  }
  if ((strcmp(p1->name, "fuer") == 0) && ((p1->n == 3) || (p1->n == 4)))
  {
    p1->choice = 1;
  }
  if ((strcmp(p2->name, "fuer") == 0) && (p2->n > 4))
  {
    if (fuerp == 1)
    {
      p2->choice = p1->choice;
    }
    else if (fuerp == 0)
    {
      p2->choice = 0;
    }
  }
  if ((strcmp(p1->name, "fuer") == 0) && (p1->n > 4))
  {
    if (fuerp == 1)
    {
      p1->choice = p2->choice;
    }
    else if (fuerp == 0)
    {
      p1->choice = 0;
    }
  }
  isscore(p1, p2);
    //将轮数加1
  if (strcmp(p1->name, "fuer") == 0)
  {
    p1->n++;
  }
  if (strcmp(p2->name, "fuer") == 0)
  {
    p2->n++;
  }

image.gif

因此,双方比赛选择且结果的完整函数如下

//两者比赛
void paly(struct player* p1, struct player* p2)
{
  //实现福尔摩斯函数
  //判断是否反击
  if ((strcmp(p1->name, "fuer") == 0) && ((p1->n == 2) || (p1->n == 3) || (p1->n == 4) || (p1->n == 1)))
  {
    if (p2->choice == 0)
    {
      fuerp = 1;
    }
  }
  if ((strcmp(p2->name, "fuer") == 0) && ((p2->n == 2) || (p2->n == 3) || (p2->n == 4) || (p2->n == 1)))
  {
    if (p1->choice == 0)
    {
      fuerp = 1;
    }
  }
  if ((strcmp(p1->name, "fuer") == 0) && p1->n == 2)
  {
    p1->choice = 0;
  }
  if ((strcmp(p2->name, "fuer") == 0) && p2->n == 2)
  {
    p2->choice = 0;
  }
  if ((strcmp(p2->name, "fuer") == 0) && ((p2->n == 3) || (p2->n == 4)))
  {
    p2->choice = 1;
  }
  if ((strcmp(p1->name, "fuer") == 0) && ((p1->n == 3) || (p1->n == 4)))
  {
    p1->choice = 1;
  }
  if ((strcmp(p2->name, "fuer") == 0) && (p2->n > 4))
  {
    if (fuerp == 1)
    {
      p2->choice = p1->choice;
    }
    else if (fuerp == 0)
    {
      p2->choice = 0;
    }
  }
  if ((strcmp(p1->name, "fuer") == 0) && (p1->n > 4))
  {
    if (fuerp == 1)
    {
      p1->choice = p2->choice;
    }
    else if (fuerp == 0)
    {
      p1->choice = 0;
    }
  }
  isscore(p1, p2);
  if (strcmp(p1->name, "fuer") == 0)
  {
    p1->n++;
  }
  if (strcmp(p2->name, "fuer") == 0)
  {
    p2->n++;
  }
  //实现复读机的函数
  if (strcmp(p1->name, "Fuduji") == 0)
  {
    p1->choice = p2->choice;
  }
  if (strcmp(p2->name, "Fuduji") == 0)
  {
    p2->choice = p1->choice;
  }
  //实现黑帮老大的函数
  if ((strcmp(p1->name, "heibang") == 0) && (p2->choice == 0))
  {
    p1->choice = 0;
  }
  if ((strcmp(p2->name, "heibang") == 0) && (p1->choice == 0))
  {
    p2->choice = 0;
  }
}

image.gif

三.完成一次比赛之后的成员选择,轮数恢复

再双方进行完比赛后,例如复读机起初的选择是合作,如果和油条进行比赛后,复读机的选择将变成欺骗,所以每一次比赛后我们都应该把每个成员选,轮数恢复成初始的数据,这样有利于下一次与其他成员进行比赛时选择的正确性。

恢复的代码如下

void hireplayer(struct player* p1, struct player* p2)
{
  if (strcmp(p1->name, "Fuduji") == 0)
  {
    p1->choice = 1;
  }
  if (strcmp(p2->name, "Fuduji") == 0)
  {
    p2->choice = 1;
  }
  if (strcmp(p2->name, "heibang") == 0)
  {
    p2->choice = 1;
  }
  if (strcmp(p1->name, "heibang") == 0)
  {
    p1->choice = 1;
  }
  if (strcmp(p1->name, "fuer") == 0)
  {
    p1->choice = 1;
    p1->n = 1;
    fuerp = 0;
  }
  if (strcmp(p2->name, "fuer") == 0)
  {
    p2->choice = 1;
    p2->n = 1;
    fuerp = 0;
  }
}

image.gif

四.一次比赛中,成员多次比赛后数据的恢复

当某一位成员完成了与自己之外的其他成员比赛时,除了这位成员,其他的成员的分数也会因此改变,所以此时将那位已经完成全部比赛的成员作为结构体指针返回,再将所有的成员全部初始化一遍,这样就可以做到多次比赛总数据的恢复

例如在文件xioahong.c中写的小红比赛后恢复的代码

struct player* playxiaohong(struct player* Fuduji, struct player* xiaohong, struct player* youtiao, struct player* heibang, struct player* fuer, int Fuduji_num, int xiaohong_num, int youtiao_num, int heibang_num, int fuer_num)
{
  int i = 0;
  if (xiaohong_num == 0)
  {
    return xiaohong;
  }
  for (i = 0; i < Fuduji_num; i++)
  {
    paly(Fuduji, xiaohong);
  }
  hireplayer(Fuduji, xiaohong);
  for (i = 0; i < xiaohong_num - 1; i++)
  {
    paly(xiaohong, xiaohong);
  }
  hireplayer(xiaohong, xiaohong);
  for (i = 0; i < youtiao_num; i++)
  {
    paly(xiaohong, youtiao);
  }
  hireplayer(xiaohong, youtiao);
  for (i = 0; i < heibang_num; i++)
  {
    paly(xiaohong, heibang);
  }
  hireplayer(xiaohong, heibang);
  for (i = 0; i < fuer_num; i++)
  {
    paly(xiaohong, fuer);
  }
  hireplayer(xiaohong, fuer);
  return xiaohong;
  InitFuduji(&Fuduji);
  Initxiaohong(&xiaohong);
  Inityoutiao(&youtiao);
  Initheibang(&heibang);
  Initfuer(&fuer);
}

image.gif

其他成员也是类似的,最终的比赛完整版代码如下图

void Competition(struct player* Fuduji, struct player* xiaohong, struct player* youtiao, struct player* heibang, struct player* fuer, int Fuduji_num, int xiaohong_num, int youtiao_num, int heibang_num, int fuer_num)
{
  int i = 0;
  int j = 0;
  struct player* newFuduji=playFuduji(Fuduji, xiaohong, youtiao, heibang, fuer, Fuduji_num, xiaohong_num, youtiao_num, heibang_num, fuer_num);
  struct player* newxiaohong = playxiaohong(Fuduji, xiaohong, youtiao, heibang, fuer, Fuduji_num, xiaohong_num, youtiao_num, heibang_num, fuer_num);
  struct player* newyoutiao = playyoutiao(Fuduji, xiaohong, youtiao, heibang, fuer, Fuduji_num, xiaohong_num, youtiao_num, heibang_num, fuer_num);
  struct player* newheibang = playheibang(Fuduji, xiaohong, youtiao, heibang, fuer, Fuduji_num, xiaohong_num, youtiao_num, heibang_num, fuer_num);
  struct player* newfuer = playfuer(Fuduji, xiaohong, youtiao, heibang, fuer, Fuduji_num, xiaohong_num, youtiao_num, heibang_num, fuer_num);
  Fuduji = newFuduji;
  xiaohong = newxiaohong;
  youtiao = newyoutiao;
  heibang = newheibang;
  fuer = newfuer;
}

image.gif

这样可以成功比赛一次

五.比赛一次后增多减少

当一次比赛完成之后,我们要将硬币最少的给删去,硬币最多的给增加,这时候,我们可以创建两个结构体,一个max结构体里面的硬币数量为0,一个min结构体里的硬币数量为2147483647,阅历每个成员的硬币数量并和max的硬币与min的硬币做比较,如果硬币数量大于max,max的硬币就会被赋值跟他一样多,同理,如果硬币小于min的,min的硬币数量也会被赋值跟它一样多,这样阅历之后,便可以找到最大与最小硬币的的成员。

如下图

struct player* max = (struct player*)malloc(sizeof(struct player));
  struct player* min = (struct player*)malloc(sizeof(struct player));
  max->score = -1000;
  min->score = 2147483647;
  //判断最大
  if (Fuduji->score > max->score)
  {
    max->score= Fuduji->score;
  }
  if (xiaohong->score > max->score)
  {
    max->score = xiaohong->score;
  }
  if (youtiao->score > max->score)
  {
    max->score = youtiao->score;
  }
  if (heibang->score > max->score)
  {
    max->score = heibang->score;
  }
  if (fuer->score > max->score)
  {
    max->score = fuer->score;
  }
  //判断最小
  if (Fuduji->score < min->score)
  {
    min->score = Fuduji->score;
  }
  if (xiaohong->score < min->score)
  {
    min->score = xiaohong->score;
  }
  if (youtiao->score < min->score)
  {
    min->score = youtiao->score;
  }
  if (heibang->score < min->score)
  {
    min->score = heibang->score;
  }
  if (fuer->score < min->score)
  {
    min->score = fuer->score;
  }
    //找最大最小
  //找最小
  if (Fuduji->score == min->score)
  {
    *Fuduji_num-=1;
  }
  if (xiaohong->score == min->score)
  { 
    *xiaohong_num -= 1;
  }
  if (heibang->score == min->score)
  {
    *heibang_num -= 1;
  }
  if (fuer->score == min->score)
  {
    *fuer_num -= 1;
  }
  if (youtiao->score == min->score)
  {
    *youtiao_num -= 1;
  }
  //找最大
  if ((Fuduji->score == max->score) && (*Fuduji_num != 0))
  {
    *Fuduji_num+=1;
  }
  if ((xiaohong->score == max->score) && (*xiaohong_num != 0))
  {
    *xiaohong_num += 1;
  }
  if ((heibang->score == max->score) && (*heibang_num != 0))
  {
    *heibang_num+=1;
  }
  if (fuer->score == max->score)
  {
    *fuer_num += 1;
  }
  if ((youtiao->score == max->score) && (*youtiao_num != 0))
  {
    *youtiao_num += 1;
  }
}

image.gif

六.比赛过后打印菜单与游戏的最终效果

之后,可以用menu将菜单再重新打印一遍

最终游戏效果如下图

image.gif编辑

总代码文件已经上传到gitee上面了,有需要的朋友可以自己去下载

gitee网址:C-practice-10-13 · Elysian剑彧/text.c - 码云 - 开源中国 (gitee.com)

能力有限,如有错误还请海涵。

相关文章
|
19天前
|
C语言
扫雷游戏(用C语言实现)
扫雷游戏(用C语言实现)
61 0
|
3月前
|
存储 算法 C语言
"揭秘C语言中的王者之树——红黑树:一场数据结构与算法的华丽舞蹈,让你的程序效率飙升,直击性能巅峰!"
【8月更文挑战第20天】红黑树是自平衡二叉查找树,通过旋转和重着色保持平衡,确保高效执行插入、删除和查找操作,时间复杂度为O(log n)。本文介绍红黑树的基本属性、存储结构及其C语言实现。红黑树遵循五项基本规则以保持平衡状态。在C语言中,节点包含数据、颜色、父节点和子节点指针。文章提供了一个示例代码框架,用于创建节点、插入节点并执行必要的修复操作以维护红黑树的特性。
92 1
|
2月前
|
C语言
C语言判断逻辑的高阶用法
在C语言中,高级的判断逻辑技巧能显著提升代码的可读性、灵活性和效率。本文介绍了六种常见方法:1) 函数指针,如回调机制;2) 逻辑运算符组合,实现复杂条件判断;3) 宏定义简化逻辑;4) 结构体与联合体组织复杂数据;5) 递归与分治法处理树形结构;6) 状态机管理状态转换。通过这些方法,可以更高效地管理和实现复杂的逻辑判断,使代码更加清晰易懂。
221 88
|
20天前
|
编译器 C语言
猜数字游戏实现#C语言
猜数字游戏实现#C语言
63 1
|
21天前
|
存储 C语言
揭秘C语言:泊舟的猜数字游戏
揭秘C语言:泊舟的猜数字游戏
|
25天前
|
算法
条件运算符与条件if的姻缘,打擂台算法和大小写字母转换,if逻辑避坑
条件运算符与条件if的姻缘,打擂台算法和大小写字母转换,if逻辑避坑
16 1
|
27天前
|
存储 算法 安全
C语言实现扫雷游戏
C语言实现扫雷游戏
|
28天前
|
算法 编译器 C语言
【C语言】实现猜数字游戏(分支语句与循环语句的运用)
【C语言】实现猜数字游戏(分支语句与循环语句的运用)
|
20天前
|
C语言
初学者指南:使用C语言实现简易版扫雷游戏
初学者指南:使用C语言实现简易版扫雷游戏
27 0
|
21天前
|
C语言
C语言扫雷游戏(详解)
C语言扫雷游戏(详解)
32 0