zoukankan      html  css  js  c++  java
  • 现代程序设计 homework-06

    写代码爽还是读代码爽?

    当然是写代码爽好吧...

    读代码明显是读+写两倍的工作量好么...

    本次作业要求:

    1) 把程序编译通过, 跑起来。

        读懂程序,在你觉得比较难懂的地方加上一些注释,这样大家就能比较容易地了解这些程序在干什么。

         把正确的 playPrev(GoMove) 的方法给实现了。 如果大家不会下围棋,那就需要大家实地或者上网练习一下围棋的死活,提子是怎么回事。这个应该一个小时就能搞定。

    注释的问题放到后面的问题有统一解决,这里先实现PlayPrev方法.

    通过仔细研读代码(¥#@#¥@#¥!#¥&8),我们可以知道这个GoMove里面的DeadGroup存的是被吃掉的子,那么我们就需要把它们的位置都恢复,我们也可以知道上一步GoMove可以通过一个队列的gameTree.PeekPrev获得,辛苦这里命名还比较易懂,否则真的不知道要找到什么时候(如果不那么蛋疼的把注释全部编程Z相信会更好),我们还可以知道RepaintOneSpotNow是重绘方法,那么再加上一些细节问题就可以实现playPrev方法了

     1 public void PlayPrev(GoMove gm)
     2         {
     3             if (gm == null)
     4             {
     5                 throw new ArgumentNullException("gm");
     6             }
     7             Point p = gm.Point;//获得当前要移除的点
     8             m_colorToPlay = gm.Color;//要移除的点的颜色
     9             ClearLabelsAndMarksOnBoard();//清除highlight信息和落子信息 
    10             Grid[p.X, p.Y].RemoveStone();//remove the current move from the board
    11             bDrawMark = false;//also remove the "lastmove" highlight
    12             RepaintOneSpotNow(p); 
    13             if (gm.DeadGroup != null)//恢复被吃掉的子
    14             {
    15                 for (int i = 0; i <gm.DeadGroup.Count; i++)
    16                 {
    17                     Point pp = (Point)gm.DeadGroup[i];
    18                     RepaintOneSpotNow(pp);
    19                     Grid[pp.X, pp.Y].SetStone(gm.DeadGroupColor);
    20                 }
    21 
    22             }
    23             m_gmLastMove = gameTree.PeekPrev();
    24             if (m_gmLastMove != null)//highlight the new "lastmove"
    25             {
    26                 bDrawMark = true;
    27                 RepaintOneSpotNow(m_gmLastMove.Point);
    28                 SetLabelsOnBoard(m_gmLastMove);
    29                 SetMarksOnBoard(m_gmLastMove);
    30             }
    31             OptRepaint();
    32         }

    机智的我制作了GIF动态图来展现playPrev方法的实现效果

    关于围棋的死活,我用了一个多小时的事件来学习围棋的规则,主要是参照了必应搜索的第一篇百度文档http://wenku.baidu.com/view/a7d18903cc17552707220831.html,讲的很不错,针对本次作业主要有以下几点规则需要特别注意:

    1. 执黑现行
    2. 禁着点不能下子,所谓禁着点,是指周围没有气,又不能吃掉对方子的地方

    2)根据你选择的教材 (三本之一或更多),点评一下这个程序设计方面的不足,例如:

         编码风格,

         程序架构,有哪些不符合良好的设计,这个程序的设计模式 (MVC等) 是高端大气国际化的么? 等等。 

         程序的错误处理,文件处理,UI 等等

    编码风格:

    很明显这个程序的命名规则不够明确,既有大小写混用的骆驼式命名法(的确很形象),也有下划线这种匈牙利命名法,所以看的时候很不协调。按照我的命名习惯,我个人比较倾向于骆驼式命名法,不过VS的代码分析是推荐我们使用帕斯卡命名法的,这个我们等会儿再说

    程序架构:

    说到这个程序的设计模式,的确是不那么高大上,MVC模式没有得到贯彻实施,一个文件中穿插了大量的游戏逻辑+文件操作+前端界面绘制,所以读代码的时候一会儿是UI一会儿是逻辑的看起来很难受,而我们的MVC设计模式强调的是业务逻辑和数据显示分离的方法,并且这样一个小的工程明显不适合用一个源文件来写,完全可以UI部分与游戏逻辑分开,将游戏逻辑的各个类单独开一个.cs,这样无论是读代码还是后期添加功能都会方便很多

    程序的错误处理,文件处理,UI 等等

    程序的文件处理明显是在赶工好么..比如打开一个棋谱文件这一段,

     1 private void OpenFile()
     2         {
     3             OpenFileDialog openDlg = new OpenFileDialog();
     4             openDlg.Filter  = "sgf files (*.sgf)|*.sgf|All Files (*.*)|*.*";
     5             openDlg.FileName = "" ;
     6             openDlg.DefaultExt = ".sgf";
     7             openDlg.CheckFileExists = true;
     8             openDlg.CheckPathExists = true;
     9             
    10             DialogResult res = openDlg.ShowDialog ();
    11             
    12             if(res == DialogResult.OK)
    13             {
    14                 if( !(openDlg.FileName).EndsWith(".sgf") && !(openDlg.FileName).EndsWith(".SGF")) 
    15                     MessageBox.Show("Unexpected file format","Super Go Format",MessageBoxButtons.OK);
    16                 else
    17                 {
    18                     FileStream f = new FileStream(openDlg.FileName, FileMode.Open); 
    19                     StreamReader r = new StreamReader(f);
    20                     string s = r.ReadToEnd();
    21                     gameTree = new GoTree(s);
    22                     gameTree.reset();
    23                     resetBoard();
    24                     r.Close(); 
    25                     f.Close();
    26                 }
    27             }        
    28         }    

    根本没有检测文件路径是否正确好么。。。然后某人果断就将布尔量设为true了么...所以说这里用一个try-catch块来处理会好很多

    还有saveFile这一块,原程序中并没有写,但就给出的接口来看,根本没有办法写貌似,尝试了多次也没有提取到程序中保存整个逻辑的信息段,而比如gm这种变量程序并没有作为全局变量出现,如果我要将它改成全局变量那么会牵扯许多代码的更改,得不偿失.

    至于UI,感觉还是可以的..毕竟我也没有怎么玩过围棋游戏,绘成这个样子还是可以的,但是有一点问题就是UI的很多控件并没有设置Lock和Anchor属性,这导致了窗体大小改变的时候很违和,

    而这个问题想要解决只需要简单设置一下Anchor属性就好,当然为了美观最好也重新改进一下左边棋盘的绘制,不要把尺寸写死,而应该根据窗体的大小来更改相应尺寸(工作量比较大先不进行了)

    3)把Code Analysis 报告的所有问题给解决了。

    不忍吐槽这个任务。。。

    扫描之后需要改进的地方有150项左右。。。

    细细分析一下大概有以下几种类型:

    • CA1709:标识符的大小写应当正确.这种问题属于命名的问题,于是索性一股脑的全部采用了帕斯卡命名法
    • CA1028:枚举存储应为 Int32.这个问题就不用改了吧...感觉好死板
    • CA1814:与多维数组相比,首选使用交错的数组.这里如果浪费很多控件会建议使用交错数组,但源程序中明显数组覆盖率为100%,所以不需要修改
    • CA1823:避免未使用的私有字段.许多没有用过的属性方法什么的果断注释掉

     

    • CA1303:不要将文本作为本地化参数传递.本地化的问题,关于何时取消显示这一警告,MSDN的说法是:
    • 如果将不会本地化代码库,或者如果字符串未公开给使用该代码库的最终用户或开发人员,则可以安全地禁止显示此规则发出的警告。

      通过重命名已命名的参数或属性或者通过将这些项设置为条件项,用户可以消除不应传递本地化字符串的方法的影响。

      果断[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1303:请不要将文本作为本地化参数传递", MessageId = "System.Windows.Forms.Control.set_Text(System.String)")]或者直接从文件中取消显示

    • CA1707:标识符不应包含下划线.这个真的是很奇葩,由于控件的响应事件默认都是采用匈牙利命名规则的,所以改起来还是很麻烦的,将匈牙利命名改成帕斯卡命名即可
    • CA2000:超出范围前释放对象.这个可以用using块来解决,其实由于很多地方确实马上释放了,所以也不妨取消显示这个错误

    还有一些其他警告,采取各种方式消除它..最后效果如下:

     

     
     

    4) 程序的注释

        所有人都觉得注释很重要,写程序不写注释的同学真是RP 比较低。。。

        那么,就请把这个程序中被标成 “zzzz” 的注释都恢复过来。 当然,你可以用中文写注释。

    为什么。。。要把注释都搞成这个样子。。。而且这个逆向工程明显更像是在猜好么。。。不过。。。机智的我还是把他们改好了。。。

    工程全部代码如下:

       1 /**
       2  *  Go Applet
       3  *  1996.11        xinz    written in Java
       4  *  2001.3        xinz    port to C#
       5  *  2001.5.10    xinz    file parsing, back/forward
       6  */
       7 
       8 using System;
       9 using System.Drawing;
      10 using System.Collections;
      11 using System.ComponentModel;
      12 using System.Windows.Forms;
      13 using System.Data;
      14 using System.IO;
      15 using System.Diagnostics;
      16 using System.Resources;
      17 [assembly: CLSCompliant(true)]
      18 namespace DesignLibrary { }
      19 
      20 namespace GoWinApp
      21 {
      22 
      23     public enum StoneColor : int //黑子白子
      24     {
      25         Black = 0, White = 1
      26     }
      27 
      28 
      29     /**
      30      * 呵呵呵
      31      */
      32     public class GoBoard : System.Windows.Forms.Form
      33     {
      34         string [] strLabels; // {"A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T"};
      35 
      36         int nSize;                        //每行每列方格数 19
      37         const int nBoardMargin = 10;    //边线距离 10
      38         int nCoodStart = 4;
      39         const int    nBoardOffset = 20; //棋盘与左边距离 20
      40         int nEdgeLen = nBoardOffset + nBoardMargin; //棋盘右下角的横纵长度
      41         int nTotalGridWidth = 360 + 36;    //方格总大小
      42         int nUnitGridWidth = 22;        //每个小方格的大小
      43         int nSeq = 0;
      44         Rectangle rGrid;            // rectangle for 整个棋盘
      45         StoneColor m_colorToPlay;   // 接下来要走的旗子颜色
      46         GoMove m_gmLastMove;        // 上一步动作
      47         Boolean bDrawMark;            // 是否highlight高亮显示(话说高亮做的好挫..)
      48         Boolean m_fAnyKill;            // 是否有吃子动作
      49         Spot [,] Grid;                // 记录棋盘状态的二维数组
      50         Pen penGrid; //各种色笔用来画图
      51         //被删掉了, penStoneW, penStoneB,penMarkW, penMarkB
      52         Brush brStar, brBoard, brBlack, brWhite, m_brMark; //各种画刷用来画图
      53     
      54         // >>Button <<Button
      55         int nFFMove = 10;   // 限制>>Button的最大操作数
      56   //      int nRewindMove = 10;  // 限制<<Button的最大操作数,但1.这个变量没有使用过 2.<<Button click的时候直接就reset了,所以根本没用
      57 
      58         GoTree    gameTree; //游戏逻辑部分
      59 
      60         ///    各种UI变量声明
      61 //        private System.ComponentModel.Container components;
      62         private System.Windows.Forms.TextBox textBox1;
      63         private System.Windows.Forms.Button Rewind;
      64         private System.Windows.Forms.Button FForward;
      65         private System.Windows.Forms.Button Save;
      66         private System.Windows.Forms.Button Open;
      67         private System.Windows.Forms.Button Back;
      68         private System.Windows.Forms.Button Forward;
      69 
      70         public GoBoard(int nSize)
      71         {
      72             //
      73             // Form第一步,初始化各种组件
      74             //
      75             InitializeComponent();
      76 
      77             //
      78             // 各种初始化操作
      79             //
      80 
      81             this.nSize = nSize;  //设定棋盘大小
      82 
      83             m_colorToPlay = StoneColor.Black; //执黑先行
      84 
      85             Grid = new Spot[nSize,nSize]; //new一个Grid存状态
      86             for (int i=0; i<nSize; i++)
      87                 for (int j=0; j<nSize; j++)
      88                     Grid[i,j] = new Spot();
      89             /*------以下各种初始化画笔画刷------*/
      90             penGrid = new Pen(Color.Brown, (float)0.5);
      91             //penStoneW = new Pen(Color.WhiteSmoke, (float)1);
      92             //penStoneB = new Pen(Color.Black,(float)1);
      93             //penMarkW = new Pen(Color.Blue, (float) 1);
      94             //penMarkB = new Pen(Color.Beige, (float) 1);
      95 
      96             brStar = new SolidBrush(Color.Black);
      97             brBoard = new SolidBrush(Color.Orange);
      98             brBlack = new SolidBrush(Color.Black);
      99             brWhite = new SolidBrush(Color.White);
     100             m_brMark = new SolidBrush(Color.Red);
     101 
     102             rGrid = new Rectangle(nEdgeLen, nEdgeLen,nTotalGridWidth, nTotalGridWidth);
     103             strLabels = new string [] {"a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t"};
     104             gameTree = new GoTree();
     105         }
     106         /*------绘制UI------*/
     107         #region
     108         ///    动态绘制各种组件,没什么好说的
     109         ///    
     110         private void InitializeComponent()
     111         {
     112             this.Open = new System.Windows.Forms.Button();
     113             this.Save = new System.Windows.Forms.Button();
     114             this.Rewind = new System.Windows.Forms.Button();
     115             this.Forward = new System.Windows.Forms.Button();
     116             this.Back = new System.Windows.Forms.Button();
     117             this.FForward = new System.Windows.Forms.Button();
     118             this.textBox1 = new System.Windows.Forms.TextBox();
     119             this.SuspendLayout();
     120             // 
     121             // Open
     122             // 
     123             this.Open.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
     124             this.Open.Location = new System.Drawing.Point(534, 95);
     125             this.Open.Name = "Open";
     126             this.Open.Size = new System.Drawing.Size(67, 25);
     127             this.Open.TabIndex = 2;
     128             this.Open.Text = "open";
     129             this.Open.Click += new System.EventHandler(this.OpenClick);
     130             // 
     131             // Save
     132             // 
     133             this.Save.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
     134             this.Save.Location = new System.Drawing.Point(611, 95);
     135             this.Save.Name = "Save";
     136             this.Save.Size = new System.Drawing.Size(67, 25);
     137             this.Save.TabIndex = 3;
     138             this.Save.Text = "save";
     139             this.Save.Click += new System.EventHandler(this.SaveClick);
     140             // 
     141             // Rewind
     142             // 
     143             this.Rewind.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
     144             this.Rewind.Location = new System.Drawing.Point(611, 60);
     145             this.Rewind.Name = "Rewind";
     146             this.Rewind.Size = new System.Drawing.Size(67, 25);
     147             this.Rewind.TabIndex = 5;
     148             this.Rewind.Text = "<<";
     149             this.Rewind.Click += new System.EventHandler(this.RewindClick);
     150             // 
     151             // Forward
     152             // 
     153             this.Forward.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
     154             this.Forward.Location = new System.Drawing.Point(534, 26);
     155             this.Forward.Name = "Forward";
     156             this.Forward.Size = new System.Drawing.Size(67, 25);
     157             this.Forward.TabIndex = 0;
     158             this.Forward.Text = ">";
     159             this.Forward.Click += new System.EventHandler(this.ForwardClick);
     160             // 
     161             // Back
     162             // 
     163             this.Back.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
     164             this.Back.Location = new System.Drawing.Point(611, 26);
     165             this.Back.Name = "Back";
     166             this.Back.Size = new System.Drawing.Size(67, 25);
     167             this.Back.TabIndex = 1;
     168             this.Back.Text = "<";
     169             this.Back.Click += new System.EventHandler(this.BackClick);
     170             // 
     171             // FForward
     172             // 
     173             this.FForward.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
     174             this.FForward.Location = new System.Drawing.Point(534, 60);
     175             this.FForward.Name = "FForward";
     176             this.FForward.Size = new System.Drawing.Size(67, 25);
     177             this.FForward.TabIndex = 4;
     178             this.FForward.Text = ">>";
     179             this.FForward.Click += new System.EventHandler(this.FForwardClick);
     180             // 
     181             // textBox1
     182             // 
     183             this.textBox1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
     184             this.textBox1.Location = new System.Drawing.Point(536, 138);
     185             this.textBox1.Multiline = true;
     186             this.textBox1.Name = "textBox1";
     187             this.textBox1.Size = new System.Drawing.Size(144, 335);
     188             this.textBox1.TabIndex = 6;
     189             this.textBox1.Text = "please open a .sgf file to view, or just play on the board";
     190             // 
     191             // GoBoard
     192             // 
     193             this.AutoScaleBaseSize = new System.Drawing.Size(6, 14);
     194             this.AutoScroll = true;
     195             this.ClientSize = new System.Drawing.Size(784, 561);
     196             this.Controls.Add(this.textBox1);
     197             this.Controls.Add(this.Rewind);
     198             this.Controls.Add(this.FForward);
     199             this.Controls.Add(this.Save);
     200             this.Controls.Add(this.Open);
     201             this.Controls.Add(this.Back);
     202             this.Controls.Add(this.Forward);
     203             this.Name = "GoBoard";
     204             this.Text = "Go_WinForm";
     205             this.Click += new System.EventHandler(this.GoBoardClick);
     206             this.Paint += new System.Windows.Forms.PaintEventHandler(this.PaintHandler);
     207             this.MouseUp += new System.Windows.Forms.MouseEventHandler(this.MouseUpHandler);
     208             this.ResumeLayout(false);
     209             this.PerformLayout();
     210 
     211         }
     212         #endregion
     213 
     214         private void PaintHandler(Object sender, PaintEventArgs e)
     215         {
     216             UpdateGoBoard(e); //更新棋盘
     217         }
     218         /*------Save功能都没有实现?------*/
     219         protected void SaveClick(object sender, System.EventArgs e)
     220         {
     221             SaveFile();
     222             return;
     223         }
     224         /*------话说这些简单的button响应事件就不用多说了吧?------*/
     225         protected void OpenClick(object sender, System.EventArgs e)
     226         {
     227             OpenFile();
     228             ShowGameInfo();//棋谱文件可能带有自述信息
     229         }
     230         #region
     231         protected void RewindClick(object sender, System.EventArgs e)
     232         {
     233             gameTree.Reset();//<<Button需要完成游戏逻辑重置,棋盘重置,并重新显示游戏信息
     234             ResetBoard();
     235             ShowGameInfo();
     236         }
     237 
     238         protected void FForwardClick(object sender, System.EventArgs e)
     239         {
     240             if (gameTree != null)
     241             {
     242                 int i = 0;
     243                 GoMove gm = null;
     244                 for (gm = gameTree.DoNext(); gm != null; gm = gameTree.DoNext())
     245                 {
     246                     PlayNext(ref gm);
     247                     if (i++ > nFFMove)//将棋盘状态恢复到允许恢复到的最新状态
     248                         break;
     249                 }
     250             }
     251         }
     252 
     253         protected void ForwardClick(object sender, System.EventArgs e)
     254         {
     255             GoMove gm = gameTree.DoNext();
     256             if (null != gm)//前进到有历史记录的下一个操作
     257             {
     258                 PlayNext(ref gm);
     259             }
     260         }
     261         private void ShowGameInfo()
     262         {
     263             //显示游戏信息
     264             textBox1.Clear();
     265             textBox1.AppendText(gameTree.Info);
     266         }
     267 
     268         protected void BackClick(object sender, System.EventArgs e)
     269         {
     270             GoMove gm = gameTree.DoPrev();    //游戏历史记录中的前一步
     271             if (null != gm)
     272             {
     273                 PlayPrev(gm);
     274             }
     275             else
     276             {
     277                 ResetBoard();
     278                 ShowGameInfo();
     279             }
     280         }
     281 
     282         Boolean OnBoard(int x, int y) //边界处理
     283         {
     284             return (x>=0 && x<nSize && y>=0 && y<nSize);
     285         }
     286         /*------又在没用可删的范畴内------*/
     287         protected void GoBoardClick(object sender, System.EventArgs e)
     288         {
     289             return;
     290         }
     291         /*------将坐标转换为棋盘中的图块------*/
     292         private Point PointToGrid(int x, int y)
     293         {
     294             Point p= new Point(0,0);
     295             p.X = (x - rGrid.X + nUnitGridWidth/2) / nUnitGridWidth;
     296             p.Y = (y - rGrid.Y + nUnitGridWidth/2) / nUnitGridWidth;
     297             return p;
     298         }
     299 
     300         //设定了在相交点附近怎样的范围内松开鼠标就视为在此处落子
     301         //
     302         private Boolean CloseEnough(Point p, int x, int y)
     303         {
     304             if (x < rGrid.X+nUnitGridWidth*p.X-nUnitGridWidth/3 ||
     305                 x > rGrid.X+nUnitGridWidth*p.X+nUnitGridWidth/3 ||
     306                 y < rGrid.Y+nUnitGridWidth*p.Y-nUnitGridWidth/3 ||
     307                 y > rGrid.Y+nUnitGridWidth*p.Y+nUnitGridWidth/3)
     308             {
     309                 return false;
     310             }
     311             else 
     312                 return true;
     313         }
     314         /// 鼠标松开事件,用来处理落子
     315         private void MouseUpHandler(Object sender,MouseEventArgs e)
     316         {
     317             Point p;
     318             GoMove    gmThisMove;
     319 
     320             p = PointToGrid(e.X,e.Y);
     321             if (!OnBoard(p.X, p.Y) || !CloseEnough(p,e.X, e.Y)|| Grid[p.X,p.Y].HasStone())
     322                 return; //不满足落子条件
     323 
     324             //满足落子条件时,落子,并将thismove传到gametree中
     325             gmThisMove = new GoMove(p.X, p.Y, m_colorToPlay, 0);
     326             PlayNext(ref gmThisMove);
     327             gameTree.AddMove(gmThisMove);
     328         }
     329 
     330         public void PlayNext(ref GoMove gm) 
     331         {
     332             if (gm == null)
     333             {
     334                 throw new ArgumentNullException("gm");
     335             }
     336             Point p = gm.Point; //获得当前move点
     337             m_colorToPlay = gm.Color;    //接下来要下子的颜色
     338 
     339             //清除highlight信息和落子信息
     340             ClearLabelsAndMarksOnBoard();
     341 
     342             if (m_gmLastMove != null)//如果上一轮已经落子,那么取消该棋子的高亮显示
     343             {
     344                 RepaintOneSpotNow(m_gmLastMove.Point);
     345             }
     346             bDrawMark = true; //高亮显示
     347             Grid[p.X,p.Y].SetStone(gm.Color); //落子
     348             m_gmLastMove = new GoMove(p.X, p.Y, gm.Color, nSeq++); //将本次操作记录在lastmove中
     349             //棋盘显示所有的labels和mark
     350             SetLabelsOnBoard(gm);
     351             SetMarksOnBoard(gm);
     352             
     353             DoDeadGroup(NextTurn(m_colorToPlay));//nextturn返回下一轮的行子颜色,这一操作即进行吃子动作,注意先判定本轮落子能否先吃对方
     354             //如果有吃子的动作,那么就存入deadgroup中 
     355             if (m_fAnyKill)
     356             {
     357                 AppendDeadGroup(ref gm, NextTurn(m_colorToPlay));
     358             }
     359             else //否则要判是否会被吃
     360             {
     361                 DoDeadGroup(m_colorToPlay);
     362                 if (m_fAnyKill)
     363                 {
     364                     AppendDeadGroup(ref gm, m_colorToPlay);
     365                 }
     366             }
     367             m_fAnyKill = false;
     368             
     369             OptRepaint();//重绘棋盘
     370 
     371             //更新下一轮落子颜色
     372             m_colorToPlay = NextTurn(m_colorToPlay);
     373             
     374             //......更新游戏信息,这里其实可以重写showgameinfo()
     375             textBox1.Clear();
     376             textBox1.AppendText(gm.Comment);
     377         }
     378         /*------添加被吃的颜色为c的子------*/
     379         private void AppendDeadGroup(ref GoMove gm, StoneColor c)
     380         {
     381             ArrayList a = new ArrayList();
     382             for (int i=0; i<nSize; i++)
     383                 for (int j=0; j<nSize; j++)
     384                     if (Grid[i,j].IsKilled())
     385                     {
     386                         Point pt = new Point(i,j);
     387                         a.Add(pt);
     388                         Grid[i,j].SetNoKilled();//这里...真的有必要封装成这个样子么..
     389                     }
     390             gm.DeadGroup = a;//存入本次动作gm中,gm.deadgroup就存放了本轮被吃的子,于是playprev可以用到
     391             gm.DeadGroupColor = c;
     392         }
     393         /*------重绘棋盘------*/
     394         public void ResetBoard()
     395         {
     396             int i,j;
     397             for (i=0; i<nSize; i++)
     398                 for (j=0; j<nSize; j++) 
     399                     Grid[i,j].RemoveStone();
     400             m_gmLastMove = null;
     401             Invalidate(null);
     402         }
     403 
     404         /*
     405          * play the move so that the game situation is just BEFORE this move is played.
     406          * what to do:
     407          *     1. remove the current move from the board :removestone
     408          *  1.1 also remove the "lastmov" highlight :bDrawMark=false;
     409          *    2. store the stones got killed by current move
     410          *  3. highlight the new "lastmove" :bDrawMark=true
     411          */
     412         public void PlayPrev(GoMove gm)
     413         {
     414             if (gm == null)
     415             {
     416                 throw new ArgumentNullException("gm");
     417             }
     418             Point p = gm.Point;//获得当前要移除的点
     419             m_colorToPlay = gm.Color;//要移除的点的颜色
     420             ClearLabelsAndMarksOnBoard();//清除highlight信息和落子信息 
     421             Grid[p.X, p.Y].RemoveStone();//remove the current move from the board
     422             bDrawMark = false;//also remove the "lastmove" highlight
     423             RepaintOneSpotNow(p); 
     424             if (gm.DeadGroup != null)//恢复被吃掉的子
     425             {
     426                 for (int i = 0; i <gm.DeadGroup.Count; i++)
     427                 {
     428                     Point pp = (Point)gm.DeadGroup[i];
     429                     RepaintOneSpotNow(pp);
     430                     Grid[pp.X, pp.Y].SetStone(gm.DeadGroupColor);
     431                 }
     432 
     433             }
     434             m_gmLastMove = gameTree.PeekPrev();
     435             if (m_gmLastMove != null)//highlight the new "lastmove"
     436             {
     437                 bDrawMark = true;
     438                 RepaintOneSpotNow(m_gmLastMove.Point);
     439                 SetLabelsOnBoard(m_gmLastMove);
     440                 SetMarksOnBoard(m_gmLastMove);
     441             }
     442             OptRepaint();
     443         }
     444 
     445                 
     446         
     447         Rectangle GetUpdatedArea(int i, int j) //返回需要更新重绘的区域
     448         {
     449             int x = rGrid.X + i * nUnitGridWidth - nUnitGridWidth/2;
     450             int y = rGrid.Y + j * nUnitGridWidth - nUnitGridWidth/2;
     451             return new Rectangle(x,y, nUnitGridWidth, nUnitGridWidth);
     452         }
     453 
     454         /**
     455          * 重绘
     456          */
     457         private void OptRepaint()
     458         {
     459             Rectangle r = new Rectangle(0,0,0,0);
     460             Region    re;
     461 
     462             for (int i=0; i<nSize; i++)
     463                 for (int j=0; j<nSize; j++)
     464                     if (Grid[i,j].IsUpdated()) 
     465                     {
     466                         r = GetUpdatedArea(i,j);
     467                         re = new Region(r);
     468                         Invalidate(re);
     469                         re.Dispose();
     470                     }
     471         }
     472 
     473         /*
     474          * 只重回一个交叉点,用在本轮已经落子需要进行>>或者<<操作的时候
     475          */
     476         public void RepaintOneSpotNow(Point point)
     477         {
     478             Grid[point.X, point.Y].SetUpdated();
     479             bDrawMark = false;
     480             Rectangle r = GetUpdatedArea(point.X, point.Y);
     481             Region re=new Region(r);
     482             Invalidate(re);
     483             re.Dispose();
     484             Grid[point.X, point.Y].ResetUpdated();
     485             bDrawMark = true;
     486         }
     487 
     488         //字面意思是记录操作,但是这个函数没有用到过,很可疑 
     489         public void RecordMove(Point point, StoneColor colorToPlay) 
     490         {
     491             Grid[point.X, point.Y].SetStone(colorToPlay);
     492             // 将上一个操作置为该次操作
     493             m_gmLastMove = new GoMove(point.X, point.Y, colorToPlay, nSeq++);
     494         }
     495         //返回下次落子的颜色
     496         static StoneColor NextTurn(StoneColor c) 
     497         {
     498             if (c == StoneColor.Black)
     499                 return StoneColor.White;
     500             else 
     501                 return StoneColor.Black;
     502         }
     503 
     504         /**
     505          *    bury the dead stones in a group (same color). 
     506          *    if a stone in one group is dead, the whole group is dead.
     507          *    说白了就是dfs消除相连的气为0的子
     508         */
     509         void BuryTheDead(int i, int j, StoneColor c) 
     510         {
     511             if (OnBoard(i,j) && Grid[i,j].HasStone() && 
     512                 Grid[i,j].Color() == c) 
     513             {
     514                 Grid[i,j].Die();
     515                 BuryTheDead(i-1, j, c);
     516                 BuryTheDead(i+1, j, c);
     517                 BuryTheDead(i, j-1, c);
     518                 BuryTheDead(i, j+1, c);
     519             }
     520         }
     521         /*------清除扫描记录,就是清除visit数组的意思------*/
     522         void CleanScanStatus()
     523         {
     524             int i,j;
     525             for (i=0; i<nSize; i++)
     526                 for (j=0; j<nSize; j++) 
     527                     Grid[i,j].ClearScanned();
     528         }
     529 
     530         /**
     531          * 扫描整个棋盘,对当前颜色c,提掉所有气为0的子
     532          */
     533         void DoDeadGroup(StoneColor c) 
     534         {
     535             int i,j;
     536             for (i=0; i<nSize; i++)
     537                 for (j=0; j<nSize; j++) 
     538                     if (Grid[i,j].HasStone() &&
     539                         Grid[i,j].Color() == c) 
     540                     {
     541                         if (CalcLiberty(i,j,c) == 0)
     542                         {
     543                             BuryTheDead(i,j,c);
     544                             m_fAnyKill = true;
     545                         }
     546                         CleanScanStatus();
     547                     }
     548         }
     549         /*------非递归BFS实现计算气------*/
     550         /*
     551         int CalcLibertyBfs(int x, int y, StoneColor c)
     552         {
     553             int lib=0;
     554             int[] dx = { 1, 0, -1, 0 };
     555             int[] dy = { 0, -1, 0, 1 };
     556             Queue q = new Queue();
     557             Point s=new Point(x,y);
     558             Point next = new Point();
     559             q.Enqueue(s);
     560             while (q.Count > 0)
     561             {
     562                 s = (Point)q.Dequeue();
     563                 for (int i = 0; i < 4; i++)
     564                 {
     565                     next.X = s.X + dx[i];
     566                     next.Y = s.Y + dy[i];
     567                     if (!OnBoard(next.X, next.Y))
     568                     {
     569                         continue;
     570                     }
     571                     if (Grid[next.X, next.Y].IsScanned())
     572                     {
     573                         continue;
     574                     }
     575                     if (!Grid[next.X, next.Y].HasStone())
     576                     {
     577                         lib++;
     578                     }
     579                     if (Grid[next.X, next.Y].Color() == c)
     580                     {
     581                         q.Enqueue(next);
     582                     }
     583                     Grid[next.X, next.Y].SetScanned();
     584                 }
     585             }
     586             return lib;
     587 
     588         }
     589         */
     590         /**
     591          * dfs计算每个子(每个group)的气
     592          */
     593         int CalcLiberty(int x, int y, StoneColor c) 
     594         {
     595             int lib = 0; // 初始化
     596             
     597             if (!OnBoard(x,y))
     598                 return 0;
     599             if (Grid[x,y].IsScanned())
     600                 return 0;
     601 
     602             if (Grid[x,y].HasStone()) 
     603             {
     604                 if (Grid[x,y].Color() == c) 
     605                 {
     606                     //dfs深搜四个相邻的格子
     607                     Grid[x,y].SetScanned();
     608                     lib += CalcLiberty(x-1, y, c);
     609                     lib += CalcLiberty(x+1, y, c);
     610                     lib += CalcLiberty(x, y-1, c);
     611                     lib += CalcLiberty(x, y+1, c);
     612                 } 
     613                 else 
     614                     return 0;
     615             } 
     616             else 
     617             {// 周围没有棋子的话气+1
     618                 lib ++;
     619                 Grid[x,y].SetScanned();
     620             }
     621 
     622             return lib;
     623         }
     624 
     625 
     626         /**
     627          * 高亮显示上一次的落子
     628          */
     629         void MarkLastMove(Graphics g) 
     630         {
     631             Brush brMark;
     632             if (m_gmLastMove.Color == StoneColor.White)
     633                 brMark = brBlack;
     634             else 
     635                 brMark = brWhite;
     636             Point p = m_gmLastMove.Point;
     637             g.FillRectangle( brMark,
     638                 rGrid.X + (p.X) * nUnitGridWidth - (nUnitGridWidth-1)/8, 
     639                 rGrid.Y + (p.Y) * nUnitGridWidth - (nUnitGridWidth-1)/8,
     640                 3, 3);
     641         }
     642         /*------消除所有棋子和高亮标记------*/
     643         private void ClearLabelsAndMarksOnBoard()
     644         {
     645             for (int i=0; i<nSize; i++)
     646                 for (int j=0; j<nSize; j++)
     647                 {
     648                     if (Grid[i,j].HasLabel())
     649                         Grid[i,j].ResetLabel();
     650                     if (Grid[i,j].HasMark())
     651                         Grid[i,j].ResetMark();
     652                 }
     653 
     654         }
     655         /*------就是按照当前操作gm,将gm之前的labels全部落下------*/
     656         private void SetLabelsOnBoard(GoMove gm)
     657         {
     658             short    nLabel = 0;
     659             Point p;
     660             if (null != gm.Labels)
     661             {
     662                 System.Collections.IEnumerator myEnumerator = gm.Labels.GetEnumerator();
     663                 while (myEnumerator.MoveNext())
     664                 {
     665                     p = (Point)myEnumerator.Current;
     666                     Grid[p.X,p.Y].SetLabel(++nLabel);
     667                 }
     668             }
     669         }
     670         /*------设置棋盘上的高亮显示------*/
     671         private void SetMarksOnBoard(GoMove gm)
     672         {
     673             Point p;
     674             if (null != gm.Labels)
     675             {
     676                 System.Collections.IEnumerator myEnumerator = gm.Marks.GetEnumerator();
     677                 while ( myEnumerator.MoveNext() )
     678                 {
     679                     p = (Point)myEnumerator.Current;
     680                     Grid[p.X,p.Y].SetMark();
     681                 }
     682             }
     683         }
     684         
     685         static private Point SwapXY(Point p)//额...交换两点坐标
     686         {
     687             Point pNew = new Point(p.Y,p.X);
     688             return pNew;
     689         }
     690         /*------绘制棋盘------*/
     691         private void DrawBoard(Graphics g)
     692         {
     693             //绘制坐标
     694             string[] strV= {"1","2","3","4","5","6","7","8","9","10","11","12","13","14","15","16","17","18","19"};
     695             string [] strH= {"A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T"};
     696 
     697             Point p1 = new Point(nEdgeLen,nEdgeLen);
     698             Point p2 = new Point(nTotalGridWidth+nEdgeLen,nEdgeLen);
     699             g.FillRectangle(brBoard,nBoardOffset,nBoardOffset,nTotalGridWidth+nBoardOffset,nTotalGridWidth+nBoardOffset);
     700             for (int i=0;i<nSize; i++)
     701             {
     702                 g.DrawString(strV[i],this.Font, brBlack, 0, nCoodStart+ nBoardOffset + nUnitGridWidth*i);
     703                 g.DrawString(strH[i],this.Font, brBlack, nBoardOffset + nCoodStart + nUnitGridWidth*i, 0);
     704                 g.DrawLine(penGrid, p1, p2);
     705                 g.DrawLine(penGrid, SwapXY(p1), SwapXY(p2));
     706 
     707                 p1.Y += nUnitGridWidth;
     708                 p2.Y += nUnitGridWidth;
     709             }
     710             //绘制边线
     711             Pen penHi = new Pen(Color.WhiteSmoke, (float)0.5);
     712             Pen penLow = new Pen(Color.Gray, (float)0.5);
     713 
     714             g.DrawLine(penHi, nBoardOffset, nBoardOffset, nTotalGridWidth+2*nBoardOffset, nBoardOffset);
     715             g.DrawLine(penHi, nBoardOffset, nBoardOffset, nBoardOffset, nTotalGridWidth+2*nBoardOffset);
     716             g.DrawLine(penLow, nTotalGridWidth+2*nBoardOffset,nTotalGridWidth+2*nBoardOffset, nBoardOffset+1, nTotalGridWidth+2*nBoardOffset);
     717             g.DrawLine(penLow, nTotalGridWidth+2*nBoardOffset,nTotalGridWidth+2*nBoardOffset, nTotalGridWidth+2*nBoardOffset, nBoardOffset+1);
     718         }
     719 
     720         void UpdateGoBoard(PaintEventArgs e)
     721         {
     722             DrawBoard(e.Graphics);
     723             
     724             //绘制天元
     725             DrawStars(e.Graphics);
     726 
     727             //绘制每一个区域
     728             DrawEverySpot(e.Graphics);
     729         }
     730 
     731         //绘制天元
     732         void DrawStar(Graphics g, int row, int col) 
     733         {
     734             g.FillRectangle(brStar,
     735                 rGrid.X + (row-1) * nUnitGridWidth - 1, 
     736                 rGrid.Y + (col-1) * nUnitGridWidth - 1, 
     737                 3, 
     738                 3);
     739         }
     740 
     741         //绘制9个天元
     742         void  DrawStars(Graphics g)
     743         {
     744             DrawStar(g, 4, 4);
     745             DrawStar(g, 4, 10);
     746             DrawStar(g, 4, 16);
     747             DrawStar(g, 10, 4);
     748             DrawStar(g, 10, 10);
     749             DrawStar(g, 10, 16);
     750             DrawStar(g, 16, 4);
     751             DrawStar(g, 16, 10);
     752             DrawStar(g, 16, 16);
     753         }
     754 
     755         /**
     756          * 绘制落子
     757          */
     758         void DrawStone(Graphics g, int row, int col, StoneColor c) 
     759         {
     760             Brush br;
     761             if (c == StoneColor.White)
     762                 br = brWhite;
     763             else 
     764                 br = brBlack;
     765             
     766             Rectangle r = new Rectangle(rGrid.X+ (row) * nUnitGridWidth - (nUnitGridWidth-1)/2, 
     767                 rGrid.Y + (col) * nUnitGridWidth - (nUnitGridWidth-1)/2,
     768                 nUnitGridWidth-1,
     769                 nUnitGridWidth-1);
     770 
     771             g.FillEllipse(br, r);
     772         }
     773         /*------这个函数貌似没有调用过?------*/
     774         void DrawLabel(Graphics g, int x, int y, short nLabel) 
     775         {
     776             if (nLabel ==0)
     777                 return;
     778             nLabel --;
     779             nLabel %= 18;            //各种转换
     780 
     781             //画Label
     782             Rectangle r = new Rectangle(rGrid.X+ x * nUnitGridWidth - (nUnitGridWidth-1)/2, 
     783                 rGrid.Y + y * nUnitGridWidth - (nUnitGridWidth-1)/2,
     784                 nUnitGridWidth-1,
     785                 nUnitGridWidth-1);
     786 
     787             g.FillEllipse(brBoard, r);
     788             g.DrawString(strLabels[nLabel],    //填字符串
     789                 this.Font, 
     790                 brBlack, 
     791                 rGrid.X+ (x) * nUnitGridWidth - (nUnitGridWidth-1)/4, 
     792                 rGrid.Y + (y) * nUnitGridWidth - (nUnitGridWidth-1)/2);
     793         }
     794         /*------绘制highlight点------*/
     795         void DrawMark(Graphics g, int x, int y)
     796         {
     797             g.FillRectangle( m_brMark,
     798                 rGrid.X + x* nUnitGridWidth - (nUnitGridWidth-1)/8, 
     799                 rGrid.Y + y * nUnitGridWidth - (nUnitGridWidth-1)/8,
     800                 5, 5);
     801         }
     802         /*------绘制每一个落子点------*/
     803         void DrawEverySpot(Graphics g) 
     804         {
     805             for (int i=0; i<nSize; i++)
     806                 for (int j=0; j<nSize; j++)
     807                 {
     808                     if (Grid[i,j].HasStone())
     809                         DrawStone(g, i, j, Grid[i,j].Color());
     810                     if (Grid[i,j].HasLabel())
     811                         DrawLabel(g, i, j, Grid[i,j].GetLabel());
     812                     if (Grid[i,j].HasMark())
     813                         DrawMark(g, i, j);
     814                 }
     815             //标记操作
     816             if (bDrawMark && m_gmLastMove != null)
     817                 MarkLastMove(g);
     818         }
     819         #endregion
     820         [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1300:SpecifyMessageBoxOptions"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2202:不要多次释放对象"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1303:请不要将文本作为本地化参数传递", MessageId = "System.Windows.Forms.MessageBox.Show(System.String,System.String,System.Windows.Forms.MessageBoxButtons)"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1307:SpecifyStringComparison", MessageId = "System.String.EndsWith(System.String)"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1303:请不要将文本作为本地化参数传递", MessageId = "System.Windows.Forms.FileDialog.set_Filter(System.String)")]
     821         private void SaveFile()
     822         {
     823             using (SaveFileDialog saveDlg = new SaveFileDialog())
     824             {
     825                 saveDlg.Filter = "sgf files (*.sgf)|*.sgf|All Files (*.*)|*.*";
     826                 saveDlg.DefaultExt = ".sgf";
     827                 DialogResult res = saveDlg.ShowDialog();
     828                 if (res == DialogResult.OK)
     829                 {
     830                     if (!(saveDlg.FileName).EndsWith(".sgf") && !(saveDlg.FileName).EndsWith(".SGF"))
     831                         MessageBox.Show("Unexpected file format", "Super Go Format", MessageBoxButtons.OK);
     832                     else
     833                     {
     834                         using (StreamWriter w = new StreamWriter(saveDlg.FileName, false))
     835                         {
     836                             string s = gameTree.Info;//这里应该递归掉gm的信息,但是gm目前不是全局变量.
     837                             w.WriteLine(s);
     838                         }
     839                     }
     840                 }
     841             }
     842         }
     843         //打开棋谱文件
     844         private void OpenFile()
     845         {
     846             OpenFileDialog openDlg = new OpenFileDialog();
     847             openDlg.Filter  = "sgf files (*.sgf)|*.sgf|All Files (*.*)|*.*";
     848             openDlg.FileName = "" ;
     849             openDlg.DefaultExt = ".sgf";
     850             openDlg.CheckFileExists = true;
     851             openDlg.CheckPathExists = true;
     852             
     853             DialogResult res = openDlg.ShowDialog ();
     854             
     855             if(res == DialogResult.OK)
     856             {
     857                 if (!(openDlg.FileName).EndsWith(".sgf") && !(openDlg.FileName).EndsWith(".SGF"))
     858                     MessageBox.Show("Unexpected file format", "Super Go Format", MessageBoxButtons.OK);
     859                 else
     860                 {
     861                     FileStream f = new FileStream(openDlg.FileName, FileMode.Open);
     862                     StreamReader r = new StreamReader(f);
     863                     string s = r.ReadToEnd();
     864                     gameTree = new GoTree(s);
     865                     gameTree.Reset();
     866                     ResetBoard();
     867                 //    r.Close();
     868                     f.Close();
     869                 }
     870             }        
     871         }    
     872     }
     873 
     874     public class GoTest
     875     {
     876         /// 
     877         /// main入口,单线程标记
     878         /// 
     879         [STAThread]
     880         public static void Main(string[] args) 
     881         {
     882             Application.Run(new GoBoard(19));
     883         }
     884     }
     885 
     886     
     887     //Spot类代表每一个点
     888     public class Spot 
     889     {
     890         private Boolean bEmpty; //是否为空
     891         private Boolean bKilled; //是否被吃
     892         private Stone s; //落子属性
     893         private short    m_nLabel; 
     894         private Boolean m_bMark; //是否高亮
     895         private Boolean bScanned; //是否被扫描过
     896         private Boolean bUpdated; //是否已经被更新
     897         /**
     898          * 构造函数
     899          */
     900         public Spot() 
     901         {
     902             bEmpty = true;
     903             bScanned = false;
     904             bUpdated = false;
     905             bKilled = false;
     906         }
     907         /*------简单各种方法------*/
     908         public Boolean HasStone() { return !bEmpty;    }
     909         public Boolean IsEmpty() {    return bEmpty;    }
     910         public Stone ThisStone() {    return s;}
     911         public StoneColor Color() {    return s.color;}
     912 
     913         public Boolean HasLabel() {return m_nLabel>0;}
     914         public Boolean HasMark() {return m_bMark;}
     915         public void SetLabel(short label) {m_nLabel = label; bUpdated = true; }
     916         public void SetMark() {m_bMark = true; bUpdated = true;}
     917         public void ResetLabel() {m_nLabel = 0; bUpdated = true;}
     918         public void ResetMark() {m_bMark = false; bUpdated = true;}
     919         public short    GetLabel() {return m_nLabel;}
     920 
     921         public Boolean IsScanned() { return bScanned;}
     922         public void SetScanned() {    bScanned = true;}
     923         public void ClearScanned() { bScanned = false; }
     924 
     925         public void SetStone(StoneColor color) 
     926         {
     927             if (bEmpty) 
     928             {
     929                 bEmpty = false;
     930                 s.color = color;
     931                 bUpdated = true;
     932             } // 落子
     933         }
     934 
     935         /*
     936          * 提子
     937         */
     938         public void RemoveStone()
     939         {    //提子
     940             bEmpty = true;
     941             bUpdated = true;
     942         }
     943                 
     944         //被吃
     945         public void Die() 
     946         {
     947             bKilled = true;
     948             bEmpty = true;
     949             bUpdated = true;
     950         } 
     951 
     952         public Boolean IsKilled() { return bKilled;}
     953         public void SetNoKilled() { bKilled = false;}
     954 
     955         public void ResetUpdated() { bUpdated = false; bKilled = false;}
     956 
     957         //是否被更新
     958         public Boolean IsUpdated() 
     959         { 
     960             if (bUpdated)
     961             {    //如果已经被更新了,那么置更新状态为反
     962                 bUpdated = false;
     963                 return true;
     964             } 
     965             else 
     966                 return false;
     967         }
     968 
     969         // updated的set函数
     970         public void SetUpdated() { bUpdated = true; }
     971     }
     972 
     973     /**
     974      * 操作类
     975      */
     976     public class GoMove 
     977     {
     978         StoneColor m_c;    //落子颜色
     979         Point m_pos;        //落子位置
     980         int m_n;            //操作数
     981         String m_comment;    // 每步操作的信息
     982         MoveResult m_mr;    //每步操作的结果
     983 
     984         ArrayList        m_alLabel; //所有的label 
     985         ArrayList        m_alMark; //所有的mark
     986 
     987         //所有的被吃点
     988         //被吃子的颜色 
     989         ArrayList        m_alDead;
     990         StoneColor    m_cDead;
     991         /**
     992          * 构造函数
     993          */
     994         public GoMove(int posX, int posY, StoneColor sc, int seq) 
     995         {
     996             m_pos = new Point(posX,posY);
     997             m_c = sc;
     998             m_n = seq;
     999             m_mr = new MoveResult();
    1000             m_alLabel = new ArrayList();
    1001             m_alMark = new ArrayList();
    1002         }
    1003         /*------这种构造函数用于棋谱文件------*/
    1004         public GoMove(String str, StoneColor color) 
    1005         {
    1006             if (str == null)
    1007             {
    1008                 throw new ArgumentNullException("str");
    1009             }
    1010             char cx = str[0];
    1011             char cy = str[1];
    1012             m_pos = new Point(0,0);
    1013             //转换为坐标
    1014             m_pos.X = (int) ( (int)cx - (int)(char)'a');
    1015             m_pos.Y = (int) ( (int)cy - (int)(char)'a');
    1016             this.m_c = color;
    1017             m_alLabel = new ArrayList();
    1018             m_alMark = new ArrayList();
    1019         }
    1020 
    1021         /*------还是将游戏信息中的str转换为点坐标,所以说上面的构造函数代码覆盖率太差------*/
    1022         static private Point    StrToPoint(String str)
    1023         {
    1024             Point p = new Point(0,0);
    1025             char cx = str[0];
    1026             char cy = str[1];
    1027             //转换为坐标
    1028             p.X = (int) ( (int)cx - (int)(char)'a');
    1029             p.Y = (int) ( (int)cy - (int)(char)'a');
    1030             return p;
    1031         }
    1032         /*------各种get/set------*/
    1033         //落子颜色
    1034         public StoneColor Color
    1035         { 
    1036             get { return m_c; } 
    1037         }
    1038         //游戏信息
    1039         public String Comment 
    1040         {
    1041             get
    1042             {
    1043                 if (m_comment == null)
    1044                     return string.Empty;
    1045                 else
    1046                     return m_comment;
    1047             }
    1048             set
    1049             {
    1050                 m_comment = value; 
    1051             }
    1052         }
    1053 
    1054         public int Seq
    1055         {
    1056             get { return m_n; }
    1057             set {    m_n = value;}
    1058         }
    1059 
    1060         public Point Point
    1061         {
    1062            get  { return m_pos; }
    1063         }
    1064 
    1065         public MoveResult Result
    1066         {
    1067             get { return m_mr; }
    1068             set { m_mr = value; }
    1069         }
    1070 
    1071         public ArrayList DeadGroup
    1072         {
    1073             get { return m_alDead;}
    1074             set {m_alDead = value;}
    1075         }
    1076 
    1077         public StoneColor DeadGroupColor
    1078         {
    1079             get { return m_cDead; }
    1080             set { m_cDead = value; }
    1081         }
    1082         
    1083         public void AddLabel(String str) {m_alLabel.Add(StrToPoint(str));}
    1084         
    1085         public void AddMark(String str) {    m_alMark.Add(StrToPoint(str));}
    1086 
    1087         public ArrayList Labels
    1088         {
    1089             get { return m_alLabel; }
    1090         }
    1091 
    1092         public ArrayList Marks
    1093         {
    1094             get { return m_alMark; }
    1095         }
    1096     }
    1097     
    1098 
    1099     /**
    1100      * 操作结果类
    1101      * 
    1102      */
    1103     public class MoveResult 
    1104     {
    1105         public StoneColor color; 
    1106         // 4个方向是否被吃子 
    1107         public Boolean bUpKilled;
    1108         public Boolean bDownKilled;
    1109         public Boolean bLeftKilled;
    1110         public Boolean bRightKilled;
    1111         public Boolean bSuicide;    //是否还有气
    1112         public  MoveResult() 
    1113         {
    1114             bUpKilled = false;
    1115             bDownKilled = false;
    1116             bLeftKilled = false;
    1117             bRightKilled = false;
    1118             bSuicide = false;
    1119         }
    1120     }
    1121 
    1122     /**
    1123      * 
    1124      * ...这是在搞什么..突然又出现一个只有一个成员的struct..
    1125      */
    1126     public struct Stone 
    1127     {
    1128         public StoneColor color; 
    1129     }
    1130 
    1131     /**
    1132      * 操作变量类
    1133      * 
    1134      */
    1135     public class GoVariation 
    1136     {
    1137     //    int m_id;            //用不到删掉了
    1138     //    string m_name;    //用不到删掉了
    1139         //请直接无视我     //天知道你在说什么    
    1140         ArrayList m_moves; 
    1141         int m_seq;            //这个东西应该是在读谱的时候才有用的 
    1142         int m_total;
    1143 
    1144         //构造函数
    1145         public GoVariation(int id)
    1146         {
    1147         //    m_id = id;
    1148             m_moves = new ArrayList(10);
    1149             m_seq = 0;
    1150             m_total = 0;
    1151         }
    1152 
    1153         public void AddAMove(GoMove gm) 
    1154         {
    1155             if (gm == null)
    1156             {
    1157                 throw new ArgumentNullException("gm");
    1158             }
    1159             gm.Seq = m_total ++;
    1160             m_seq++;
    1161             m_moves.Add(gm);
    1162         }
    1163 
    1164         public void UpdateResult(GoMove gm) 
    1165         {
    1166         }
    1167 
    1168         public GoMove DoNext()
    1169         {
    1170             if (m_seq < m_total) 
    1171             {
    1172                 return (GoMove)m_moves[m_seq++];
    1173             } 
    1174             else 
    1175                 return null;
    1176         }
    1177 
    1178         public GoMove DoPrev()
    1179         {
    1180             if (m_seq > 0)
    1181                 return (GoMove)(m_moves[--m_seq]);
    1182             else 
    1183                 return null;
    1184         }
    1185 
    1186         /*
    1187          *  嗯下面这个确实很有用,它返回操作队列的当前操作的前一个
    1188          */
    1189         public GoMove PeekPrev()
    1190         {
    1191             if (m_seq > 0)
    1192                 return (GoMove)(m_moves[m_seq-1]);
    1193             else 
    1194                 return null;
    1195         }
    1196 
    1197         public void Reset() {m_seq = 0;}
    1198     }
    1199 
    1200 
    1201     /**
    1202     * 我想说下面的其实用不到 
    1203     * 下面的用不到的 
    1204     */
    1205     //struct VarStartPoint
    1206     //{
    1207     //    int m_id; 
    1208     //    int m_seq;
    1209     //}
    1210 
    1211     struct GameInfo //这个GameInfo其实有好多用不到的地方
    1212     {
    1213         public string gameName;
    1214         public string playerBlack;
    1215         public string playerWhite;
    1216         public string rankBlack;
    1217         public string rankWhite;
    1218         public string result;
    1219         public string date;
    1220         public string km;
    1221         public string size;
    1222         public string comment;
    1223         public string handicap;
    1224         public string gameEvent;
    1225         public string location;
    1226         public string time;             // 时间
    1227         public string unknown_ff;   //谁能告诉我这是什么...
    1228         public string unknown_gm;
    1229         public string unknown_vw; 
    1230     }
    1231 
    1232     /*------这一坨应该是解析棋谱类------*/
    1233 
    1234     public class KeyValuePair 
    1235     {
    1236         public string k; public ArrayList alV;
    1237 
    1238         static private string    RemoveBackSlash(string strIn)
    1239         {
    1240             string strOut; 
    1241             int        iSlash;
    1242 
    1243             strOut = string.Copy(strIn);
    1244             if (strOut.Length < 2)
    1245                 return strOut;
    1246             for (iSlash = strOut.Length-2; iSlash>=0; iSlash--)
    1247             {
    1248                 if (strOut[iSlash] == '\')        // && 转义字符首先,搜字符
    1249                 {
    1250                     strOut = strOut.Remove(iSlash,1);
    1251                     if (iSlash>0)
    1252                         iSlash --;    // 就是专门解析棋谱文件的字符串操作...我们没必要花时间在这个上面
    1253                 }
    1254             }
    1255             return strOut;
    1256         }
    1257         public KeyValuePair(string k, string v)
    1258         {
    1259             if (k == null)
    1260             {
    1261                 throw new ArgumentNullException("k");
    1262             }
    1263             this.k = string.Copy(k);
    1264             string strOneVal;
    1265             int        iBegin, iEnd;
    1266 
    1267             // 将棋谱信息转换为X[]的形式
    1268             alV = new ArrayList(1);
    1269 
    1270             // Comment
    1271             if (k.Equals("C"))
    1272             {
    1273                 strOneVal = RemoveBackSlash(string.Copy(v));
    1274                 // Comment
    1275                 alV.Add(strOneVal);
    1276                 return;
    1277             }
    1278             if (v == null)
    1279             {
    1280                 throw new ArgumentNullException("v");
    1281             }
    1282             iBegin = v.IndexOf("[");
    1283             if (iBegin == -1)    // 里面是坐标
    1284             {
    1285                 alV.Add(v);
    1286                 return; 
    1287             }
    1288             
    1289             iBegin = 0;
    1290             while (iBegin < v.Length && iBegin>=0)
    1291             {
    1292                 iEnd = v.IndexOf("]", iBegin);
    1293                 if (iEnd > 0)
    1294                     strOneVal = v.Substring(iBegin, iEnd-iBegin);
    1295                 else
    1296                     strOneVal = v.Substring(iBegin);    // 里面是坐标
    1297                 alV.Add(strOneVal);
    1298                 iBegin = v.IndexOf("[", iBegin+1);
    1299                 if (iBegin > 0)
    1300                     iBegin++;    // 循环继续
    1301             }
    1302         }
    1303     }
    1304 
    1305     //GoTree其实是操作队列
    1306 
    1307     public class GoTree 
    1308     {
    1309         GameInfo _gi;        //_gi:GameInfo游戏信息
    1310         ArrayList _vars;        //forward的时候用
    1311         int _currVarId;        //当前操作ID
    1312 //        int _currVarNum;
    1313         GoVariation _currVar;        //当前操作
    1314         string    _stGameComment;
    1315        
    1316         // 由棋谱产生的构造函数
    1317         public GoTree(string str)
    1318         {
    1319             _vars = new ArrayList(10);
    1320 //            _currVarNum = 0;
    1321             _currVarId = 0; 
    1322             _currVar = new GoVariation(_currVarId);
    1323             _vars.Add(_currVar);
    1324             ParseFile(str); // 棋谱信息转换
    1325         }
    1326 
    1327         //    平时用的构造函数
    1328         public GoTree()
    1329         {
    1330             _vars = new ArrayList(10);
    1331     //        _currVarNum = 0;
    1332             _currVarId = 0; 
    1333             _currVar = new GoVariation(_currVarId);
    1334             _vars.Add(_currVar);
    1335         }
    1336 
    1337         public    string Info
    1338         {
    1339             get
    1340             {
    1341                 return _gi.comment == null? string.Empty : _gi.comment;
    1342             }
    1343         }
    1344 
    1345         public void AddMove(GoMove gm) 
    1346         {
    1347             _currVar.AddAMove(gm);
    1348         }
    1349 
    1350         /**
    1351          * 顾名思义,棋谱文件转换用的
    1352          */
    1353         Boolean ParseFile(String goStr) 
    1354         {
    1355             int iBeg, iEnd=0; 
    1356             while (iEnd < goStr.Length) 
    1357             {
    1358                 if (iEnd > 0)
    1359                     iBeg = iEnd;
    1360                 else 
    1361                     iBeg = goStr.IndexOf(";", iEnd);//从iEnd后第一个;的位置
    1362                 iEnd = goStr.IndexOf(";", iBeg+1);//indexof如果未找到会返回-1
    1363                 if (iEnd < 0) // 没找到
    1364                     iEnd = goStr.LastIndexOf(")", goStr.Length);        //// 找最后一个)
    1365                 if (iBeg >= 0 && iEnd > iBeg) 
    1366                 {
    1367                     string section = goStr.Substring(iBeg+1, iEnd-iBeg-1);
    1368                     ParseASection(section);//划分出棋谱主体部分开始搞
    1369                 } 
    1370                 else 
    1371                     break;
    1372             }
    1373             return true;
    1374         }
    1375 
    1376         /// 相当于词法分析提取一个单词
    1377         static public int FindEndofValueStr(String sec)
    1378         {
    1379             if (sec == null)
    1380             {
    1381                 throw new ArgumentNullException("sec");
    1382             }
    1383             int i = 0;
    1384             // 截到]
    1385             while (i >= 0)
    1386             {
    1387                 i = sec.IndexOf(']', i+1);
    1388                 if (i > 0 && sec[i - 1] != '\')
    1389                     return i;    // 返回单词位置
    1390             }
    1391 
    1392             // 没提到单词就返回总长度
    1393             return sec.Length - 1;        // 没提到单词就返回总长度
    1394         }
    1395         
    1396         static public int FindEndofValueStrOld(String sec)//老版,用不到
    1397         {
    1398             if (sec == null)
    1399             {
    1400                 throw new ArgumentNullException("sec");
    1401             }
    1402             int i = 0;
    1403             // 就是专门解析棋谱文件的字符串操作...我们没必要花时间在这个上面
    1404             bool fOutside = false;
    1405             
    1406             for (i=0; i<sec.Length;i++)
    1407             {
    1408                 if (sec[i] == ']')
    1409                 {
    1410                     if (i > 1 && sec[i - 1] != '\') // 就是专门解析棋谱文件的字符串操作...我们没必要花时间在这个上面
    1411                         fOutside = true;
    1412                 }
    1413                 else if (char.IsLetter(sec[i]) && fOutside && i>0)
    1414                     return i-1;
    1415                 else if (fOutside && sec[i] == '[')
    1416                     fOutside = false;
    1417             }
    1418             return sec.Length - 1;        // 就是专门解析棋谱文件的字符串操作...我们没必要花时间在这个上面
    1419         }
    1420 
    1421         static private string PurgeCRLFSuffix(string inStr)
    1422         {
    1423             int iLast = inStr.Length - 1; // 就像词法分析跳过没有意义的字符一样
    1424 
    1425             if (iLast <= 0)
    1426                 return inStr; 
    1427 
    1428             while ((inStr[iLast] == '
    ' || inStr[iLast] == '
    ' || inStr[iLast] == ' '))
    1429             {
    1430                 iLast--; 
    1431             }
    1432             if ((iLast+1) != inStr.Length)
    1433                 return inStr.Substring(0, iLast + 1);  //就像词法分析跳过没有意义的字符一样
    1434             else
    1435                 return inStr; 
    1436         }
    1437 
    1438 
    1439         // 棋谱主体部分
    1440         Boolean ParseASection(String sec) 
    1441         {
    1442             int iKey = 0;
    1443             int iValue = 0;
    1444             int iLastValue = 0;
    1445             KeyValuePair kv;
    1446             ArrayList Section = new ArrayList(10);
    1447             
    1448             try 
    1449             {
    1450                 iKey = sec.IndexOf("[");
    1451                 if (iKey < 0)
    1452                 {
    1453                     return false;
    1454                 }
    1455                 sec = PurgeCRLFSuffix(sec);
    1456 
    1457                 iValue = FindEndofValueStr(sec); // 提取一个[]操作
    1458                 iLastValue = sec.LastIndexOf("]");
    1459                 if (iValue <= 0 || iLastValue <= 1)
    1460                 {
    1461                     return false;
    1462                 }
    1463                 sec = sec.Substring(0,iLastValue+1);
    1464                 while (iKey > 0 && iValue > iKey)// 正确提取了一个[]
    1465                 {
    1466                     string key = sec.Substring(0,iKey);
    1467                     int iNonLetter = 0;
    1468                     while (!char.IsLetter(key[iNonLetter]) && iNonLetter < key.Length)
    1469                         iNonLetter ++;
    1470                     key = key.Substring(iNonLetter);
    1471                     // X[]
    1472                     string strValue = sec.Substring(iKey+1, iValue-iKey-1);
    1473                     // 键值对
    1474                     kv = new KeyValuePair(key, strValue);
    1475                     Section.Add(kv);
    1476                     if (iValue >= sec.Length)
    1477                         break;
    1478                     sec = sec.Substring(iValue+1);
    1479                     iKey = sec.IndexOf("[");
    1480                     if (iKey > 0)
    1481                     {
    1482                         iValue = FindEndofValueStr(sec); // 循环继续
    1483                     }
    1484                 }
    1485             }
    1486             catch
    1487             {
    1488                 return false;
    1489             }
    1490 
    1491             ProcessASection(Section);
    1492             return true;
    1493         }
    1494 
    1495 
    1496         // 提取出操作后就要进行识别了
    1497         Boolean ProcessASection(ArrayList arrKV) 
    1498         {
    1499             Boolean fMultipleMoves = false;   //单步操作
    1500             GoMove gm = null; 
    1501             
    1502             string key, strValue;
    1503 
    1504             for (int i = 0;i<arrKV.Count;i++)
    1505             {
    1506                 key = ((KeyValuePair)(arrKV[i])).k;
    1507                 for (int j=0; j<((KeyValuePair)(arrKV[i])).alV.Count; j++)
    1508                 {
    1509                     strValue = (string)(((KeyValuePair)(arrKV[i])).alV[j]);
    1510 
    1511                     if (key.Equals("B"))   //
    1512                     {
    1513                         Debug.Assert(gm == null);
    1514                         gm = new GoMove(strValue, StoneColor.Black);
    1515                     }
    1516                     else if (key.Equals("W"))  //
    1517                     {
    1518                         Debug.Assert(gm == null);
    1519                         gm = new GoMove(strValue, StoneColor.White);
    1520                     }
    1521                     else if (key.Equals("C")) // Comment,针对一些步数发表自己的看法。。
    1522                     {
    1523                         // 初始comment
    1524                         if (gm != null)
    1525                             gm.Comment = strValue;
    1526                         else    // appent comment
    1527                             _gi.comment += strValue;
    1528                     }
    1529                     else if (key.Equals("L"))  // 放子,就是一开始就有一些地方放了子
    1530                     {
    1531                         if (gm != null)
    1532                             gm.AddLabel(strValue);
    1533                         else    // 中途放子是个什么逻辑
    1534                             _stGameComment += strValue;
    1535                     }
    1536 
    1537                     else if (key.Equals("M")) // 貌似是在开始之前就显示一些重要的操作?
    1538                     {
    1539                         if (gm != null)
    1540                             gm.AddMark(strValue);
    1541                         else    // 游戏中途搞这个?
    1542                             _gi.comment += strValue;
    1543                     }
    1544                     else if (key.Equals("AW"))        // 突然觉得好蛋疼,给这么一串英文标识符让我们来猜意思?
    1545                     {
    1546                         fMultipleMoves = true;
    1547                         gm = new GoMove(strValue, StoneColor.White);
    1548                     }
    1549                     else if (key.Equals("AB"))        // 多步黑
    1550                     {
    1551                         fMultipleMoves = true;
    1552                         gm = new GoMove(strValue, StoneColor.Black);
    1553                     }
    1554                     else if (key.Equals("HA"))//这些键值对根本就没有被用过..
    1555                         _gi.handicap = (strValue);
    1556                     else if (key.Equals("BR"))
    1557                         _gi.rankBlack = (strValue);
    1558                     else if (key.Equals("PB"))
    1559                         _gi.playerBlack = (strValue);
    1560                     else if (key.Equals("PW"))
    1561                         _gi.playerWhite = (strValue);
    1562                     else if (key.Equals("WR"))
    1563                         _gi.rankWhite = (strValue);
    1564                     else if (key.Equals("DT"))
    1565                         _gi.date = (strValue);
    1566                     else if (key.Equals("KM"))
    1567                         _gi.km = (strValue);
    1568                     else if (key.Equals("RE"))
    1569                         _gi.result = (strValue);
    1570                     else if (key.Equals("SZ"))
    1571                         _gi.size = (strValue);
    1572                     else if (key.Equals("EV"))
    1573                         _gi.gameEvent = (strValue);
    1574                     else if (key.Equals("PC"))
    1575                         _gi.location = (strValue);
    1576                     else if (key.Equals("TM"))
    1577                         _gi.time = (strValue);
    1578                     else if (key.Equals("GN"))
    1579                         _gi.gameName = strValue;
    1580 
    1581                     else if (key.Equals("FF"))
    1582                         _gi.unknown_ff = (strValue);
    1583                     else if (key.Equals("GM"))
    1584                         _gi.unknown_gm = (strValue);
    1585                     else if (key.Equals("VW"))
    1586                         _gi.unknown_vw = (strValue);
    1587                     else if (key.Equals("US"))
    1588                         _gi.unknown_vw = (strValue);
    1589 
    1590                     else if (key.Equals("BS"))
    1591                         _gi.unknown_vw = (strValue);
    1592                     else if (key.Equals("WS"))
    1593                         _gi.unknown_vw = (strValue);
    1594                     else if (key.Equals("ID"))
    1595                         _gi.unknown_vw = (strValue);
    1596                     else if (key.Equals("KI"))
    1597                         _gi.unknown_vw = (strValue);
    1598                     else if (key.Equals("SO"))
    1599                         _gi.unknown_vw = (strValue);
    1600                     else if (key.Equals("TR"))
    1601                         _gi.unknown_vw = (strValue);
    1602                     else if (key.Equals("LB"))
    1603                         _gi.unknown_vw = (strValue);
    1604                     else if (key.Equals("RO"))
    1605                         _gi.unknown_vw = (strValue);
    1606 
    1607 
    1608                     // 未定义的键值对
    1609                     else
    1610                         System.Diagnostics.Debug.Assert(false, "unhandle key: " + key + " "+ strValue);
    1611 
    1612                     // 如果是多步操作
    1613                     if (fMultipleMoves)
    1614                     {
    1615                         _currVar.AddAMove(gm);
    1616                     }
    1617                 }
    1618             }
    1619 
    1620             // 下一步
    1621             if (!fMultipleMoves && gm != null)
    1622             {
    1623                 _currVar.AddAMove(gm);
    1624             }
    1625             return true;
    1626         } 
    1627 
    1628         public GoMove DoPrev() 
    1629         {
    1630             return _currVar.DoPrev();
    1631         }
    1632 
    1633         public GoMove PeekPrev() 
    1634         {
    1635             return _currVar.PeekPrev();
    1636         }
    1637 
    1638         public GoMove DoNext() 
    1639         {
    1640             return _currVar.DoNext();
    1641         }
    1642 
    1643         public void UpdateResult(GoMove gm) 
    1644         {
    1645             _currVar.UpdateResult(gm);
    1646         }
    1647         
    1648         public void Reset()
    1649         {
    1650 //            _currVarNum = 0;
    1651             _currVarId = 0; 
    1652             _currVar.Reset();
    1653         }
    1654         static public void RewindToStart()
    1655         {
    1656 
    1657         }
    1658     } 
    1659 }
    View Code

    5) 选择题: (提示: 这个题目另外算分,满分10分,需要挣分的同学就可以考虑这个选择题)

    对于功能上的小问题, 那么你怎么改进呢? 请选出 1-2个你想做的改进,然后运用你的各种编程技术和能力把这些改进给实现了(必须明确指出改进/增加了哪一个功能)。

          把所有的改进都实现之后,把代码签入 GitHub, 经历了这一番改动,你的程序和别的同学的程序就很不一样了。

     

    这里我做的改进主要是把SaveFile功能实现,但是...由于我提取不到整个游戏的逻辑string信息..所以其实是一个伪实现..

     1  private void SaveFile()
     2         {
     3             SaveFileDialog saveDlg = new SaveFileDialog();
     4             saveDlg.Filter = "sgf files (*.sgf)|*.sgf|All Files (*.*)|*.*";
     5             saveDlg.DefaultExt = ".sgf";
     6             DialogResult res = saveDlg.ShowDialog();
     7             if (res == DialogResult.OK)
     8             {
     9                 if (!(saveDlg.FileName).EndsWith(".sgf") && !(saveDlg.FileName).EndsWith(".SGF"))
    10                     MessageBox.Show("Unexpected file format", "Super Go Format", MessageBoxButtons.OK);
    11                 else
    12                 {
    13                     StreamWriter w = new StreamWriter(saveDlg.FileName, false);
    14                     string s = gameTree.Info;//这里应该递归掉gm的信息,但是gm目前不是全局变量.
    15                     w.WriteLine(s);
    16                     w.Close();
    17                 }
    18             }
    19         }

     后来我看到肖犇犇把计算气的非递归实现也当作一个改进,我想这也行,他是用栈实现的,机智的我用队列将它是实现了..

     1 /*------非递归BFS实现计算气------*/
     2         /*
     3         int CalcLibertyBfs(int x, int y, StoneColor c)
     4         {
     5             int lib=0;
     6             int[] dx = { 1, 0, -1, 0 };
     7             int[] dy = { 0, -1, 0, 1 };
     8             Queue q = new Queue();
     9             Point s=new Point(x,y);
    10             Point next = new Point();
    11             q.Enqueue(s);
    12             while (q.Count > 0)
    13             {
    14                 s = (Point)q.Dequeue();
    15                 for (int i = 0; i < 4; i++)
    16                 {
    17                     next.X = s.X + dx[i];
    18                     next.Y = s.Y + dy[i];
    19                     if (!OnBoard(next.X, next.Y))
    20                     {
    21                         continue;
    22                     }
    23                     if (Grid[next.X, next.Y].IsScanned())
    24                     {
    25                         continue;
    26                     }
    27                     if (!Grid[next.X, next.Y].HasStone())
    28                     {
    29                         lib++;
    30                     }
    31                     if (Grid[next.X, next.Y].Color() == c)
    32                     {
    33                         q.Enqueue(next);
    34                     }
    35                     Grid[next.X, next.Y].SetScanned();
    36                 }
    37             }
    38             return lib;
    39 
    40         }
    41         */

    如果大家有时间并有兴趣,可以做一些大的改进:

          a) 如果我要把这个程序变成一个可以人机对战的小游戏 (假设你的AI 模块已经写好,这里我们就可以让一个函数返回一个合法的位置就可以), 那这个程序的架构应该怎么变化?  请把这个功能写出来。

          b) 如果我想让这个程序变成两个用户可以通过网络对战,这个程序的架构要怎么变化?

    网络对战还是比较简单的。。。上次我们刚刚做过网络编程,那么这个只需要每次传递下棋的坐标就好,架构的变化我的倾向是对于游戏中每次换人行子的这部分改掉,这个GoMove参数可以由本机传递,也可以由网络编程传递的坐标来传,同理AI这块也可以这样做,可以让AI学习比较多的棋谱之后,计算得到下子的坐标,然后传到游戏的下子逻辑中即可

  • 相关阅读:
    洛谷P3747 [六省联考2017]相逢是问候
    染色(dye)
    BZOJ1426: 收集邮票
    消息队列RabbitMQ
    CRM
    BBS
    版本控制
    RESTful API
    Luffy
    axios使用
  • 原文地址:https://www.cnblogs.com/oldoldb/p/3439005.html
Copyright © 2011-2022 走看看