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

个人感想

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

我的队友

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

程序设计

本次结对编程目标是: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等。

程序实现(C语言)

玩家信息保存结构体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);
    }
}

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

程序运行(C语言)

程序开始界面:

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

第一轮游戏:

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

打印第一轮游戏成绩:

第二轮游戏:

第二轮成绩:

 

游戏继续...

 

最后一轮游戏:

最后一轮游戏结果:

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

选择是否继续游戏。

程序实现(C#语言)

程序入口:

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();
        }

实现对窗口的关闭。

程序运行(C#语言)

游戏欢迎界面:

游戏开始界面:

第一轮游戏:

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

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

 

游戏继续...

 

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

游戏分数排名:

点击重新开始:

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

 

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

     

 

编程体会

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

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

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

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

    我的coding地址:https://coding.net/u/sunxingzi

posted on 2016-04-09 13:35  孙杏子  阅读(304)  评论(1编辑  收藏  举报

导航