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

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

相关文章
|
9天前
|
搜索推荐 C语言
【排序算法】快速排序升级版--三路快排详解 + 实现(c语言)
本文介绍了快速排序的升级版——三路快排。传统快速排序在处理大量相同元素时效率较低,而三路快排通过将数组分为三部分(小于、等于、大于基准值)来优化这一问题。文章详细讲解了三路快排的实现步骤,并提供了完整的代码示例。
32 4
|
1月前
|
C语言
扫雷游戏(用C语言实现)
扫雷游戏(用C语言实现)
84 0
|
2月前
|
C语言
C语言判断逻辑的高阶用法
在C语言中,高级的判断逻辑技巧能显著提升代码的可读性、灵活性和效率。本文介绍了六种常见方法:1) 函数指针,如回调机制;2) 逻辑运算符组合,实现复杂条件判断;3) 宏定义简化逻辑;4) 结构体与联合体组织复杂数据;5) 递归与分治法处理树形结构;6) 状态机管理状态转换。通过这些方法,可以更高效地管理和实现复杂的逻辑判断,使代码更加清晰易懂。
229 88
|
10天前
|
搜索推荐 算法 C语言
【排序算法】八大排序(上)(c语言实现)(附源码)
本文介绍了四种常见的排序算法:冒泡排序、选择排序、插入排序和希尔排序。通过具体的代码实现和测试数据,详细解释了每种算法的工作原理和性能特点。冒泡排序通过不断交换相邻元素来排序,选择排序通过选择最小元素进行交换,插入排序通过逐步插入元素到已排序部分,而希尔排序则是插入排序的改进版,通过预排序使数据更接近有序,从而提高效率。文章最后总结了这四种算法的空间和时间复杂度,以及它们的稳定性。
51 8
|
10天前
|
搜索推荐 算法 C语言
【排序算法】八大排序(下)(c语言实现)(附源码)
本文继续学习并实现了八大排序算法中的后四种:堆排序、快速排序、归并排序和计数排序。详细介绍了每种排序算法的原理、步骤和代码实现,并通过测试数据展示了它们的性能表现。堆排序利用堆的特性进行排序,快速排序通过递归和多种划分方法实现高效排序,归并排序通过分治法将问题分解后再合并,计数排序则通过统计每个元素的出现次数实现非比较排序。最后,文章还对比了这些排序算法在处理一百万个整形数据时的运行时间,帮助读者了解不同算法的优劣。
41 7
|
8天前
|
C语言 Windows
C语言课设项目之2048游戏源码
C语言课设项目之2048游戏源码,可作为课程设计项目参考,代码有详细的注释,另外编译可运行文件也已经打包,windows电脑双击即可运行效果
20 1
|
1月前
|
编译器 C语言
猜数字游戏实现#C语言
猜数字游戏实现#C语言
81 1
|
1月前
|
存储 C语言
揭秘C语言:泊舟的猜数字游戏
揭秘C语言:泊舟的猜数字游戏
|
1月前
|
算法
条件运算符与条件if的姻缘,打擂台算法和大小写字母转换,if逻辑避坑
条件运算符与条件if的姻缘,打擂台算法和大小写字母转换,if逻辑避坑
21 1
|
1月前
|
存储 算法 安全
C语言实现扫雷游戏
C语言实现扫雷游戏