结对项目

Github地址


PSP 2.1 表格

 

PSP2.1Personal Software Process Stages预估耗时(分钟)实际耗时(分钟)
Planning 计划 10 10
· Estimate · 估计这个任务需要多少时间 10 10
Development 开发 620 800
· Analysis · 需求分析 (包括学习新技术) 120 150
· Design Spec · 生成设计文档 20 20
· Design Review · 设计复审 (和同事审核设计文档) 40 30
· Coding Standard · 代码规范 (为目前的开发制定合适的规范) 20 20
· Design · 具体设计 60 50
· Coding · 具体编码 240 360
· Code Review · 代码复审 60 50
· Test · 测试(自我测试,修改代码,提交修改) 60 120
Reporting 报告 70 60
· Test Report · 测试报告 30 20
· Size Measurement · 计算工作量 10 10
· Postmortem & Process Improvement Plan · 事后总结, 并提出过程改进计划 30 30
  合计 700 870

 


 

第一阶段

1.接口实现

 

接口设计说明

 

Information Hiding

 

接口隐藏实现细节和实例属性,接口的调用者无法直接修改对象的属性。对成员形成安全保护。

 

Interface Design

 

接口设计方便代码复用,是对一种操作或实现的抽象表示。对于现代软件工程极其重要,我们撰写的软件会使用大量标准库和第三方库的接口。

 

Loose Coupling

 

松耦合。模块之间的依赖有限。修改其中的任意一个模块内部的实现细节,不应对其他模块造成影响。其他模块不需要进行任何代码上的修改,也能保持功能的正常。

 

我们在阶段一进行接口设计时,就利用了这些思想。比如,接口对内部信息的隐藏。一个调用者对接口的调用,不用知道其具体实现,也不用担心对其内部的副作用。松耦合也是我们特别关注的。命令行程序与GUI程序公用一个Core.DLL,对Core.dll的更新不会影响其他程序的实现。

 

 

计算模块名为Core,包含2个命名空间(每人开发一个),包括9个类,大约30个函数。他们之间的关系组织见后面的UML图。

 

关键函数,生成唯一解的数独残局:

 

关键部分:每挖一个空,就判断是否是唯一解

 

独到之处:比起挖完空之后,再判断是否唯一解,减少了大量试错,提高了时间效率

 

UML图

 

 

接口1

 

void generate(int number, ref int[][,] result)

 

 

我们个人项目已经实现了生成特定数目的数独并写入文件的功能,此接口与之不同的是:需要将结果存入result中。

 

我们需要在生成过程中,维护一个3维数组,生成一个新的数独就存入其中(之前是直接写入文件,可扩展性比较差,且IO消耗巨大)。

 

接口2

 

void generate(int number, int mode, ref int[][,] result)

 

 

  • [number]的范围限定为1 - 10000。
  • [mode]的范围限定为1 - 3,不同的数字代表了数独游戏的难度级别,如下表所示:
编号级别
1 简单
2 中等
3 困难

 

我们个人项目已经实现了生成特定数目的数独并写入文件,和生成数独残局的功能。此接口的不同之处在于:

 

  • 不能将结果直接写入文件,而是写入result参数;
  • 增加生成特定难度数独的功能
  • 生成数独残局

 对难度的定义:

一般情况下,给定的数字个数越多,数独相对越简单。

通过参考资料,我们将我们的数独游戏的难度定义为:

 

难度挖空数
简单 45~49
中等 50~54
困难 55~59

 

接口3

 

void generate(int number, int lower, int upper, ref int[][,] result)

 

  • [lower] 的值最小为20,
  • [upper] 的值最大为55,
  • [upper] >= [lower]。

 

接口4

 

bool solve(int[,] puzzle, int[,] solution)


对于输入的数独题目puzzle,返回一个bool值表示是否有解。如果有解,则将一个可行解存储在solution中。

 

Design by Contract, Code Contract的优缺点

感觉Design by Contract和OO中学到的方法注释很像,一个接口接受输入,产生输出,并对一些对象的域可能产生副作用,同时,还会有可能的异常产生。

优点:

  • 接口定义规范
  • 副作用可控
  • 输入要求严格

缺点:

  • 需要所有人(实现者,调用者)都遵守,一旦有人违反,会产生很大的副作用。

我们在实现自己的接口时,严格定义的接受参数的范围,并定义了清晰的异常在调用者不遵守要求时抛出;对于可能产生的副作用,接口的设计对其进行隐藏,即所有的副作用都不会对接口的调用者产生影响。

2.单元测试

3.单元测试覆盖率

 


 

第二阶段

1.异常处理

 

我们为接口设计了共3种异常:

 

  • BoundOutOfRange:表示挖空上下界不符合范围标准
  • GenerateNumberOutOfRange:表示生成数独终局和残局的数目不符合标准
  • ModeOutOfRange:表示生成数独残局的难度Mode不符合标准

 

2.单元测试

 

BoundOutOfRange

 

[TestMethod]
        [ExpectedException(typeof(BoundOutOfRange))]
        public void testBoundOutOfRange1()
        {
            int[][,] result = null;
            Core.SudokuFounctionLibrary.generate(1000, 4, 5, true, ref result);
        }

 

对应场景:调用生成数独残局是,调用者传入的lower或upper参数不符合要求。

 

GenerateNumberOutOfRange

 

 [TestMethod]
        [ExpectedException(typeof(GenerateNumberOutOfRange))]
        public void testGenerateNumberOutOfRange2()
        {
            int[][,] result = null;
            Core.SudokuFounctionLibrary.generate(1001, 2, ref result);
        }

 

对应场景:调用生成数独残局是,调用者传入的number参数不符合要求。

 

ModeOutOfRange

 

 [TestMethod]
        [ExpectedException(typeof(ModeOutOfRange))]
        public void testModeOutOfRange1()
        {
            int[][,] result = null;
            Core.SudokuFounctionLibrary.generate(1001, 4, ref result);
        }

 

对应场景:调用生成数独残局是,调用者传入的mode参数不符合要求。

 


 

第三阶段

1.界面设计

这个项目主要有以下三个界面

  • 开始界面

    

 

      开始界面是程序的起始界面

      在开始界面可以选择难度,开始游戏,或打开最佳纪录。

      这个界面比较简单,没有什么复杂的逻辑。

  • 最好记录界面

    

      在这里可以查看不同难度的最佳纪录。

  • 游戏界面

    

   游戏界面是数独游戏最重要的界面。

   这个界面由最上面显示难度和时间的文本框,中间的9*9数独棋盘和下面的两排按钮组成。

   数独棋盘我们是用81个按钮实现的,这81个按钮会在生成数独题目的时候分为两类,一类是不可改变的,也就是数独题目原本有数字的格子,另一类是可以改变的,也就是需要玩家填数字的格子。当一个可改变的按钮被点击时,这个格子就会被标记,这时如果点击底部的按钮,被标记的格子就会被改变。按钮1到9可以给该格子填上相应的数字,按钮C可以清除该格子的内容,提示按钮可以直接显示出被标记格子应该填的数字。提交按钮用来检查当前的数独局面。

   游戏界面的逻辑部分主要包括一下几个函数:

 

  choose函数监听数独棋盘中的81个按钮被按下的事件,如果被按下的是可改变的按钮,就标记被按下的按钮。    

 void choose(object sender, EventArgs e)
        {
            Button button = (Button)sender;
            char c1 = button.Name[1];
            char c2 = button.Name[2];
            if (noChange[c1 - '0', c2 - '0'] == 0)
            {
                (this.FindName(lastChoice) as Button).Background = startColor;
                lastChoice = button.Name;

                (this.FindName(lastChoice) as Button).Background = chooseColor;

            }
        }

 

  fill函数监听按钮1到9,按钮C和提示按钮被按下的事件,对被标记的格子做出相应的改变。

 void fill(object sender, EventArgs e)
        {
            Button button = (Button)sender;
            char c = button.Name[1];
            char c1 = lastChoice[1];
            char c2 = lastChoice[2];
            if (noChange[c1 - '0', c2 - '0'] == 0)
            {
                if (c == 'C')
                {
                    (this.FindName(lastChoice) as Button).Content = (" ");
                }
                else if (c == 'H')
                {
                    (this.FindName(lastChoice) as Button).Content = Start.solvedPuzzle[lastChoice[1] - '0', lastChoice[2] - '0'];
                    (this.FindName(lastChoice) as Button).FontSize = FSS;
                    (this.FindName(lastChoice) as Button).FontStyle = FontStyles.Italic;
                    (this.FindName(lastChoice) as Button).Foreground = helpColor;
                }
                else
                {
                    (this.FindName(lastChoice) as Button).Content = c;
                    (this.FindName(lastChoice) as Button).FontSize = FS;
                    (this.FindName(lastChoice) as Button).FontStyle = FontStyles.Normal;
                    (this.FindName(lastChoice) as Button).Foreground = Black;
                }
            }
        }

  BS_Click函数监听的是提交按钮。这个函数检查当前的数独局面并弹出相应的提示。

private void BS_Click(object sender, RoutedEventArgs e)
        {
            int i, j;
            for (i = 0; i < 9; i++)
            {
                for (j = 0; j < 9; j++)
                {
                    var s = ("B" + i) + j;
                    try
                    {
                        var n = Int32.Parse((this.FindName(s) as Button).Content.ToString());
                        if (n != Start.solvedPuzzle[i, j])
                        {
                            MessageBox.Show(String.Format("Not a right answer; check mistake at ({0}, {1}). Your time spent: {2} s", i + 1, j + 1, seconds));
                            return;
                        }
                    }
                    catch(FormatException)
                    {
                        MessageBox.Show(String.Format("Not a right answer; check mistake at ({0}, {1}). Your time spent: {2} s", i + 1, j + 1, seconds));
                        return;
                    }
                }
            }
            MessageBox.Show(String.Format("Congradulations! Your time spent: {0} s", count));

            switch (Start.mode)
            {
                case 1:
                    if (seconds < App.BestRecordEasy)
                        App.BestRecordEasy = seconds;
                    break;
                case 2:
                    if (seconds < App.BestRecordMedium)
                        App.BestRecordMedium = seconds;
                    break;
                case 3:
                    if (seconds < App.BestRecordHard)
                        App.BestRecordHard = seconds;
                    break;
                default:
                    break;
            }
        }

  

2.两个模块的对接

  程序主要通过以下两个接口的调用实现Core和GUI两个模块的对接。

  • 当开始界面的开始游戏按钮被点下时,调用generate接口生成数独题目。
SudokuFounctionLibrary.generate(1, mode, ref GUIpuzzle);

 

  • 之后调用solve接口保存题目的答案。
 Core.SudokuFounctionLibrary.solve(Start.GUIpuzzle[0], ref Start.solvedPuzzle);

   

 

  


 

结对编程

1.结对编程过程

2.结对编程优缺点

  • 优点:两个人可以互相帮助,在能力方面可以取长补短。

     两个人互相监督,提高工作效率。

     两个人同时对代码进行检查,更容易发现程序的问题。

  • 缺点:结对编程在时间的选择上有一定的局限性,需要考虑两个人的时间分配是否冲突。  

     结对编程过程中可能会出现意见分歧,会对工作效率产生影响。

3.个人优缺点

杨森

  • 优点:非常有耐心。耐心地解答我的各种疑问,以及耐心地寻找程序的bug。

      编程能力较强,代码质量高。

      对工作有认真负责的态度,很早就开始做准备。

  • 缺点:有时候会犯一些粗心的错误。

赵晓宇

  • 优点:善于接收新知识

     善于沟通

     有界面开发经验

  • 缺点:有严重的拖延症,只有deadline快到的时候才不得不专心工作。

     对编程语言掌握不扎实,对工具的使用不熟悉。

 

posted @ 2017-10-15 13:58  zhaobs  阅读(265)  评论(2编辑  收藏  举报