• 来自童晶老师的游戏开发课程作业


    此作业的要求参见:https://edu.cnblogs.com/campus/nenu/2020Fall/homework/11577

    作业要求

    1.课程网址 [https://www.icourse163.org/course/HHU-1206797807]

    2.项目名称及分值

    游戏名称满分分值功能点提示
    生命游戏 20 随机初始化、生命算法、刷新显示

    3.作业提交要求

    除代码及git以外,要求 WBS、PSP,要求使用博客报告完成的功能和截图,讲解
    关键技术和代码片断。其中WBS要求包括不限于每个子任务的工时估算时间和实
    际耗时,精确到分钟。子任务可以包括分析、设计、代码、测试、调试、文档,
    鼓励精确到二级子任务如功能点等。

    项目coding地址: https://e.coding.net/jianghui2/lifegame/lib.git

    项目PSP:

    类型任务开始时间结束时间中断时间(分钟)delta时间(分钟)
    准备 问题了解及主要算法流程设计 12.18  19:28 12.18 20:12 0 44
    编程 代码编写 12.19  9:04 12.19  12:33 5+6 198
    编程 代码调试 12.19  18:06 12.19  19:50 2+5 97
    文档 技术文档编写 12.20  10:34 12:20  11:30 0 56

    项目WBS:

     

    关键技术:

    1.随机初始化
     

    为了实现随机初始化,调用了stdlib.h头文件中的rand函数,在c语言中用来产生一个随机数的函数。srand函数是随机数发生器的初始化函数。

    rand()函数每次调用前都会查询是否调用过srand(seed),是否给seed设定了一个值,如果有那么它会自动调用srand(seed)一次来初始化它的起始值。若之前没有调用srand(seed),那么系统会自动给seed赋初始值,即srand(1),自动调用它一次。

    为了避免rand()产生随机数时,因srand(seed)相同产生而产生相同的的随机数数组。所以在这里采用时间作种子 srand((unsigned)time(NULL))。每次运行程序的时间肯定是不相同的,产生的随机数就也不一样了。rand()产生的随机数和2取余得到随机的0或1,然后将随机数循环赋值给每一个细胞,得到一个随机的细胞生命的初始化状态。

     
    void randStart()// 数据随机初始化
    {
        int i, j;
        srand((unsigned)time(NULL));//让rund函数在每次程序运行中产生不同的随机数
        for ( i = 0; i < High; i++)
        {
            for ( j = 0; j < Width; j++)
            {
                cells[i][j] = rand() % 2;//随机数与2取余,得到随机的0或1
            }
        }
    }
    2.生命算法
     

    根据生命游戏演化的规则:

    一个由N*M个放个组成的矩形中,每个方格可以包含一个细胞,不在边上的有机体有8个相邻方格。

    1. 如果一个细胞周围有3个细胞为生,则该细胞为生(即该细胞若原先为死,则转为生,若原先为生,则保持不变)

    2. 如果一个细胞周围有2个细胞为生,则该细胞的生死状态保持不变

    3. 在其它情况下,该细胞为死(即该细胞若原先为生,则转为死,若原先为死,则保持不变)

     
     

    根据上述规则,用一个临时的二维数组nextCells,来记录Cells的下一个状态。每次对Cells中的点的周围情况neibourNumber进行统计,并据此更新nextCells的值,然后用nextCells更新cells的值。

     
    void cellUpdate()
    {
        int nextCells[Width][High];// 下一帧的细胞生命状态
        int neibourNumber;//细胞周围生存细胞数
        int i, j;
        for ( i = 1; i <= High-1; i++)
        {
            for ( j = 1; j <= Width-1; j++)
            {
                neibourNumber = cells[i - 1][j - 1] + cells[i - 1][j] + cells[i - 1][j + 1] + cells[i][j - 1] + cells[i][j + 1] + cells[i + 1][j - 1] + cells[i + 1][j] + cells[i + 1][j + 1];
                if (neibourNumber == 3)
                {
                    nextCells[i][j] = 1;
                }
                else if (neibourNumber == 2)
                {
                    nextCells[i][j] = cells[i][j];
                }
                else
                    nextCells[i][j] = 0;
            }
        }
        for (i = 1; i <= High - 1; i++)
        {
            for ( j = 1; j <= Width-1 ; j++)
            {
                cells[i][j] = nextCells[i][j];
            }
        }
    }
     
    3.刷新显示
     
    3.1移动光标

    在这里使用了控制台API函数SetConsoleCursorPosition,这个函数的功能是设置控制台光标坐标(Set--设置、Console--控制台、Cursor--光标、Position--坐标),使用这个函数需要两个参数:第一个参数类型为HANDLE,第二个参数类型为COORD。

    HANDLE是用来定义任何类型的句柄。函数功能:获取指定的标准设备的句柄,使用GetStdHandle需要一个参数,参数的取值有三种

    1.STDINPUTHANDLE----标准输入句柄,

    2.STDOUTPUTHANDLE----标准输出句柄,

    3.STDERRORHANDLE----标准错误句柄。

    所以在此处赋值给handle的是标准输出句柄

    COORD是Windows API中定义的一种结构,表示一个字符在控制台屏幕上的坐标

    使用上述类型以及函数必须包含windows.h头文件

     
    void gotoxy(int x, int y)//将光标移动到坐标(x,y)
    {
        HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
        COORD pos;
        pos.X = x;
        pos.Y = y;
        SetConsoleCursorPosition(handle, pos);//设置控制台光标坐标
    }
     
    3.2 刷新显示 
     
    void showCell()//从原点坐标刷新细胞状态
    {
        gotoxy(0,0);//清理上一帧状态
        int i, j;
        for ( i = 1; i <= High-1; i++)
        {
            for ( j = 1; j <= Width-1; j++)
            {
                if (cells[i][j]==1)
                {
                    cout << "*";
                }
                else
                {
                    cout << " ";
                }
            }
            cout << endl;
        }
    }
     
    4.主函数及效果展示图
     
    int main()
    {
        char judge;
        int count=0;
        int L;
        randStart();
        cout << "是否开始初始化细胞状态(Y/N)?" << endl;
        cin >> judge;
        while (judge!= 'Y' && judge!= 'y' && judge!= 'N' && judge!= 'n') {
            cout << "输入错误,请重新输入(Y/N)" << endl;
            cin >> judge;
        }
        while (judge== 'Y' || judge== 'y') {
            showCell();
            cellUpdate();
            count++;
            cout << "当前为第" << count <<"次繁衍后的细胞生命状态"<< endl ;
            cout << "请输入是否继续(Y/N)?" << endl;
            for(L=0;L<20;L++)
                cout << "                                                                " <<endl;
            gotoxy(0,31);
            cin >> judge;
            while (judge!= 'Y' && judge!= 'y' && judge!= 'N' && judge!= 'n') {
            cout << "输入错误,请重新输入(Y/N)" << endl;
            cin >> judge;
            }
        }
        cout << "感谢试玩!欢迎下次继续!" << endl;
        return 0;
    }

     

     


  • 相关阅读:
    Ruby: 获取IE的一些信息(其实应用AutoIt脚本本身,获取这些信息更加简单)
    Watir: 对浏览器的保存文件操作, 其实应用的是AutoIt脚本
    Watir: 右键点击实例(某些如果应用AutoIt来做会更加简单高效)
    Watir: Get document detail information in Watir.
    Ruby的一些常用全局变量
    Watir: 很久以前,对Watir开始学习时候做的笔记
    AutoIT: 开发界面结合GUI automation和Watir Automation
    AutoIT:为文件夹下面的文件批量改名
    AutoIT: 如何设置GUICtrlCreateCombo选项为不可修改状态
    AutoIT: GUISetFont VS GUICtrlSetFont
  • 原文地址:https://www.cnblogs.com/Jh-123/p/14174258.html
Copyright © 2020-2023  润新知