您的位置:首页 > 编程语言

结对编程——黄金点小游戏的设计与实现

2016-04-09 13:35 447 查看
[b]个人感想[/b]

最近总是很纠结,关于如何平衡考研时间和学校课程时间,还有关于考研资料的选择。就是在这样一种状态下,我迎来了结对编程项目,两个人共同编程完成一个小游戏,说实话,刚开始时我对这个项目不怎么感兴趣,我总觉得应该把时间都放在考研上。还有一个原因就是,我觉得自己什么都不会,肯定会拖累队友,但是经过我们多次沟通后,我发现这个小游戏没有我想象中的那么难,而且我逐渐有点兴趣了,再加上和队友的多次沟通,我觉得结对编程是一件很有意思的事,两个人提出不同的想法然后讨论,再接着看着自己的想法都能慢慢的实现出来,而且它的优势就在于比个人编程完善很多。

[b]我的队友[/b]

我的队友是明仁江,他呢,在我看来人挺好的,对待这次项目很认真,准确来说,在我印象中,他做什么都很认真。他真的教了我很多东西,刚开始时,主动找我讨论对这个小游戏的想法,我们讨论了很多次,每次他都特别耐心的给我解释我不懂的地方,我和他刚开始都不会做界面,他就一点一点的学着做,每次有了新的进展都会一起看,他是一个很有能力的人,在软件工程课上表现的很优秀,开课没多久就把构建之法全书读完了,然后每次的博客写的都很细致,步骤写的很详细,逻辑思维很清晰,这点我必须要学习,我的博客写的一直都不怎么好。以后会多学习别人的优点,不断地改进。总之,我给我的队友大大的赞。

[b]程序设计[/b]

本次结对编程目标是:N个同学(N通常大于10),每人写一个0~100之间的有理数 (不包括0或100),交给裁判,裁判算出所有数字的平均值,然后乘以0.618(所谓黄金分割常数),得到G值。提交的数字最靠近G(取绝对值)的同学得到N分,离G最远的同学得到-2分,其他同学得0分。每次游戏至少可以运行10轮以上,并能够保留每轮比赛结果。

本次结对编程使用结构体来保存玩家信息和游戏成绩信息,分别是结构体数组player和achieve。还包含了五个基本函数分别是信息输入函数Input、玩家数字和黄金点比较函数Campare、裁判函数Referee、分数从高到低排序函数Sort、分数输出函数Output。

我的队友完成了程序的整个框架,和信息输入函数Input、裁判函数Referee,同时,队友还帮助实现了玩家数字和黄金点比较函数Campare、按分数从高到低排序函数Sort等。

[b]程序实现(C语言)[/b]

玩家信息保存结构体Game:

struct game
{
int number;
float digit;
int score;
};


int类型变量number为玩家编号,浮点类型变量digit为玩家输入的数字,int类型变量score为玩家成绩。

该程序的核心函数:

void Input(int peoplecount);  //信息输入
void Campare(int peoplecount, float goldpoint); //比较函数
void Referee(int gamecount, int peoplecount);   //输赢判断
void Sort(int peoplecount);   //分数排序
void Output(int peoplecount); //分数输出


玩家信息输入函数:

//玩家信息输入
void Input(int peoplecount)
{
int i;
for (i = 0;i < peoplecount;i++)
{
player[i] = new game;
printf("\t第%d号玩家,请输入数字:", i + 1);
player[i]->number = i;
scanf("%f", &player[i]->digit);
}
printf("\n");
}


依次输入玩家的信息,包括玩家的编号、玩家的数字。

裁判函数:

//输赢判断
void Referee(int gamecount, int peoplecount)
{
int i;
float sum = 0, goldpoint = 0;
for (i = 0;i < peoplecount;i++)
{
sum += player[i]->digit;
}
printf("\t本轮游戏的平均数为:%f。\n", sum / peoplecount);
goldpoint = (sum / peoplecount)*(0.618);
printf("\t本轮游戏的黄金点为:%f。\n", goldpoint);
printf("\n");
Campare(peoplecount, goldpoint);
}


在该函数中,用float类型sum变量来保存本轮游戏的平均数,float类型goldpoint变量保存本轮游戏的黄金点,还调用了玩家输赢比较函数Compare,以判断输赢玩家,并对所有玩家的分数输出。

玩家输赢比较函数:

//比较函数
void Campare(int peoplecount, float goldpoint)
{
int i;
float max, min, winpeople = 0, lospeople = 0;
max = min = fabs(player[0]->digit - goldpoint);
for (i = 0;i < peoplecount;i++)
{
if (fabs(player[i]->digit - goldpoint) <= min) //找到最接近黄金点的数
{
winpeople = player[i]->digit;
min = fabs(player[i]->digit - goldpoint);
}
if (fabs(player[i]->digit - goldpoint) >= max) //找到离黄金点最远的数
{
lospeople = player[i]->digit;
max = fabs(player[i]->digit - goldpoint);
}
}
for (i = 0;i < peoplecount;i++)
{
if (player[i]->digit == winpeople)
{
achieve[i]->score += peoplecount;
printf("\t第%d号玩家赢。\n", i + 1);
}
}
for (i = 0;i < peoplecount;i++)
{
if (player[i]->digit == lospeople)
{
achieve[i]->score -= 2;
printf("\t第%d号玩家输。\n", i + 1);
}
}
printf("\n");
}


在本函数中,先用float类型变量winpeople、lospeople分别保存离黄金点最近的数字和离黄金点最远的数字。给赢家和输家加分数或者减分数,再依次输出和winpeople、lospeople相等的玩家的编号。最后,对每个玩家的分数输出。

按分数从高到底排序函数Sort:

void Sort(int peoplecount)
{
int i, j;
for (i = 0;i < peoplecount;i++)
{
int tempsignal = i, tempnumber = achieve[i]->number, tempscore = achieve[i]->score;
tempnumber = achieve[i]->number;
tempscore = achieve[i]->score;
for (j = i + 1;j < peoplecount;j++)
{
if (tempscore< achieve[j]->score)
{
tempsignal = j;
tempnumber = achieve[j]->number;
tempscore = achieve[j]->score;
}
}
achieve[tempsignal]->number = achieve[i]->number;
achieve[tempsignal]->score = achieve[i]->score;
achieve[i]->number = tempnumber;
achieve[i]->score = tempscore;
}
}


该函数实现了玩家分数从大到小的排序。采用的排序方法是冒泡排序法。

玩家分数输出函数:

void Output(int peoplecount)
{
int i;
for (i = 0;i < peoplecount;i++)
{
printf("\t第%d号玩家:%d。\n", achieve[i]->number + 1, achieve[i]->score);
}
}


该函数实现了玩家分数的依次输出。

[b]程序运行(C语言)[/b]

程序开始界面:



程序开始界面,首先显示游戏规则,再提示输入游戏轮次和玩家个数,按回车,开始玩游戏。

第一轮游戏:



提示输入各个玩家的数字,然后计算出平均值和黄金点,判断哪些玩家赢,哪些玩家输。最后提示是否打印成绩。

打印第一轮游戏成绩:



第二轮游戏:



第二轮成绩:



游戏继续...

最后一轮游戏:



最后一轮游戏结果:



按分数从高到底显示各个玩家分数:



选择是否继续游戏。

[b]程序实现(C#语言)[/b]

程序入口:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;

namespace GoldPoint_Game
{
static class Program
{
/// <summary>
/// 应用程序的主入口点。
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new frmWelcome());
}
}
}


在program类中,运行程序欢迎窗体frmWelcome。

欢迎窗体:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace GoldPoint_Game
{
public partial class frmWelcome : Form
{
public frmWelcome()
{
InitializeComponent();
}

private void textBox1_TextChanged(object sender, EventArgs e)
{

}

private void frmWelcome_Load(object sender, EventArgs e)
{

}

private void button1_Click(object sender, EventArgs e)
{
GoldGame f1 = new GoldGame(textBox2.Text,textBox3.Text);
f1.ShowDialog();
this.Close();
}

private void textBox2_TextChanged(object sender, EventArgs e)
{
}

private void button2_Click(object sender, EventArgs e)
{
this.Close();
}
}
}


在该窗体中中,实现了对欢迎窗体的初始化,包括游戏规则的提示,游戏轮次、玩家个数的输入,退出游戏、进入游戏提示等。

游戏窗体:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace GoldPoint_Game
{
partial class GoldGame : Form
{
......
}
}


游戏窗体是该程序的主体部分。

一个Goldgame类和两个player,achieve列表:

class Goldgame
{
public int number;
public float digit;
public int score;
};
List<Goldgame> player = new List<Goldgame> { };
List<Goldgame> achieve = new List<Goldgame> { };


两个列表用于保存玩家的信息和玩家的成就。

两个整型变量gameCount、peopleCount:

private int gameCount;
private int peopleCount;
public int GameCount
{
get
{
return gameCount;
}
set
{
gameCount = value;
}
}

public int PeopleCount
{
get
{
return peopleCount;
}
set
{
peopleCount = value;
}
}

int rgameCount;
int rpeopleCount;

public GoldGame(string str1,string  str2)
{
InitializeComponent();
this.gameCount = Convert.ToInt32(str1);
this.peopleCount = Convert.ToInt32(str2);
}
public GoldGame()
{
InitializeComponent();
}


通过函数重载的方法,实现两个整型变量gameCount和peopleCount用于接收欢迎窗体传过来的游戏轮次和游戏玩家个数的值。

游戏窗体Load事件:

private void Form1_Load(object sender, EventArgs e)
{
int i;
rgameCount = 1;
rpeopleCount = 1;
for (i = 0; i <= peopleCount; i++)
{
Goldgame players = new Goldgame();
players.number = rpeopleCount-1;
players.digit = 0;
players.score = 0;
player.Add(players);
Goldgame achieves = new Goldgame();
achieves.number = rpeopleCount-1;
achieves.digit = 0;
achieves.score = 0;
achieve.Add(achieves);
rpeopleCount++;
}
rpeopleCount = 1;
label3.Text = "第" + rgameCount + "轮游戏:";
textBox1.Text = Convert.ToString(rpeopleCount);
textBox2.Text = "0";
}


该事件中,实现了对玩家信息列表和游戏成就列表的赋初值,和对各个控件的信息设置。

游戏输赢比较函数Campare:

void Campare(float goldpoint)
{
int i;
float max, min, winpeople = 0, lospeople = 0;
max = min = System.Math.Abs(player[1].digit - goldpoint);
for (i = 1; i <= peopleCount; i++)
{
if (System.Math.Abs(player[i].digit - goldpoint) <= min) //找到最接近黄金点的数
{
winpeople = player[i].digit;
min = System.Math.Abs(player[i].digit - goldpoint);
}
if (System.Math.Abs(player[i].digit - goldpoint) >= max) //找到离黄金点最远的数
{
lospeople = player[i].digit;
max = System.Math.Abs(player[i].digit - goldpoint);
}
}
for (i=1; i <= peopleCount; i++)
{
achieve[i].digit = player[i].digit;
}
listBox1.Items.Add('\n');
if (winpeople == lospeople)
{
listBox1.Items.Add("玩家数字一样,故不判断输赢!");
}
else
{
for (i = 1; i <= peopleCount; i++)
{
if (player[i].digit == winpeople)
{
achieve[i].score += peopleCount;
listBox1.Items.Add("第" + i + "号玩家赢。");
}
}
for (i = 1; i <= peopleCount; i++)
{
if (player[i].digit == lospeople)
{
achieve[i].score -= 2;
listBox1.Items.Add("第" + i + "号玩家输。");
}
}
}
listBox1.Items.Add('\n');
for (i = 1; i <= peopleCount; i++)
{
listBox1.Items.Add("第" + i + "号玩家," +"数字为:"+achieve[i].digit+ ",分数为:" + achieve[i].score);
}
}


首先找到离黄金点最近和最远的输,然后对离黄金点最近和最远的玩家进行分数的加和减操作,接着输出赢家或者输家。最后输出所有人的积累分数。

裁判函数Referee:

private void Referee()
{
int i;
float sum = 0, goldpoint = 0;
for (i = 1; i <= peopleCount; i++)
{
sum += player[i].digit;
}
label3.Text = "第"+rgameCount+"轮游戏结果如下:";
listBox1.Items.Clear();
listBox1.Items.Add("第"+rgameCount+"轮游戏平均数为:"+sum/peopleCount);
goldpoint = Convert.ToSingle(sum / peopleCount * 0.618);
listBox1.Items.Add("第" + rgameCount + "轮游戏黄金点为:" + sum / peopleCount*0.618);
Campare(goldpoint);
}


首先计算出所有玩家的分数之和,再算出平均数,输出平均数。再算出黄金点,输出黄金点,信息均输出到listBox1中。其中调用了输赢比较函数Campare。

输出分数按钮的Click事件:

private void button1_Click(object sender, EventArgs e)
{
if (rpeopleCount < peopleCount)
{
listBox1.Items.Add(Convert.ToString("玩家编号:"+ rpeopleCount+","+"玩家数字:"  + textBox2.Text));
player[rpeopleCount].number = rpeopleCount;
player[rpeopleCount].digit = Convert.ToSingle(textBox2.Text);
rpeopleCount++;
}
else if((rpeopleCount == peopleCount))
{
listBox1.Items.Add(Convert.ToString("玩家编号:" + rpeopleCount + "," + "玩家数字:" + textBox2.Text));
player[rpeopleCount].number = rpeopleCount;
player[rpeopleCount].digit = Convert.ToSingle(textBox2.Text);
textBox1.Text = Convert.ToString(rpeopleCount);
listBox1.Text = "第"+rgameCount+"游戏成绩如下:";
Referee();
MessageBox.Show("全部玩家已输入数字,请点击下一轮游戏!", "输入提示", MessageBoxButtons.OK, MessageBoxIcon.Information);

}
textBox1.Text = Convert.ToString(rpeopleCount);
}


对玩家信息的输入,同时显示到listBox1中,输入完毕,宣布本轮游戏的游戏成绩并提示进入下一轮。

下轮游戏按钮的Click事件:

private void button4_Click(object sender, EventArgs e)
{
if (rgameCount < gameCount)
{
rgameCount++;
label3.Text = "第" + rgameCount + "轮游戏:";
rpeopleCount = 1;
textBox1.Text = Convert.ToString(rpeopleCount);
listBox1.Items.Clear();
}
else
{
label3.Text = "第" + rgameCount + "轮游戏:";
textBox1.Text = Convert.ToString(rpeopleCount);
MessageBox.Show("游戏结束,请点击公布成绩!", "输入提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}


实现了对每轮游戏的玩家编号的初始化及各个控件的设置。若游戏结束,则会提示游戏结束并提示点击公布成绩。

按分数从高到底排序函数Sort:

private void Sort()
{
int i, j;
for (i = 1; i <= peopleCount; i++)
{
int tempsignal = i, tempnumber = achieve[i].number, tempscore = achieve[i].score;
tempnumber = achieve[i].number;
tempscore = achieve[i].score;
for (j = i + 1; j <= peopleCount; j++)
{
if (tempscore < achieve[j].score)
{
tempsignal = j;
tempnumber = achieve[j].number;
tempscore = achieve[j].score;
}
}
achieve[tempsignal].number = achieve[i].number;
achieve[tempsignal].score = achieve[i].score;
achieve[i].number = tempnumber;
achieve[i].score = tempscore;
}
}


该函数实现了对分数从高到底的排序,使用的排序方法是冒泡排序法。

公布成绩按钮的Click事件:

private void button2_Click(object sender, EventArgs e)
{
Sort();
int i;
label3.Text = "游戏分数排名:";
listBox1.Items.Clear();
for (i = 1; i <= peopleCount; i++)
{
listBox1.Items.Add("玩家编号:" + achieve[i].number + "," + "玩家分数:" + achieve[i].score);
}
}


该事件对游戏窗体的lLoad事件,实现了对玩家信息列表和游戏成就列表的清空,游戏轮次、游戏玩家的初始化以及各个控件的设置。

private void button5_Click(object sender, EventArgs e)
{
this.Close();
}


实现对窗口的关闭。

[b]程序运行(C#语言)[/b]

游戏欢迎界面:



游戏开始界面:



第一轮游戏:



所有玩家输入数字,提示进入下一轮游戏提示:



所有玩家输入数字,提示进入下一轮游戏提示:



游戏继续...

所有游戏轮次结束,提示公布成绩:





游戏分数排名:



点击重新开始:



若需继续游戏,则各玩家输入数字,继续游戏。若需退出游戏,请点击退出游戏。

下面附上几张讨论时的照片:







[b]编程体会[/b]

在这次编程过程中,我体会到了基础知识的重要性,从刚开始的什么都不太懂,到最后和我的队友共同完成这次结对编程,我收获了很多,碰到不会的地方就一起讨论,或者查资料。我和队友起初都不会做界面,然后一点一点的学,看c#的书,终于做出来了,可能不是很完美,但是我们尽了最大的努力。

我觉得结对编程比一个人编程能达到的效果会好很多,两个人的想法会多一点,可以让程序的功能等各方面都改进很多,我相信付出的汗水总会有回报的。我体会到了从来没有过的成就感。以后会更加努力,相信可以做的更好。

我的队友博客链接:http://www.cnblogs.com/visionming

队友coding地址:https://coding.net/u/mingrenjiang

我的coding地址:https://coding.net/u/sunxingzi
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: