菜单 学习猿地 - LMONKEY

VIP

开通学习猿地VIP

尊享10项VIP特权 持续新增

知识通关挑战

打卡带练!告别无效练习

接私单赚外块

VIP优先接,累计金额超百万

学习猿地私房课免费学

大厂实战课仅对VIP开放

你的一对一导师

每月可免费咨询大牛30次

领取更多软件工程师实用特权

入驻
127
0

现代程序设计 homework-06

原创
05/13 14:22
阅读数 94343

写代码爽还是读代码爽?

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

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

 

本次作业要求:

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] == '\r' || inStr[iLast] == '\n' || 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学习比较多的棋谱之后,计算得到下子的坐标,然后传到游戏的下子逻辑中即可

 

发表评论

0/200
127 点赞
0 评论
收藏
为你推荐 换一批