第二次博客作业-结对编程第二阶段

一、实验目标
  1)体验敏捷开发中的两人合作。

  2)进一步提高个人编程技巧与实践。

二 、实验内容
  1)根据以下问题描述,练习结对编程(pair programming)实践;

  2)要求学生两人一组,自由组合。每组使用一台计算机,二人共同编码,完成实验要求。

  3)要求在结对编程工作期间,两人的角色至少切换 4 次;

  4)编程语言不限,版本不限。建议使用 Python 或 JAVA 进行编程。

 

三、队员信息

  杜家云 杜蒙蒙
博客地址 https://www.cnblogs.com/cloudyyy/ https://www.cnblogs.com/qingmuling/
github地址 https://github.com/cloudy-y/game_of_life https://github.com/qingmuling/my-travel-plans-1

 

 

四、代码规范

1、变量名不可以是关键字,尽量做到见名知意。
2、宏定义里变量名全大写。
3、函数名采用小驼峰式命名法。
4、缩进正确
5、注释简明易懂

五、程序的总体设计

第二次博客作业-结对编程第二阶段_第1张图片

 

 六、结对编程过程

    本次结对编程实验我们队主要是在qq上使用qq屏幕分享以及在github上提交代码来完成的。

第二次博客作业-结对编程第二阶段_第2张图片

 

 

第一次互换 杜蒙蒙同学完成矩阵初始化模块,杜家云同学进行纠错。
第二次互换 杜家云同学完成下一时刻细胞分布模块与矩阵输出模块,杜蒙蒙同学进行纠错。
第三次互换 杜蒙蒙同学对功能模块进行整合,调用,完善程序,杜家云同学进行纠错。
第四次互换 程序完成后出错,杜家云同学进行修改
第五次互换 杜蒙蒙同学对程序进行进一步完善,修改。程序完成

 

 

七、功能模块

上一阶段我们队初步讨论是使用老师建议的python代码编写程序,但是这周经过深入讨论觉得我们还是对c/c++代码更加熟悉一些,于是觉得改成C++代码编写程序。

1、初始化矩阵

    使用随机函数随机选择细胞的初始生存状态。

 1 void InitMap()        //初始化细胞矩阵
 2 {
 3     killAll();
 4 
 5     srand((unsigned)time(NULL)); //用时间做种,每次产生随机数不一样
 6 
 7     for (int i = 0; i < WIDTH; ++i)
 8     {
 9         for (int j = 0; j < HEIGHT; ++j)
10         {
11             int Alive = rand() % 2;  //产生0或1的随机数
12             setCurCell(i, j, Alive);
13         }
14 
15     }
16 }

初始化细胞状态后,设置矩阵

 1 void setCurCell(int x, int y, int Alive)  //设置当前细胞矩阵细胞存活状态
 2 {
 3     if (locValid(x, y) == 0)
 4     {
 5         return;
 6     }
 7     else
 8     {
 9         SCell* cell = getCell(current_map, x, y);  //getCell函数为获得细胞的生存状态
10         if (cell - current_map >= WIDTH * HEIGHT)
11         {
12             return;
13         }
14         cell->Alive = Alive;
15     }
16 }

 

2、下一时刻细胞矩阵

    根据生命游戏规则来计算当前细胞下一时刻的生存状态。下面程序是用来计算周围八个位置存活的细胞数量

 1 int getAroundCellNum(int x, int y)   //计算周围存活细胞数量
 2 {
 3     int count = 0;
 4 
 5     if (locValid(x, y) == 0)  //边界判断
 6     {   
 7         return -1;
 8     }
 9     //测试目标位置周围的八个相邻位置
10     for (int i = x - 1; i <= x + 1; ++i)
11     {
12         for (int j = y - 1; j <= y + 1; ++j)
13         {
14             if (i == x && j == y)
15             {
16                 continue;
17             }
18             if (locValid(i, j) == 1)
19             {
20                 if (getCellAlive(i, j) == 1)
21                 {
22                     count++;
23                 }
24             }
25         }
26     }
27 
28     return count;
29 }

以下程序用来计算下一时刻的细胞矩阵,其规则如下:

每个细胞的生死遵循下面的原则:
①如果一个细胞周围有3个细胞为生(一个细胞周围共有8个细胞),则该细胞为生(即该细胞若原先为死,则转为生,若原先为生,则保持不变) 。
② 如果一个细胞周围有2个细胞为生,则该细胞的生死状态保持不变;
③在其它情况下,该细胞为死

 1 void nextStep(void)     //根据规则计算下一时刻细胞矩阵
 2 {
 3     int aroundNum = 0;
 4     for (int i = 0; i < WIDTH; ++i)
 5     {
 6         for (int j = 0; j < HEIGHT; ++j)
 7         {
 8             aroundNum = getAroundCellNum(i, j);
 9             if (aroundNum == 2)
10             {
11                 setNewCell(i, j, getCellAlive(i, j));
12             }
13             else if (aroundNum == 3)
14             {
15                 setNewCell(i, j, 1);
16             }
17             else
18             {
19                 setNewCell(i, j, 0);
20             }
21         }
22     }
23     swapMap();
24 }

 

3、输出矩阵

    本阶段实验我们队并未实现GUI界面的编程,只是输出0/1矩阵,用0,1代码表示细胞的生死,在下周的实验中我们会做关于生命游戏的界面,并进一步去完善程序,使其能够实现更多的功能。

 1 void print()  //输出细胞矩阵
 2 {
 3     int k;
 4     for(int i=0;i)
 5     {
 6         for(int j=0;j)
 7         {
 8           k=getCellAlive(i,j);
 9           if(k==0)  printf("0 ");
10           else if(k==1) printf("1 ");
11         }
12         printf("\n");
13     }
14     
15 }

以下是输出结果预览图

第二次博客作业-结对编程第二阶段_第3张图片                                           第二次博客作业-结对编程第二阶段_第4张图片

 

4、清屏

    清屏功能是将细胞全部杀死,即矩阵全部置0。本次实验中虽然编写了该模块,但并未调用,这是为后续界面做的基础功能,在下一阶段界面设计好后会添加清屏功能。

 1 void killAll(void)                //清屏
 2 {
 3     if (current_map != NULL && new_map != NULL)
 4     {
 5         for (int i = 0; i < WIDTH; ++i)
 6         {
 7             for (int j = 0; j < HEIGHT; ++j)
 8             {
 9                 setCurCell(i, j, 0);
10                 setNewCell(i, j, 0);
11             }
12         }
13     }
14 
15 }

 

4月5日更新

5、界面功能

    本次界面功能我与杜家云同学多次交换角色,没有明确的区分驾驶员和领航员,我们在网络上查找了很多关于windows编程的资料,最后主要在CSDN找到了一位博主学习windows编程的学习笔记,以下是笔记之一的链接

https://blog.csdn.net/nullccc/article/details/81188355

跟着这位博主的学习笔记,让我们对于windows编程有了很大的了解,并能够根据这个,进行简单的绘制窗口。以下是程序的主要绘制代码,由于windows编程绘制窗口涉及的代码很多,下面代码仅涉及绘制生命游戏世界。

 1 void DrawWorld(CWorld * world, int world_w, int world_h, HDC hdc)
 2 {
 3     CleanWorld(hdc);
 4     DrawGrid(hdc, world_w, world_h);
 5     DrawCell(world, hdc);
 6 }
 7 
 8 //将世界涂成黑色(背景色)
 9 void CleanWorld(HDC hdc)
10 {
11     HPEN BlackPen = CreatePen(PS_SOLID, 1, RGB(0,0,0));//建立画笔
12     HBRUSH BlackBrush = CreateSolidBrush(RGB(0,0,0));//建立阴影画刷
13     SelectObject(hdc, BlackPen);//选用GDI对象
14     SelectObject(hdc, BlackBrush);
15 
16     //画矩形
17     Rectangle(hdc, 0, 0, WORLD_WIDTH * CELL_SIZE, WORLD_HEIGHT * CELL_SIZE);
18     DeleteObject(BlackPen);//删除GDI对象
19     DeleteObject(BlackBrush);
20 }
21 
22 //描画所有细胞
23 void DrawCell(CWorld* world, HDC hdc)
24 {
25     HPEN WhitePen = CreatePen(PS_SOLID, 1, RGB(255,250,240));
26     HBRUSH WhiteBrush = CreateSolidBrush(RGB(255,250,240));
27     SelectObject(hdc, WhitePen);
28     SelectObject(hdc, WhiteBrush);
29     for (int i = 0; i < world->getWidth(); ++i)
30     {
31         for (int j = 0; j < world->getHeight(); ++j)
32         {
33             if (world->getCellAlive(i, j) == 1)
34             {
35                 Rectangle(hdc, i * CELL_SIZE, j * CELL_SIZE, i * CELL_SIZE + CELL_SIZE, j * CELL_SIZE + CELL_SIZE);
36             }
37         }
38     }
39 
40     DeleteObject(WhitePen);
41     DeleteObject(WhiteBrush);
42 }
43 
44 //描画网格
45 void DrawGrid(HDC hdc, int w, int h)
46 {
47     HPEN GrayPen = CreatePen(PS_SOLID, 1, RGB(128, 128, 128));
48     SelectObject(hdc, GrayPen);
49     for (int i = 0; i <= w; ++i)
50     {
51         MoveToEx(hdc, i * CELL_SIZE, 0, NULL);//移动目标
52         LineTo(hdc, i * CELL_SIZE, h * CELL_SIZE);//画线
53     }
54     for (i = 0; i <= h; ++i)
55     {
56         MoveToEx(hdc, 0, i * CELL_SIZE, NULL);
57         LineTo(hdc, w * CELL_SIZE, i * CELL_SIZE);
58     }
59 
60     DeleteObject(GrayPen);
61 }

以下是预览图

第二次博客作业-结对编程第二阶段_第5张图片 第二次博客作业-结对编程第二阶段_第6张图片

 

 

八、github项目

下图是我们的github项目仓库

第二次博客作业-结对编程第二阶段_第7张图片

 

 下面两张图是我的提交记录

第二次博客作业-结对编程第二阶段_第8张图片

                                                                                                 提交图1

 

 

 第二次博客作业-结对编程第二阶段_第9张图片

 

                                                                                                            提交图2

 

 九、实验总结

结对编程过程中遇到的问题:

1、在第一阶段讨论各模块的功能时,我们觉得边界细胞的计算与内部细胞计算方式应该不同,故而准备在边界设一圈死细胞,方便里面的细胞计算,但后来在编写代码时我们尝试编写讨论发觉完全没必要,只需要多加一个边界判断模块,就可以很轻松的解决边界问题。

2、同样是在第一阶段讨论时,我们准备在初始化的时候,一开始默认为死,初始化活细胞,其余默认为死,而本次经过讨论后,直接使用随机函数,为细胞

赋值0或1

3、在下一时刻细胞矩阵模块中,由于我们在编写代码时的配合不够默契,导致最后整合功能模块代码的时候出现了错误。修改后,运行成功。

4、代码完成后,由于我们的程序只能运行一次,只能观察到一次单步演化,故而增加了循环后,可以多次进行单步演化。

5、在添加了界面功能之后,由于一开始我们是在win32 application下编写的程序,并没有报错,但之后在将代码复制给对方时,却发现直接运行.cpp文件会报错,上网查询后发现,我们是因为windows子系统设置错误,将Console子系统换成windows子系统后就没有报错了。

 本次结对编程相对于以前传统的单人编程给我的感觉很不一样,一个人写代码时很容易陷入自己的思维误区,而结对编程则可以很好的避免这一点,结对编程工作效果绝对是1+1>2的。而由于我和队友组队时间不长,故而彼此之间还不够默契,有些地方难免会磨合不到位,有些小失误,但也能基本解决问题。本次实验让我对于c++的windows编程有了很大的认识,并对于c++类的了解有了很大的进步。但由于时间关系,还有很多功能没能实现。

 

你可能感兴趣的:(第二次博客作业-结对编程第二阶段)