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


    个人感想

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

    我的队友

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

    程序设计

    本次结对编程目标是: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("	第%d号玩家,请输入数字:", i + 1);
            player[i]->number = i;
            scanf("%f", &player[i]->digit);
        }
        printf("
    ");
    }

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

    裁判函数:

    //输赢判断
    void Referee(int gamecount, int peoplecount)
    {
        int i;
        float sum = 0, goldpoint = 0;
        for (i = 0;i < peoplecount;i++)
        {
            sum += player[i]->digit;
        }
        printf("	本轮游戏的平均数为:%f。
    ", sum / peoplecount);
        goldpoint = (sum / peoplecount)*(0.618);
        printf("	本轮游戏的黄金点为:%f。
    ", goldpoint);
        printf("
    ");
        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("	第%d号玩家赢。
    ", i + 1);
            }
        }
        for (i = 0;i < peoplecount;i++)
        {
            if (player[i]->digit == lospeople)
            {
                achieve[i]->score -= 2;
                printf("	第%d号玩家输。
    ", i + 1);
            }
        }
        printf("
    ");
    }

    在本函数中,先用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("	第%d号玩家:%d。
    ", 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('
    ');
                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('
    ');
                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

  • 相关阅读:
    对弈类游戏的人工智能(5)--2048游戏AI的解读
    对弈类游戏的人工智能(4)--游戏AI的落地
    对弈类游戏的人工智能(3)--博弈树优化
    对弈类游戏的人工智能(2)--学习算法
    java.awt.headless 模式
    SpringBoot启动过程分析
    SpringBoot入门之内嵌Tomcat配置
    git tag的用法
    SpringBoot程序远程debug
    SpringBoot入门之分散配置
  • 原文地址:https://www.cnblogs.com/sunxingzi/p/5341688.html
Copyright © 2020-2023  润新知