结对编程的作业:
黄金点游戏
黄金点游戏是一个数字小游戏,其游戏规则是:
N个同学(N通常大于10),每人写一个0~100之间的有理数 (不包括0或100),交给裁判,裁判算出所有数字的平均值,然后乘以0.618(所谓黄金分割常数),得到G值。提交的数字最靠近G(取绝对值)的同学得到N分,离G最远的同学得到-2分,其他同学得0分。玩了几天以后,大家发现了一些很有意思的现象,比如黄金点在逐渐地往下移动。
现在请大家根据这个游戏规则,编一个可以多人一起玩的小游戏程序,要求如下:
1、本作业属于结对编程项目,必须由二人共同完成,并分别将本次作业过程发到博客,同时将本次作业源代码提交到codeing系统;
2、如果可能的话尽量以C/S或B/S方式实现,即利用服务器接收和处理所有玩家提交的数字,并将结果反馈给各玩家,玩家可以通过客户端提交的数字;
3、如果采用单机方式实现的话,需要为用户提供便利的输入界面;
4、该游戏每次至少可以运行10轮以上,并能够保留各轮比赛结果。
进行情况:
黄金分割点0.0
#include "stdio.h" #include "math.h" #include "stdlib.h" void Game( ); struct Player { int num; //玩家编号 float score; //玩家输入的数据 float modulus; //绝对值数据 }m[10]; void Game() { struct Player m[10]; int i,j; float avescore; //平均值 float gloden_score; //黄金分割点 struct Player t; bool flag; int a; while(flag) { system("cls"); //清屏函数 avescore=0; printf(" "); for (i=0;i<10;i++) { m[i].num = i+1; printf (" 第%d位玩家输入的数据:",m[i].num); scanf ("%f",&m[i].score); avescore +=m[i].score; } avescore /=10; //求十个数的平均值 gloden_score=avescore*0.618; //求黄金分割点 printf(" "); printf (" 黄金分割点的值:%f ",gloden_score); printf(" "); for (i=0;i<10;i++) { m[i].modulus=fabs (gloden_score-m[i].score); //求绝对值 printf(" 第%d位玩家与黄金分割点的差是:%f ",m[i].num, m[i].modulus); } printf(" "); for(i=1;i<10;i++) for(j=0;j<10-i;j++) if (m[j].modulus>m[j+1].modulus) { t=m[j]; m[j]=m[j+1]; m[j+1]=t; } printf(" 游戏排行(排行顺序由高到低): "); for(i=0;i<10;i++) printf (" 玩家%d ",m[i].num); //冒泡排序 printf(" Do you want try again ? "); //判断是否继续游戏 printf(" Yes choose 1,No choose 2 "); printf(" 你的选择是:"); scanf("%d",&a); if (a==1) flag=true; else break; } return 0; }
这是最初的版本。
遇到的问题及解决方法
(1)问题:最开始使用的是一维数组,比较简单能进行玩家数据的存储,但玩家与数据不能一一对应,提取很不方便。
方案:用结构体进行数据的存储,可以是玩家和输入的数据进行一一对应,并且提取方便。
《基本实现了十个人玩一轮游戏的功能》
黄金分割点1.0
#include "stdafx.h" #include "stdio.h" #include "math.h" #include "stdlib.h" int Game(); void Introduce(); #define NUM 100 struct Player { int num; //玩家编号 float score; //玩家输入的数据 float modulus; //绝对值数据 }m[NUM]; void main(int argc, char* argv[]) { int choose=0; int flag01; while (1) { system("cls"); printf(" "); printf(" 请选择您要进行的操作: "); printf(" 1.开始游戏 "); printf(" 2.游戏介绍 "); printf(" 请输入您进行操作的序号:"); fflush(stdin); flag01=scanf ("%d",&choose); switch (choose) { case 1: system("cls"); Game(); break; case 2: system("cls"); Introduce(); system("pause"); break; default: printf("输入错误,请重新输入!"); break; } } } int Game() { struct Player m[NUM]; int i,j,k,flag01; int Player_num; //玩家人数 int Time; //游戏次数 float avescore; //平均值 float gloden_score; //黄金分割点 struct Player t; bool flag; int a; while(flag) { system("cls"); printf(" "); printf(" 有几个小伙伴要试试呀!(童鞋,少于是10个人不够运费~) "); printf(" "); fflush(stdin); flag01=scanf ("%d",&Player_num); //错误数据处理 if(Player_num>=10) { flag=false; } } flag=true; while(flag) { system("cls"); printf(" "); printf(" 童鞋你想玩儿几轮???(勇者,你必须至少玩儿10轮哦) "); printf(" "); fflush(stdin); flag01=scanf("%d",&Time); //错误数据处理 if(Time>=10) { flag=false; } } for (k=0;k<Time;k++) { system("cls"); //清屏函数 avescore=0; printf(" "); for (i=0;i<Player_num;i++) { m[i].num = i+1; printf (" 第%d位玩家输入的数据:",m[i].num); scanf ("%f",&m[i].score); avescore +=m[i].score; } avescore /=Player_num; //求十个数的平均值 gloden_score=avescore*0.618; //求黄金分割点 printf(" "); printf (" 黄金分割点的值:%f ",gloden_score); printf(" "); for (i=0;i<Player_num;i++) { m[i].modulus=fabs (gloden_score-m[i].score); //求绝对值 printf(" 第%d位玩家与黄金分割点的差是:%f ",m[i].num, m[i].modulus); } printf(" "); for(i=1;i<Player_num;i++) for(j=0;j<10-i;j++) if (m[j].modulus>m[j+1].modulus) { t=m[j]; m[j]=m[j+1]; m[j+1]=t; } printf(" 游戏排行(排行顺序由高到低): "); for(i=0;i<Player_num;i++) printf (" 玩家%d ",m[i].num); //冒泡排序 printf(" Do you want try again ? "); //判断是否继续游戏 printf(" Yes choose 1,No choose 2 "); printf(" 你的选择是:"); scanf("%d",&a); if (a==2) { printf("童鞋,游戏不符合心意吗?真要狠心抛弃哦?"); scanf("%d",&a); if(a==2) break; } } return 0; } void Introduce() { printf (" 黄金点游戏是一个数字小游戏,其游戏规则是: "); printf(" N个同学(N通常大于10),每人写一个0~100之间的有理数 (不包括0或100),交给裁判,"); printf("裁判算出所有数字的平均值,然后乘以0.618(所谓黄金分割常数),得到G值。"); printf("提交的数字最靠近G(取绝对值)的同学得到N分,离G最远的同学得到-2分,其他同学得0分。"); printf(" 玩了几天以后,大家发现了一些很有意思的现象,比如黄金点在逐渐地往下移动。 "); }
经过对版本0.0进行测试之后,主要存在以下几个问题
1.如果玩家数据输入的不是数字,程序会崩溃。
改进方法:目前还没有进展,有方法可以完成必须输入数字但情况有点不同,还在探讨中。。。。
2.玩家人数固定,不能由用户自己选择。
while(flag) { system("cls"); printf(" "); printf(" 有几个小伙伴要试试呀!(童鞋,少于是10个人不够运费~) "); printf(" "); fflush(stdin); flag01=scanf ("%d",&Player_num); //错误数据处理 if(Player_num>=10) { flag=false; } }
改进方法:在程序中加入选择模块,人数必须十人以上,才能跳出循环,而且可以容错。当你输入的不是数字时程序也可以识别出来。
错误数据处理利用的是输入缓存区处理。下面是具体解释:
这个程序首先会提示用户输入一个整数,然后等待用户输入,如果用户输入的是整数,程序会输出刚才输入的整数,并且再次提示用户输入一个整数,然后等待用户输入。但是一旦用户输入的不是整数(如小数或者字母),假设 scanf 函数最后一次得到的整数是 2 ,那么程序会不停地输出“Please input an integer: 2”。这是因为scanf("%d", &i);只能接受整数,如果用户输入了字母,则这个字母会遗留在“输入缓冲区”中。因为缓冲中有数据,故而 scanf 函数不会等待用户输入,直接就去缓冲中读取,可是缓冲中的却是字母,这个字母再次被遗留在缓冲中,如此反复,从而导致不停地输出“Please input an integer: 2”。也许有人会说:“居然这样,那么在 scanf 函数后面加上‘fflush(stdin);’,把输入缓冲清空掉不就行了?”然而这是错的!C和C++的标准里从来没有定义过 fflush(stdin)。也许有人会说:“可是我用 fflush(stdin) 解决了这个问题,你怎么能说是错的呢?”的确,某些编译器(如VC6)支持用 fflush(stdin) 来清空输入缓冲,但是并非所有编译器都要支持这个功能(linux 下的 gcc 就不支持),因为标准中根本没有定义 fflush(stdin)。MSDN 文档里也清楚地写着fflush on input stream is an extension to the C standard(fflush 操作输入流是对 C 标准的扩充)。当然,如果你毫不在乎程序的移植性,用 fflush(stdin) 也没什么大问题。以下是 C99 对 fflush 函数的定义:
int fflush(FILE *stream);
如果 stream 指向输出流或者更新流(update stream),并且这个更新流最近执行的操作不是输入,那么 fflush 函数将把这个流中任何待写数据传送至宿主环境(host environment)写入文件。否则,它的行为是未定义的。
3.游戏不能自己进行十轮以上
改进方法:与玩家人数的改进方法类似,就不再多加解释了。附上代码
while(flag) { system("cls"); printf(" "); printf(" 童鞋你想玩儿几轮???(勇者,你必须至少玩儿10轮哦) "); printf(" "); fflush(stdin); flag01=scanf("%d",&Time); //错误数据处理 if(Time>=10) { flag=false; } }