《信任的进化》游戏简易版逻辑算法的实现(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)

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

相关文章
|
26天前
|
机器学习/深度学习 C语言
九/十:《初学C语言》— 扫雷游戏实现和函数递归基础
【8月更文挑战第5天】本篇文章用C语言采用多文件编写实现了一个基础的扫雷游戏(附源码),并讲解了关于函数递归的基础概念及其相对应的习题练习(附源码)
32 1
九/十:《初学C语言》— 扫雷游戏实现和函数递归基础
|
11天前
|
存储 算法 C语言
"揭秘C语言中的王者之树——红黑树:一场数据结构与算法的华丽舞蹈,让你的程序效率飙升,直击性能巅峰!"
【8月更文挑战第20天】红黑树是自平衡二叉查找树,通过旋转和重着色保持平衡,确保高效执行插入、删除和查找操作,时间复杂度为O(log n)。本文介绍红黑树的基本属性、存储结构及其C语言实现。红黑树遵循五项基本规则以保持平衡状态。在C语言中,节点包含数据、颜色、父节点和子节点指针。文章提供了一个示例代码框架,用于创建节点、插入节点并执行必要的修复操作以维护红黑树的特性。
37 1
|
2月前
|
存储 C语言 开发者
C语言实战 | Flappy Bird游戏
【7月更文挑战第4天】Flappy Bird是由越南开发者制作的简单却极具挑战性的游戏,玩家需控制小鸟穿越水管障碍。游戏涉及角色初始化、显示和更新。小鸟和水管结构体存储数据,使用变量和数组。初始化小鸟和水管,显示背景、小鸟和水管,更新小鸟位置及碰撞检测。代码示例展示了小鸟和水管的状态管理,当小鸟与管道碰撞或触地时,游戏结束。游戏的成功在于其独特的虐心体验。
44 0
C语言实战 | Flappy Bird游戏
|
12天前
|
算法 编译器 C语言
【C语言篇】猜数字游戏(赋源码)
rand函数会返回⼀个伪随机数,这个随机数的范围是在0~RAND_MAX之间,这个RAND_MAX的⼤⼩是依赖编译器上实现的,但是⼤部分编译器上是32767。
|
22天前
|
人工智能 算法 Java
LeetCode经典算法题:井字游戏+优势洗牌+Dota2参议院java解法
LeetCode经典算法题:井字游戏+优势洗牌+Dota2参议院java解法
33 1
|
30天前
|
机器学习/深度学习 算法 数据挖掘
决策树算法大揭秘:Python让你秒懂分支逻辑,精准分类不再难
【8月更文挑战第2天】决策树算法以其直观性和解释性在机器学习领域中独具魅力,尤其擅长处理非线性关系。相较于复杂模型,决策树通过简单的分支逻辑实现数据分类,易于理解和应用。本示例通过Python的scikit-learn库演示了使用决策树对鸢尾花数据集进行分类的过程,并计算了预测准确性。虽然决策树优势明显,但也存在过拟合等问题。即便如此,无论是初学者还是专家都能借助决策树的力量提升数据分析能力。
22 4
|
16天前
|
算法
互动游戏解决遇到问题之基于射线投射寻路算法的问题如何解决
互动游戏解决遇到问题之基于射线投射寻路算法的问题如何解决
|
2月前
|
算法 搜索推荐 测试技术
python中算法逻辑错误(Logic Errors)
【7月更文挑战第18天】
42 2
|
20天前
|
算法 Python
【python】python基于 Q-learning 算法的迷宫游戏(源码+论文)【独一无二】
【python】python基于 Q-learning 算法的迷宫游戏(源码+论文)【独一无二】
|
2月前
|
存储 编译器 C语言
C语言实战 | “贪吃蛇”游戏
【7月更文挑战第5天】在C语言实战中,本文档介绍了如何构建一个简单的“贪吃蛇”游戏。游戏的核心是控制蛇移动并增长,当吃掉食物时,蛇的身体变长。数据结构使用固定大小的数组表示蛇的位置,变量存储食物位置和蛇的长度。初始化后,利用非阻塞式`getKey()`函数实现WASD键盘控制蛇的运动方向。虽然蛇的边界检测和吃食物后的增长尚未详细说明,但提到了这些问题作为练习留给读者解决,并预告将在后续章节讨论模块化编程以简化复杂代码。
70 0
C语言实战 | “贪吃蛇”游戏
下一篇
云函数