1) 把程序编译通过, 跑起来。
读懂程序,在你觉得比较难懂的地方加上一些注释,这样大家就能比较容易地了解这些程序在干什么。
把正确的 playPrev(GoMove) 的方法给实现了。
注释见Github上的代码,正确的实现我写在了下面:
1 public void playPrev(GoMove gm) 2 { 3 Point P=gm.Point; 4 5 Grid[P.X, P.Y].removeStone(); 6 m_gmLastMove = gameTree.peekPrev(); 7 if (m_gmLastMove != null) 8 { 9 Grid[m_gmLastMove.Point.X, m_gmLastMove.Point.Y].setUpdated(); 10 } 11 if (gm.DeadGroup != null) 12 { 13 System.Collections.IEnumerator myEnumerator =gm.DeadGroup.GetEnumerator(); 14 while (myEnumerator.MoveNext()) 15 { 16 Point p; 17 p = (Point)myEnumerator.Current; 18 Grid[p.X, p.Y].setStone(m_colorToPlay); 19 } 20 } 21 m_colorToPlay = nextTurn(m_colorToPlay); 22 optRepaint(); 23 textBox1.Clear(); 24 textBox1.AppendText(gm.Comment); 25 return; 26 }
2)根据你选择的教材 (三本之一或更多),点评一下这个程序设计方面的不足,例如:
编码风格,
程序架构,有哪些不符合良好的设计,这个程序的设计模式 (MVC等) 是高端大气国际化的么? 等等。
编码风格方面:这个程序把所有的方法都写在了GoBoard类里面,没有写成几个高内聚性的类,因此读起来比较吃力。程序中也没有把控制器和视图分开,所有的控制器都写在了GoBoard这个Winform里面,不是标准的MVC设计模式。
3)程序的注释
注释详见Github,注释时主要有两方面不明白,因此注释就没有写。
1)label和mark分别是什么意思,这一点没有在程序中看明白。
2)从文件中读取棋谱后,一些文件处理操作的函数没有看明白。
4)功能上小问题的改进:
我改的地方是对于向后回退,即悔棋时,如果只在playprev中操作,而不更改其他地方的话,会发现对于棋谱中,这种已经既定后续操作的情况下可以适用,但是如果是用户自己去下棋的情况时,就会发现回退不能得到意想的效果。主要原因出在这里:
1 public void addAMove(GoMove gm) 2 { 3 gm.Seq = m_total ++; 4 m_moves.Insert(m_seq,gm); 5 m_seq++; 6 //m_moves.Add(gm); 7 8 }
被注释掉的是原来的代码。原来的代码的弊端在于它对于用户回退掉的棋子并没有在m_moves这个动态数组中delete掉,导致用户先回退,在添加,再回退,这种场景时就会出现选择棋子上的错误。因此我采用的解决方案是将m_moves.Add(gm);改为m_moves.Insert(m_seq,gm);,这样就可以覆盖掉先前的棋局中的棋子,而达到理想的回退效果。
5)我还想做一个功能上的改进,但是由于时间上的原因,就没有具体实现,下面把我的想法大致说明一下:
save功能的具体实现:
save功能我的设想就是把用户手动下的棋局保存为系统要求的sgf文件。
实现的方法是遍历gametree,因为gametree里面存储了所有的下棋步骤。再利用foreach从第一个遍历到最后一个,然后获取它的颜色和横纵坐标存储为类似B[A,B]的形式。可以先保存到txt文件,最后再将后缀名改为.sgf即可。这样就可以得到一个棋谱了。
6)其他改进及附加题
其他改进的话就是算气的那一部分可以改成压栈是非递归。
附加题2:改成联网的对战游戏。
这一问比较容易实现。
那么每次传递的就是对方的棋子位置和颜色即可。就是将每次换颜色的这部分改掉,改成接受对方传过来的参数,在棋盘上绘制棋子即可。
附加题1:AI接收的是当前棋盘的格局,然后返回的是下一个要下的棋子的点。
那么程序的架构就可以改为每当用户点击完成后,mouseuphandler方法执行完该用户下的棋子的绘制操作后,就将棋局的格局和要下的颜色传给AI,然后AI返回一个下棋的点的位置,在调用playnext函数将AI返回的棋子绘制在棋局上即可。伪代码如下所示:增加的语句为:
GoMove gmNextMove = AI(gameTree,m_colorToPlay);
playNext(gmNextMove);
gameTree.addMove(gmThisMove);
1 private void MouseUpHandler(Object sender,MouseEventArgs e) 2 { 3 Point p; 4 GoMove gmThisMove; 5 6 p = PointToGrid(e.X,e.Y); 7 if (!onBoard(p.X, p.Y) || !closeEnough(p,e.X, e.Y)|| Grid[p.X,p.Y].hasStone()) 8 return; //如果鼠标的位置不在面板上或不在格点上或该点已经有了一颗棋子,那么就返回不绘制点 9 10 //ZZZZZ ZZZZ ZZ Z ZZZZZZ ZZZZ, ZZ ZZZZ ZZ ZZZ ZZZ ZZZZ ZZ ZZZ ZZZZ ZZZZ 11 //将这个点的信息添加到gameTree中 12 gmThisMove = new GoMove(p.X, p.Y, m_colorToPlay, 0); 13 playNext(ref gmThisMove); 14 gameTree.addMove(gmThisMove); 15 GoMove gmNextMove = AI(gameTree,m_colorToPlay); 16 playNext(gmNextMove); 17 gameTree.addMove(gmThisMove); 18 }