现代程序设计 homework-06

时间:2023-02-01 10:30:00

写代码爽还是读代码爽?

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

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

本次作业要求:

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

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

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

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

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

 public void PlayPrev(GoMove gm)
{
if (gm == null)
{
throw new ArgumentNullException("gm");
}
Point p = gm.Point;//获得当前要移除的点
m_colorToPlay = gm.Color;//要移除的点的颜色
ClearLabelsAndMarksOnBoard();//清除highlight信息和落子信息
Grid[p.X, p.Y].RemoveStone();//remove the current move from the board
bDrawMark = false;//also remove the "lastmove" highlight
RepaintOneSpotNow(p);
if (gm.DeadGroup != null)//恢复被吃掉的子
{
for (int i = ; i <gm.DeadGroup.Count; i++)
{
Point pp = (Point)gm.DeadGroup[i];
RepaintOneSpotNow(pp);
Grid[pp.X, pp.Y].SetStone(gm.DeadGroupColor);
} }
m_gmLastMove = gameTree.PeekPrev();
if (m_gmLastMove != null)//highlight the new "lastmove"
{
bDrawMark = true;
RepaintOneSpotNow(m_gmLastMove.Point);
SetLabelsOnBoard(m_gmLastMove);
SetMarksOnBoard(m_gmLastMove);
}
OptRepaint();
}

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

现代程序设计 homework-06

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

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

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

编码风格,

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

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

编码风格:

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

程序架构:

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

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

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

 private void OpenFile()
{
OpenFileDialog openDlg = new OpenFileDialog();
openDlg.Filter = "sgf files (*.sgf)|*.sgf|All Files (*.*)|*.*";
openDlg.FileName = "" ;
openDlg.DefaultExt = ".sgf";
openDlg.CheckFileExists = true;
openDlg.CheckPathExists = true; DialogResult res = openDlg.ShowDialog (); if(res == DialogResult.OK)
{
if( !(openDlg.FileName).EndsWith(".sgf") && !(openDlg.FileName).EndsWith(".SGF"))
MessageBox.Show("Unexpected file format","Super Go Format",MessageBoxButtons.OK);
else
{
FileStream f = new FileStream(openDlg.FileName, FileMode.Open);
StreamReader r = new StreamReader(f);
string s = r.ReadToEnd();
gameTree = new GoTree(s);
gameTree.reset();
resetBoard();
r.Close();
f.Close();
}
}
}

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

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

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

现代程序设计 homework-06

而这个问题想要解决只需要简单设置一下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块来解决,其实由于很多地方确实马上释放了,所以也不妨取消显示这个错误

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

现代程序设计 homework-06

 
 

4) 程序的注释

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

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

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

工程全部代码如下:

 /**
* Go Applet
* 1996.11 xinz written in Java
* 2001.3 xinz port to C#
* 2001.5.10 xinz file parsing, back/forward
*/ using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.IO;
using System.Diagnostics;
using System.Resources;
[assembly: CLSCompliant(true)]
namespace DesignLibrary { } namespace GoWinApp
{ public enum StoneColor : int //黑子白子
{
Black = , White =
} /**
* 呵呵呵
*/
public class GoBoard : System.Windows.Forms.Form
{
string [] strLabels; // {"A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T"}; int nSize; //每行每列方格数 19
const int nBoardMargin = ; //边线距离 10
int nCoodStart = ;
const int nBoardOffset = ; //棋盘与左边距离 20
int nEdgeLen = nBoardOffset + nBoardMargin; //棋盘右下角的横纵长度
int nTotalGridWidth = + ; //方格总大小
int nUnitGridWidth = ; //每个小方格的大小
int nSeq = ;
Rectangle rGrid; // rectangle for 整个棋盘
StoneColor m_colorToPlay; // 接下来要走的旗子颜色
GoMove m_gmLastMove; // 上一步动作
Boolean bDrawMark; // 是否highlight高亮显示(话说高亮做的好挫..)
Boolean m_fAnyKill; // 是否有吃子动作
Spot [,] Grid; // 记录棋盘状态的二维数组
Pen penGrid; //各种色笔用来画图
//被删掉了, penStoneW, penStoneB,penMarkW, penMarkB
Brush brStar, brBoard, brBlack, brWhite, m_brMark; //各种画刷用来画图 // >>Button <<Button
int nFFMove = ; // 限制>>Button的最大操作数
// int nRewindMove = 10; // 限制<<Button的最大操作数,但1.这个变量没有使用过 2.<<Button click的时候直接就reset了,所以根本没用 GoTree gameTree; //游戏逻辑部分 /// 各种UI变量声明
// private System.ComponentModel.Container components;
private System.Windows.Forms.TextBox textBox1;
private System.Windows.Forms.Button Rewind;
private System.Windows.Forms.Button FForward;
private System.Windows.Forms.Button Save;
private System.Windows.Forms.Button Open;
private System.Windows.Forms.Button Back;
private System.Windows.Forms.Button Forward; public GoBoard(int nSize)
{
//
// Form第一步,初始化各种组件
//
InitializeComponent(); //
// 各种初始化操作
// this.nSize = nSize; //设定棋盘大小 m_colorToPlay = StoneColor.Black; //执黑先行 Grid = new Spot[nSize,nSize]; //new一个Grid存状态
for (int i=; i<nSize; i++)
for (int j=; j<nSize; j++)
Grid[i,j] = new Spot();
/*------以下各种初始化画笔画刷------*/
penGrid = new Pen(Color.Brown, (float)0.5);
//penStoneW = new Pen(Color.WhiteSmoke, (float)1);
//penStoneB = new Pen(Color.Black,(float)1);
//penMarkW = new Pen(Color.Blue, (float) 1);
//penMarkB = new Pen(Color.Beige, (float) 1); brStar = new SolidBrush(Color.Black);
brBoard = new SolidBrush(Color.Orange);
brBlack = new SolidBrush(Color.Black);
brWhite = new SolidBrush(Color.White);
m_brMark = new SolidBrush(Color.Red); rGrid = new Rectangle(nEdgeLen, nEdgeLen,nTotalGridWidth, nTotalGridWidth);
strLabels = new string [] {"a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t"};
gameTree = new GoTree();
}
/*------绘制UI------*/
#region
/// 动态绘制各种组件,没什么好说的
///
private void InitializeComponent()
{
this.Open = new System.Windows.Forms.Button();
this.Save = new System.Windows.Forms.Button();
this.Rewind = new System.Windows.Forms.Button();
this.Forward = new System.Windows.Forms.Button();
this.Back = new System.Windows.Forms.Button();
this.FForward = new System.Windows.Forms.Button();
this.textBox1 = new System.Windows.Forms.TextBox();
this.SuspendLayout();
//
// Open
//
this.Open.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.Open.Location = new System.Drawing.Point(, );
this.Open.Name = "Open";
this.Open.Size = new System.Drawing.Size(, );
this.Open.TabIndex = ;
this.Open.Text = "open";
this.Open.Click += new System.EventHandler(this.OpenClick);
//
// Save
//
this.Save.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.Save.Location = new System.Drawing.Point(, );
this.Save.Name = "Save";
this.Save.Size = new System.Drawing.Size(, );
this.Save.TabIndex = ;
this.Save.Text = "save";
this.Save.Click += new System.EventHandler(this.SaveClick);
//
// Rewind
//
this.Rewind.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.Rewind.Location = new System.Drawing.Point(, );
this.Rewind.Name = "Rewind";
this.Rewind.Size = new System.Drawing.Size(, );
this.Rewind.TabIndex = ;
this.Rewind.Text = "<<";
this.Rewind.Click += new System.EventHandler(this.RewindClick);
//
// Forward
//
this.Forward.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.Forward.Location = new System.Drawing.Point(, );
this.Forward.Name = "Forward";
this.Forward.Size = new System.Drawing.Size(, );
this.Forward.TabIndex = ;
this.Forward.Text = ">";
this.Forward.Click += new System.EventHandler(this.ForwardClick);
//
// Back
//
this.Back.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.Back.Location = new System.Drawing.Point(, );
this.Back.Name = "Back";
this.Back.Size = new System.Drawing.Size(, );
this.Back.TabIndex = ;
this.Back.Text = "<";
this.Back.Click += new System.EventHandler(this.BackClick);
//
// FForward
//
this.FForward.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.FForward.Location = new System.Drawing.Point(, );
this.FForward.Name = "FForward";
this.FForward.Size = new System.Drawing.Size(, );
this.FForward.TabIndex = ;
this.FForward.Text = ">>";
this.FForward.Click += new System.EventHandler(this.FForwardClick);
//
// textBox1
//
this.textBox1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.textBox1.Location = new System.Drawing.Point(, );
this.textBox1.Multiline = true;
this.textBox1.Name = "textBox1";
this.textBox1.Size = new System.Drawing.Size(, );
this.textBox1.TabIndex = ;
this.textBox1.Text = "please open a .sgf file to view, or just play on the board";
//
// GoBoard
//
this.AutoScaleBaseSize = new System.Drawing.Size(, );
this.AutoScroll = true;
this.ClientSize = new System.Drawing.Size(, );
this.Controls.Add(this.textBox1);
this.Controls.Add(this.Rewind);
this.Controls.Add(this.FForward);
this.Controls.Add(this.Save);
this.Controls.Add(this.Open);
this.Controls.Add(this.Back);
this.Controls.Add(this.Forward);
this.Name = "GoBoard";
this.Text = "Go_WinForm";
this.Click += new System.EventHandler(this.GoBoardClick);
this.Paint += new System.Windows.Forms.PaintEventHandler(this.PaintHandler);
this.MouseUp += new System.Windows.Forms.MouseEventHandler(this.MouseUpHandler);
this.ResumeLayout(false);
this.PerformLayout(); }
#endregion private void PaintHandler(Object sender, PaintEventArgs e)
{
UpdateGoBoard(e); //更新棋盘
}
/*------Save功能都没有实现?------*/
protected void SaveClick(object sender, System.EventArgs e)
{
SaveFile();
return;
}
/*------话说这些简单的button响应事件就不用多说了吧?------*/
protected void OpenClick(object sender, System.EventArgs e)
{
OpenFile();
ShowGameInfo();//棋谱文件可能带有自述信息
}
#region
protected void RewindClick(object sender, System.EventArgs e)
{
gameTree.Reset();//<<Button需要完成游戏逻辑重置,棋盘重置,并重新显示游戏信息
ResetBoard();
ShowGameInfo();
} protected void FForwardClick(object sender, System.EventArgs e)
{
if (gameTree != null)
{
int i = ;
GoMove gm = null;
for (gm = gameTree.DoNext(); gm != null; gm = gameTree.DoNext())
{
PlayNext(ref gm);
if (i++ > nFFMove)//将棋盘状态恢复到允许恢复到的最新状态
break;
}
}
} protected void ForwardClick(object sender, System.EventArgs e)
{
GoMove gm = gameTree.DoNext();
if (null != gm)//前进到有历史记录的下一个操作
{
PlayNext(ref gm);
}
}
private void ShowGameInfo()
{
//显示游戏信息
textBox1.Clear();
textBox1.AppendText(gameTree.Info);
} protected void BackClick(object sender, System.EventArgs e)
{
GoMove gm = gameTree.DoPrev(); //游戏历史记录中的前一步
if (null != gm)
{
PlayPrev(gm);
}
else
{
ResetBoard();
ShowGameInfo();
}
} Boolean OnBoard(int x, int y) //边界处理
{
return (x>= && x<nSize && y>= && y<nSize);
}
/*------又在没用可删的范畴内------*/
protected void GoBoardClick(object sender, System.EventArgs e)
{
return;
}
/*------将坐标转换为棋盘中的图块------*/
private Point PointToGrid(int x, int y)
{
Point p= new Point(,);
p.X = (x - rGrid.X + nUnitGridWidth/) / nUnitGridWidth;
p.Y = (y - rGrid.Y + nUnitGridWidth/) / nUnitGridWidth;
return p;
} //设定了在相交点附近怎样的范围内松开鼠标就视为在此处落子
//
private Boolean CloseEnough(Point p, int x, int y)
{
if (x < rGrid.X+nUnitGridWidth*p.X-nUnitGridWidth/ ||
x > rGrid.X+nUnitGridWidth*p.X+nUnitGridWidth/ ||
y < rGrid.Y+nUnitGridWidth*p.Y-nUnitGridWidth/ ||
y > rGrid.Y+nUnitGridWidth*p.Y+nUnitGridWidth/)
{
return false;
}
else
return true;
}
/// 鼠标松开事件,用来处理落子
private void MouseUpHandler(Object sender,MouseEventArgs e)
{
Point p;
GoMove gmThisMove; p = PointToGrid(e.X,e.Y);
if (!OnBoard(p.X, p.Y) || !CloseEnough(p,e.X, e.Y)|| Grid[p.X,p.Y].HasStone())
return; //不满足落子条件 //满足落子条件时,落子,并将thismove传到gametree中
gmThisMove = new GoMove(p.X, p.Y, m_colorToPlay, );
PlayNext(ref gmThisMove);
gameTree.AddMove(gmThisMove);
} public void PlayNext(ref GoMove gm)
{
if (gm == null)
{
throw new ArgumentNullException("gm");
}
Point p = gm.Point; //获得当前move点
m_colorToPlay = gm.Color; //接下来要下子的颜色 //清除highlight信息和落子信息
ClearLabelsAndMarksOnBoard(); if (m_gmLastMove != null)//如果上一轮已经落子,那么取消该棋子的高亮显示
{
RepaintOneSpotNow(m_gmLastMove.Point);
}
bDrawMark = true; //高亮显示
Grid[p.X,p.Y].SetStone(gm.Color); //落子
m_gmLastMove = new GoMove(p.X, p.Y, gm.Color, nSeq++); //将本次操作记录在lastmove中
//棋盘显示所有的labels和mark
SetLabelsOnBoard(gm);
SetMarksOnBoard(gm); DoDeadGroup(NextTurn(m_colorToPlay));//nextturn返回下一轮的行子颜色,这一操作即进行吃子动作,注意先判定本轮落子能否先吃对方
//如果有吃子的动作,那么就存入deadgroup中
if (m_fAnyKill)
{
AppendDeadGroup(ref gm, NextTurn(m_colorToPlay));
}
else //否则要判是否会被吃
{
DoDeadGroup(m_colorToPlay);
if (m_fAnyKill)
{
AppendDeadGroup(ref gm, m_colorToPlay);
}
}
m_fAnyKill = false; OptRepaint();//重绘棋盘 //更新下一轮落子颜色
m_colorToPlay = NextTurn(m_colorToPlay); //......更新游戏信息,这里其实可以重写showgameinfo()
textBox1.Clear();
textBox1.AppendText(gm.Comment);
}
/*------添加被吃的颜色为c的子------*/
private void AppendDeadGroup(ref GoMove gm, StoneColor c)
{
ArrayList a = new ArrayList();
for (int i=; i<nSize; i++)
for (int j=; j<nSize; j++)
if (Grid[i,j].IsKilled())
{
Point pt = new Point(i,j);
a.Add(pt);
Grid[i,j].SetNoKilled();//这里...真的有必要封装成这个样子么..
}
gm.DeadGroup = a;//存入本次动作gm中,gm.deadgroup就存放了本轮被吃的子,于是playprev可以用到
gm.DeadGroupColor = c;
}
/*------重绘棋盘------*/
public void ResetBoard()
{
int i,j;
for (i=; i<nSize; i++)
for (j=; j<nSize; j++)
Grid[i,j].RemoveStone();
m_gmLastMove = null;
Invalidate(null);
} /*
* play the move so that the game situation is just BEFORE this move is played.
* what to do:
* 1. remove the current move from the board :removestone
* 1.1 also remove the "lastmov" highlight :bDrawMark=false;
* 2. store the stones got killed by current move
* 3. highlight the new "lastmove" :bDrawMark=true
*/
public void PlayPrev(GoMove gm)
{
if (gm == null)
{
throw new ArgumentNullException("gm");
}
Point p = gm.Point;//获得当前要移除的点
m_colorToPlay = gm.Color;//要移除的点的颜色
ClearLabelsAndMarksOnBoard();//清除highlight信息和落子信息
Grid[p.X, p.Y].RemoveStone();//remove the current move from the board
bDrawMark = false;//also remove the "lastmove" highlight
RepaintOneSpotNow(p);
if (gm.DeadGroup != null)//恢复被吃掉的子
{
for (int i = ; i <gm.DeadGroup.Count; i++)
{
Point pp = (Point)gm.DeadGroup[i];
RepaintOneSpotNow(pp);
Grid[pp.X, pp.Y].SetStone(gm.DeadGroupColor);
} }
m_gmLastMove = gameTree.PeekPrev();
if (m_gmLastMove != null)//highlight the new "lastmove"
{
bDrawMark = true;
RepaintOneSpotNow(m_gmLastMove.Point);
SetLabelsOnBoard(m_gmLastMove);
SetMarksOnBoard(m_gmLastMove);
}
OptRepaint();
} Rectangle GetUpdatedArea(int i, int j) //返回需要更新重绘的区域
{
int x = rGrid.X + i * nUnitGridWidth - nUnitGridWidth/;
int y = rGrid.Y + j * nUnitGridWidth - nUnitGridWidth/;
return new Rectangle(x,y, nUnitGridWidth, nUnitGridWidth);
} /**
* 重绘
*/
private void OptRepaint()
{
Rectangle r = new Rectangle(,,,);
Region re; for (int i=; i<nSize; i++)
for (int j=; j<nSize; j++)
if (Grid[i,j].IsUpdated())
{
r = GetUpdatedArea(i,j);
re = new Region(r);
Invalidate(re);
re.Dispose();
}
} /*
* 只重回一个交叉点,用在本轮已经落子需要进行>>或者<<操作的时候
*/
public void RepaintOneSpotNow(Point point)
{
Grid[point.X, point.Y].SetUpdated();
bDrawMark = false;
Rectangle r = GetUpdatedArea(point.X, point.Y);
Region re=new Region(r);
Invalidate(re);
re.Dispose();
Grid[point.X, point.Y].ResetUpdated();
bDrawMark = true;
} //字面意思是记录操作,但是这个函数没有用到过,很可疑
public void RecordMove(Point point, StoneColor colorToPlay)
{
Grid[point.X, point.Y].SetStone(colorToPlay);
// 将上一个操作置为该次操作
m_gmLastMove = new GoMove(point.X, point.Y, colorToPlay, nSeq++);
}
//返回下次落子的颜色
static StoneColor NextTurn(StoneColor c)
{
if (c == StoneColor.Black)
return StoneColor.White;
else
return StoneColor.Black;
} /**
* bury the dead stones in a group (same color).
* if a stone in one group is dead, the whole group is dead.
* 说白了就是dfs消除相连的气为0的子
*/
void BuryTheDead(int i, int j, StoneColor c)
{
if (OnBoard(i,j) && Grid[i,j].HasStone() &&
Grid[i,j].Color() == c)
{
Grid[i,j].Die();
BuryTheDead(i-, j, c);
BuryTheDead(i+, j, c);
BuryTheDead(i, j-, c);
BuryTheDead(i, j+, c);
}
}
/*------清除扫描记录,就是清除visit数组的意思------*/
void CleanScanStatus()
{
int i,j;
for (i=; i<nSize; i++)
for (j=; j<nSize; j++)
Grid[i,j].ClearScanned();
} /**
* 扫描整个棋盘,对当前颜色c,提掉所有气为0的子
*/
void DoDeadGroup(StoneColor c)
{
int i,j;
for (i=; i<nSize; i++)
for (j=; j<nSize; j++)
if (Grid[i,j].HasStone() &&
Grid[i,j].Color() == c)
{
if (CalcLiberty(i,j,c) == )
{
BuryTheDead(i,j,c);
m_fAnyKill = true;
}
CleanScanStatus();
}
}
/*------非递归BFS实现计算气------*/
/*
int CalcLibertyBfs(int x, int y, StoneColor c)
{
int lib=0;
int[] dx = { 1, 0, -1, 0 };
int[] dy = { 0, -1, 0, 1 };
Queue q = new Queue();
Point s=new Point(x,y);
Point next = new Point();
q.Enqueue(s);
while (q.Count > 0)
{
s = (Point)q.Dequeue();
for (int i = 0; i < 4; i++)
{
next.X = s.X + dx[i];
next.Y = s.Y + dy[i];
if (!OnBoard(next.X, next.Y))
{
continue;
}
if (Grid[next.X, next.Y].IsScanned())
{
continue;
}
if (!Grid[next.X, next.Y].HasStone())
{
lib++;
}
if (Grid[next.X, next.Y].Color() == c)
{
q.Enqueue(next);
}
Grid[next.X, next.Y].SetScanned();
}
}
return lib; }
*/
/**
* dfs计算每个子(每个group)的气
*/
int CalcLiberty(int x, int y, StoneColor c)
{
int lib = ; // 初始化 if (!OnBoard(x,y))
return ;
if (Grid[x,y].IsScanned())
return ; if (Grid[x,y].HasStone())
{
if (Grid[x,y].Color() == c)
{
//dfs深搜四个相邻的格子
Grid[x,y].SetScanned();
lib += CalcLiberty(x-, y, c);
lib += CalcLiberty(x+, y, c);
lib += CalcLiberty(x, y-, c);
lib += CalcLiberty(x, y+, c);
}
else
return ;
}
else
{// 周围没有棋子的话气+1
lib ++;
Grid[x,y].SetScanned();
} return lib;
} /**
* 高亮显示上一次的落子
*/
void MarkLastMove(Graphics g)
{
Brush brMark;
if (m_gmLastMove.Color == StoneColor.White)
brMark = brBlack;
else
brMark = brWhite;
Point p = m_gmLastMove.Point;
g.FillRectangle( brMark,
rGrid.X + (p.X) * nUnitGridWidth - (nUnitGridWidth-)/,
rGrid.Y + (p.Y) * nUnitGridWidth - (nUnitGridWidth-)/,
, );
}
/*------消除所有棋子和高亮标记------*/
private void ClearLabelsAndMarksOnBoard()
{
for (int i=; i<nSize; i++)
for (int j=; j<nSize; j++)
{
if (Grid[i,j].HasLabel())
Grid[i,j].ResetLabel();
if (Grid[i,j].HasMark())
Grid[i,j].ResetMark();
} }
/*------就是按照当前操作gm,将gm之前的labels全部落下------*/
private void SetLabelsOnBoard(GoMove gm)
{
short nLabel = ;
Point p;
if (null != gm.Labels)
{
System.Collections.IEnumerator myEnumerator = gm.Labels.GetEnumerator();
while (myEnumerator.MoveNext())
{
p = (Point)myEnumerator.Current;
Grid[p.X,p.Y].SetLabel(++nLabel);
}
}
}
/*------设置棋盘上的高亮显示------*/
private void SetMarksOnBoard(GoMove gm)
{
Point p;
if (null != gm.Labels)
{
System.Collections.IEnumerator myEnumerator = gm.Marks.GetEnumerator();
while ( myEnumerator.MoveNext() )
{
p = (Point)myEnumerator.Current;
Grid[p.X,p.Y].SetMark();
}
}
} static private Point SwapXY(Point p)//额...交换两点坐标
{
Point pNew = new Point(p.Y,p.X);
return pNew;
}
/*------绘制棋盘------*/
private void DrawBoard(Graphics g)
{
//绘制坐标
string[] strV= {"","","","","","","","","","","","","","","","","","",""};
string [] strH= {"A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T"}; Point p1 = new Point(nEdgeLen,nEdgeLen);
Point p2 = new Point(nTotalGridWidth+nEdgeLen,nEdgeLen);
g.FillRectangle(brBoard,nBoardOffset,nBoardOffset,nTotalGridWidth+nBoardOffset,nTotalGridWidth+nBoardOffset);
for (int i=;i<nSize; i++)
{
g.DrawString(strV[i],this.Font, brBlack, , nCoodStart+ nBoardOffset + nUnitGridWidth*i);
g.DrawString(strH[i],this.Font, brBlack, nBoardOffset + nCoodStart + nUnitGridWidth*i, );
g.DrawLine(penGrid, p1, p2);
g.DrawLine(penGrid, SwapXY(p1), SwapXY(p2)); p1.Y += nUnitGridWidth;
p2.Y += nUnitGridWidth;
}
//绘制边线
Pen penHi = new Pen(Color.WhiteSmoke, (float)0.5);
Pen penLow = new Pen(Color.Gray, (float)0.5); g.DrawLine(penHi, nBoardOffset, nBoardOffset, nTotalGridWidth+*nBoardOffset, nBoardOffset);
g.DrawLine(penHi, nBoardOffset, nBoardOffset, nBoardOffset, nTotalGridWidth+*nBoardOffset);
g.DrawLine(penLow, nTotalGridWidth+*nBoardOffset,nTotalGridWidth+*nBoardOffset, nBoardOffset+, nTotalGridWidth+*nBoardOffset);
g.DrawLine(penLow, nTotalGridWidth+*nBoardOffset,nTotalGridWidth+*nBoardOffset, nTotalGridWidth+*nBoardOffset, nBoardOffset+);
} void UpdateGoBoard(PaintEventArgs e)
{
DrawBoard(e.Graphics); //绘制天元
DrawStars(e.Graphics); //绘制每一个区域
DrawEverySpot(e.Graphics);
} //绘制天元
void DrawStar(Graphics g, int row, int col)
{
g.FillRectangle(brStar,
rGrid.X + (row-) * nUnitGridWidth - ,
rGrid.Y + (col-) * nUnitGridWidth - ,
,
);
} //绘制9个天元
void DrawStars(Graphics g)
{
DrawStar(g, , );
DrawStar(g, , );
DrawStar(g, , );
DrawStar(g, , );
DrawStar(g, , );
DrawStar(g, , );
DrawStar(g, , );
DrawStar(g, , );
DrawStar(g, , );
} /**
* 绘制落子
*/
void DrawStone(Graphics g, int row, int col, StoneColor c)
{
Brush br;
if (c == StoneColor.White)
br = brWhite;
else
br = brBlack; Rectangle r = new Rectangle(rGrid.X+ (row) * nUnitGridWidth - (nUnitGridWidth-)/,
rGrid.Y + (col) * nUnitGridWidth - (nUnitGridWidth-)/,
nUnitGridWidth-,
nUnitGridWidth-); g.FillEllipse(br, r);
}
/*------这个函数貌似没有调用过?------*/
void DrawLabel(Graphics g, int x, int y, short nLabel)
{
if (nLabel ==)
return;
nLabel --;
nLabel %= ; //各种转换 //画Label
Rectangle r = new Rectangle(rGrid.X+ x * nUnitGridWidth - (nUnitGridWidth-)/,
rGrid.Y + y * nUnitGridWidth - (nUnitGridWidth-)/,
nUnitGridWidth-,
nUnitGridWidth-); g.FillEllipse(brBoard, r);
g.DrawString(strLabels[nLabel], //填字符串
this.Font,
brBlack,
rGrid.X+ (x) * nUnitGridWidth - (nUnitGridWidth-)/,
rGrid.Y + (y) * nUnitGridWidth - (nUnitGridWidth-)/);
}
/*------绘制highlight点------*/
void DrawMark(Graphics g, int x, int y)
{
g.FillRectangle( m_brMark,
rGrid.X + x* nUnitGridWidth - (nUnitGridWidth-)/,
rGrid.Y + y * nUnitGridWidth - (nUnitGridWidth-)/,
, );
}
/*------绘制每一个落子点------*/
void DrawEverySpot(Graphics g)
{
for (int i=; i<nSize; i++)
for (int j=; j<nSize; j++)
{
if (Grid[i,j].HasStone())
DrawStone(g, i, j, Grid[i,j].Color());
if (Grid[i,j].HasLabel())
DrawLabel(g, i, j, Grid[i,j].GetLabel());
if (Grid[i,j].HasMark())
DrawMark(g, i, j);
}
//标记操作
if (bDrawMark && m_gmLastMove != null)
MarkLastMove(g);
}
#endregion
[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)")]
private void SaveFile()
{
using (SaveFileDialog saveDlg = new SaveFileDialog())
{
saveDlg.Filter = "sgf files (*.sgf)|*.sgf|All Files (*.*)|*.*";
saveDlg.DefaultExt = ".sgf";
DialogResult res = saveDlg.ShowDialog();
if (res == DialogResult.OK)
{
if (!(saveDlg.FileName).EndsWith(".sgf") && !(saveDlg.FileName).EndsWith(".SGF"))
MessageBox.Show("Unexpected file format", "Super Go Format", MessageBoxButtons.OK);
else
{
using (StreamWriter w = new StreamWriter(saveDlg.FileName, false))
{
string s = gameTree.Info;//这里应该递归掉gm的信息,但是gm目前不是全局变量.
w.WriteLine(s);
}
}
}
}
}
//打开棋谱文件
private void OpenFile()
{
OpenFileDialog openDlg = new OpenFileDialog();
openDlg.Filter = "sgf files (*.sgf)|*.sgf|All Files (*.*)|*.*";
openDlg.FileName = "" ;
openDlg.DefaultExt = ".sgf";
openDlg.CheckFileExists = true;
openDlg.CheckPathExists = true; DialogResult res = openDlg.ShowDialog (); if(res == DialogResult.OK)
{
if (!(openDlg.FileName).EndsWith(".sgf") && !(openDlg.FileName).EndsWith(".SGF"))
MessageBox.Show("Unexpected file format", "Super Go Format", MessageBoxButtons.OK);
else
{
FileStream f = new FileStream(openDlg.FileName, FileMode.Open);
StreamReader r = new StreamReader(f);
string s = r.ReadToEnd();
gameTree = new GoTree(s);
gameTree.Reset();
ResetBoard();
// r.Close();
f.Close();
}
}
}
} public class GoTest
{
///
/// main入口,单线程标记
///
[STAThread]
public static void Main(string[] args)
{
Application.Run(new GoBoard());
}
} //Spot类代表每一个点
public class Spot
{
private Boolean bEmpty; //是否为空
private Boolean bKilled; //是否被吃
private Stone s; //落子属性
private short m_nLabel;
private Boolean m_bMark; //是否高亮
private Boolean bScanned; //是否被扫描过
private Boolean bUpdated; //是否已经被更新
/**
* 构造函数
*/
public Spot()
{
bEmpty = true;
bScanned = false;
bUpdated = false;
bKilled = false;
}
/*------简单各种方法------*/
public Boolean HasStone() { return !bEmpty; }
public Boolean IsEmpty() { return bEmpty; }
public Stone ThisStone() { return s;}
public StoneColor Color() { return s.color;} public Boolean HasLabel() {return m_nLabel>;}
public Boolean HasMark() {return m_bMark;}
public void SetLabel(short label) {m_nLabel = label; bUpdated = true; }
public void SetMark() {m_bMark = true; bUpdated = true;}
public void ResetLabel() {m_nLabel = ; bUpdated = true;}
public void ResetMark() {m_bMark = false; bUpdated = true;}
public short GetLabel() {return m_nLabel;} public Boolean IsScanned() { return bScanned;}
public void SetScanned() { bScanned = true;}
public void ClearScanned() { bScanned = false; } public void SetStone(StoneColor color)
{
if (bEmpty)
{
bEmpty = false;
s.color = color;
bUpdated = true;
} // 落子
} /*
* 提子
*/
public void RemoveStone()
{ //提子
bEmpty = true;
bUpdated = true;
} //被吃
public void Die()
{
bKilled = true;
bEmpty = true;
bUpdated = true;
} public Boolean IsKilled() { return bKilled;}
public void SetNoKilled() { bKilled = false;} public void ResetUpdated() { bUpdated = false; bKilled = false;} //是否被更新
public Boolean IsUpdated()
{
if (bUpdated)
{ //如果已经被更新了,那么置更新状态为反
bUpdated = false;
return true;
}
else
return false;
} // updated的set函数
public void SetUpdated() { bUpdated = true; }
} /**
* 操作类
*/
public class GoMove
{
StoneColor m_c; //落子颜色
Point m_pos; //落子位置
int m_n; //操作数
String m_comment; // 每步操作的信息
MoveResult m_mr; //每步操作的结果 ArrayList m_alLabel; //所有的label
ArrayList m_alMark; //所有的mark //所有的被吃点
//被吃子的颜色
ArrayList m_alDead;
StoneColor m_cDead;
/**
* 构造函数
*/
public GoMove(int posX, int posY, StoneColor sc, int seq)
{
m_pos = new Point(posX,posY);
m_c = sc;
m_n = seq;
m_mr = new MoveResult();
m_alLabel = new ArrayList();
m_alMark = new ArrayList();
}
/*------这种构造函数用于棋谱文件------*/
public GoMove(String str, StoneColor color)
{
if (str == null)
{
throw new ArgumentNullException("str");
}
char cx = str[];
char cy = str[];
m_pos = new Point(,);
//转换为坐标
m_pos.X = (int) ( (int)cx - (int)(char)'a');
m_pos.Y = (int) ( (int)cy - (int)(char)'a');
this.m_c = color;
m_alLabel = new ArrayList();
m_alMark = new ArrayList();
} /*------还是将游戏信息中的str转换为点坐标,所以说上面的构造函数代码覆盖率太差------*/
static private Point StrToPoint(String str)
{
Point p = new Point(,);
char cx = str[];
char cy = str[];
//转换为坐标
p.X = (int) ( (int)cx - (int)(char)'a');
p.Y = (int) ( (int)cy - (int)(char)'a');
return p;
}
/*------各种get/set------*/
//落子颜色
public StoneColor Color
{
get { return m_c; }
}
//游戏信息
public String Comment
{
get
{
if (m_comment == null)
return string.Empty;
else
return m_comment;
}
set
{
m_comment = value;
}
} public int Seq
{
get { return m_n; }
set { m_n = value;}
} public Point Point
{
get { return m_pos; }
} public MoveResult Result
{
get { return m_mr; }
set { m_mr = value; }
} public ArrayList DeadGroup
{
get { return m_alDead;}
set {m_alDead = value;}
} public StoneColor DeadGroupColor
{
get { return m_cDead; }
set { m_cDead = value; }
} public void AddLabel(String str) {m_alLabel.Add(StrToPoint(str));} public void AddMark(String str) { m_alMark.Add(StrToPoint(str));} public ArrayList Labels
{
get { return m_alLabel; }
} public ArrayList Marks
{
get { return m_alMark; }
}
} /**
* 操作结果类
*
*/
public class MoveResult
{
public StoneColor color;
// 4个方向是否被吃子
public Boolean bUpKilled;
public Boolean bDownKilled;
public Boolean bLeftKilled;
public Boolean bRightKilled;
public Boolean bSuicide; //是否还有气
public MoveResult()
{
bUpKilled = false;
bDownKilled = false;
bLeftKilled = false;
bRightKilled = false;
bSuicide = false;
}
} /**
*
* ...这是在搞什么..突然又出现一个只有一个成员的struct..
*/
public struct Stone
{
public StoneColor color;
} /**
* 操作变量类
*
*/
public class GoVariation
{
// int m_id; //用不到删掉了
// string m_name; //用不到删掉了
//请直接无视我 //天知道你在说什么
ArrayList m_moves;
int m_seq; //这个东西应该是在读谱的时候才有用的
int m_total; //构造函数
public GoVariation(int id)
{
// m_id = id;
m_moves = new ArrayList();
m_seq = ;
m_total = ;
} public void AddAMove(GoMove gm)
{
if (gm == null)
{
throw new ArgumentNullException("gm");
}
gm.Seq = m_total ++;
m_seq++;
m_moves.Add(gm);
} public void UpdateResult(GoMove gm)
{
} public GoMove DoNext()
{
if (m_seq < m_total)
{
return (GoMove)m_moves[m_seq++];
}
else
return null;
} public GoMove DoPrev()
{
if (m_seq > )
return (GoMove)(m_moves[--m_seq]);
else
return null;
} /*
* 嗯下面这个确实很有用,它返回操作队列的当前操作的前一个
*/
public GoMove PeekPrev()
{
if (m_seq > )
return (GoMove)(m_moves[m_seq-]);
else
return null;
} public void Reset() {m_seq = ;}
} /**
* 我想说下面的其实用不到
* 下面的用不到的
*/
//struct VarStartPoint
//{
// int m_id;
// int m_seq;
//} struct GameInfo //这个GameInfo其实有好多用不到的地方
{
public string gameName;
public string playerBlack;
public string playerWhite;
public string rankBlack;
public string rankWhite;
public string result;
public string date;
public string km;
public string size;
public string comment;
public string handicap;
public string gameEvent;
public string location;
public string time; // 时间
public string unknown_ff; //谁能告诉我这是什么...
public string unknown_gm;
public string unknown_vw;
} /*------这一坨应该是解析棋谱类------*/ public class KeyValuePair
{
public string k; public ArrayList alV; static private string RemoveBackSlash(string strIn)
{
string strOut;
int iSlash; strOut = string.Copy(strIn);
if (strOut.Length < )
return strOut;
for (iSlash = strOut.Length-; iSlash>=; iSlash--)
{
if (strOut[iSlash] == '\\') // && 转义字符首先,搜字符\
{
strOut = strOut.Remove(iSlash,);
if (iSlash>)
iSlash --; // 就是专门解析棋谱文件的字符串操作...我们没必要花时间在这个上面
}
}
return strOut;
}
public KeyValuePair(string k, string v)
{
if (k == null)
{
throw new ArgumentNullException("k");
}
this.k = string.Copy(k);
string strOneVal;
int iBegin, iEnd; // 将棋谱信息转换为X[]的形式
alV = new ArrayList(); // Comment
if (k.Equals("C"))
{
strOneVal = RemoveBackSlash(string.Copy(v));
// Comment
alV.Add(strOneVal);
return;
}
if (v == null)
{
throw new ArgumentNullException("v");
}
iBegin = v.IndexOf("[");
if (iBegin == -) // 里面是坐标
{
alV.Add(v);
return;
} iBegin = ;
while (iBegin < v.Length && iBegin>=)
{
iEnd = v.IndexOf("]", iBegin);
if (iEnd > )
strOneVal = v.Substring(iBegin, iEnd-iBegin);
else
strOneVal = v.Substring(iBegin); // 里面是坐标
alV.Add(strOneVal);
iBegin = v.IndexOf("[", iBegin+);
if (iBegin > )
iBegin++; // 循环继续
}
}
} //GoTree其实是操作队列 public class GoTree
{
GameInfo _gi; //_gi:GameInfo游戏信息
ArrayList _vars; //forward的时候用
int _currVarId; //当前操作ID
// int _currVarNum;
GoVariation _currVar; //当前操作
string _stGameComment; // 由棋谱产生的构造函数
public GoTree(string str)
{
_vars = new ArrayList();
// _currVarNum = 0;
_currVarId = ;
_currVar = new GoVariation(_currVarId);
_vars.Add(_currVar);
ParseFile(str); // 棋谱信息转换
} // 平时用的构造函数
public GoTree()
{
_vars = new ArrayList();
// _currVarNum = 0;
_currVarId = ;
_currVar = new GoVariation(_currVarId);
_vars.Add(_currVar);
} public string Info
{
get
{
return _gi.comment == null? string.Empty : _gi.comment;
}
} public void AddMove(GoMove gm)
{
_currVar.AddAMove(gm);
} /**
* 顾名思义,棋谱文件转换用的
*/
Boolean ParseFile(String goStr)
{
int iBeg, iEnd=;
while (iEnd < goStr.Length)
{
if (iEnd > )
iBeg = iEnd;
else
iBeg = goStr.IndexOf(";", iEnd);//从iEnd后第一个;的位置
iEnd = goStr.IndexOf(";", iBeg+);//indexof如果未找到会返回-1
if (iEnd < ) // 没找到
iEnd = goStr.LastIndexOf(")", goStr.Length); //// 找最后一个)
if (iBeg >= && iEnd > iBeg)
{
string section = goStr.Substring(iBeg+, iEnd-iBeg-);
ParseASection(section);//划分出棋谱主体部分开始搞
}
else
break;
}
return true;
} /// 相当于词法分析提取一个单词
static public int FindEndofValueStr(String sec)
{
if (sec == null)
{
throw new ArgumentNullException("sec");
}
int i = ;
// 截到]
while (i >= )
{
i = sec.IndexOf(']', i+);
if (i > && sec[i - ] != '\\')
return i; // 返回单词位置
} // 没提到单词就返回总长度
return sec.Length - ; // 没提到单词就返回总长度
} static public int FindEndofValueStrOld(String sec)//老版,用不到
{
if (sec == null)
{
throw new ArgumentNullException("sec");
}
int i = ;
// 就是专门解析棋谱文件的字符串操作...我们没必要花时间在这个上面
bool fOutside = false; for (i=; i<sec.Length;i++)
{
if (sec[i] == ']')
{
if (i > && sec[i - ] != '\\') // 就是专门解析棋谱文件的字符串操作...我们没必要花时间在这个上面
fOutside = true;
}
else if (char.IsLetter(sec[i]) && fOutside && i>)
return i-;
else if (fOutside && sec[i] == '[')
fOutside = false;
}
return sec.Length - ; // 就是专门解析棋谱文件的字符串操作...我们没必要花时间在这个上面
} static private string PurgeCRLFSuffix(string inStr)
{
int iLast = inStr.Length - ; // 就像词法分析跳过没有意义的字符一样 if (iLast <= )
return inStr; while ((inStr[iLast] == '\r' || inStr[iLast] == '\n' || inStr[iLast] == ' '))
{
iLast--;
}
if ((iLast+) != inStr.Length)
return inStr.Substring(, iLast + ); //就像词法分析跳过没有意义的字符一样
else
return inStr;
} // 棋谱主体部分
Boolean ParseASection(String sec)
{
int iKey = ;
int iValue = ;
int iLastValue = ;
KeyValuePair kv;
ArrayList Section = new ArrayList(); try
{
iKey = sec.IndexOf("[");
if (iKey < )
{
return false;
}
sec = PurgeCRLFSuffix(sec); iValue = FindEndofValueStr(sec); // 提取一个[]操作
iLastValue = sec.LastIndexOf("]");
if (iValue <= || iLastValue <= )
{
return false;
}
sec = sec.Substring(,iLastValue+);
while (iKey > && iValue > iKey)// 正确提取了一个[]
{
string key = sec.Substring(,iKey);
int iNonLetter = ;
while (!char.IsLetter(key[iNonLetter]) && iNonLetter < key.Length)
iNonLetter ++;
key = key.Substring(iNonLetter);
// X[]
string strValue = sec.Substring(iKey+, iValue-iKey-);
// 键值对
kv = new KeyValuePair(key, strValue);
Section.Add(kv);
if (iValue >= sec.Length)
break;
sec = sec.Substring(iValue+);
iKey = sec.IndexOf("[");
if (iKey > )
{
iValue = FindEndofValueStr(sec); // 循环继续
}
}
}
catch
{
return false;
} ProcessASection(Section);
return true;
} // 提取出操作后就要进行识别了
Boolean ProcessASection(ArrayList arrKV)
{
Boolean fMultipleMoves = false; //单步操作
GoMove gm = null; string key, strValue; for (int i = ;i<arrKV.Count;i++)
{
key = ((KeyValuePair)(arrKV[i])).k;
for (int j=; j<((KeyValuePair)(arrKV[i])).alV.Count; j++)
{
strValue = (string)(((KeyValuePair)(arrKV[i])).alV[j]); if (key.Equals("B")) // 黑
{
Debug.Assert(gm == null);
gm = new GoMove(strValue, StoneColor.Black);
}
else if (key.Equals("W")) // 白
{
Debug.Assert(gm == null);
gm = new GoMove(strValue, StoneColor.White);
}
else if (key.Equals("C")) // Comment,针对一些步数发表自己的看法。。
{
// 初始comment
if (gm != null)
gm.Comment = strValue;
else // appent comment
_gi.comment += strValue;
}
else if (key.Equals("L")) // 放子,就是一开始就有一些地方放了子
{
if (gm != null)
gm.AddLabel(strValue);
else // 中途放子是个什么逻辑
_stGameComment += strValue;
} else if (key.Equals("M")) // 貌似是在开始之前就显示一些重要的操作?
{
if (gm != null)
gm.AddMark(strValue);
else // 游戏中途搞这个?
_gi.comment += strValue;
}
else if (key.Equals("AW")) // 突然觉得好蛋疼,给这么一串英文标识符让我们来猜意思?
{
fMultipleMoves = true;
gm = new GoMove(strValue, StoneColor.White);
}
else if (key.Equals("AB")) // 多步黑
{
fMultipleMoves = true;
gm = new GoMove(strValue, StoneColor.Black);
}
else if (key.Equals("HA"))//这些键值对根本就没有被用过..
_gi.handicap = (strValue);
else if (key.Equals("BR"))
_gi.rankBlack = (strValue);
else if (key.Equals("PB"))
_gi.playerBlack = (strValue);
else if (key.Equals("PW"))
_gi.playerWhite = (strValue);
else if (key.Equals("WR"))
_gi.rankWhite = (strValue);
else if (key.Equals("DT"))
_gi.date = (strValue);
else if (key.Equals("KM"))
_gi.km = (strValue);
else if (key.Equals("RE"))
_gi.result = (strValue);
else if (key.Equals("SZ"))
_gi.size = (strValue);
else if (key.Equals("EV"))
_gi.gameEvent = (strValue);
else if (key.Equals("PC"))
_gi.location = (strValue);
else if (key.Equals("TM"))
_gi.time = (strValue);
else if (key.Equals("GN"))
_gi.gameName = strValue; else if (key.Equals("FF"))
_gi.unknown_ff = (strValue);
else if (key.Equals("GM"))
_gi.unknown_gm = (strValue);
else if (key.Equals("VW"))
_gi.unknown_vw = (strValue);
else if (key.Equals("US"))
_gi.unknown_vw = (strValue); else if (key.Equals("BS"))
_gi.unknown_vw = (strValue);
else if (key.Equals("WS"))
_gi.unknown_vw = (strValue);
else if (key.Equals("ID"))
_gi.unknown_vw = (strValue);
else if (key.Equals("KI"))
_gi.unknown_vw = (strValue);
else if (key.Equals("SO"))
_gi.unknown_vw = (strValue);
else if (key.Equals("TR"))
_gi.unknown_vw = (strValue);
else if (key.Equals("LB"))
_gi.unknown_vw = (strValue);
else if (key.Equals("RO"))
_gi.unknown_vw = (strValue); // 未定义的键值对
else
System.Diagnostics.Debug.Assert(false, "unhandle key: " + key + " "+ strValue); // 如果是多步操作
if (fMultipleMoves)
{
_currVar.AddAMove(gm);
}
}
} // 下一步
if (!fMultipleMoves && gm != null)
{
_currVar.AddAMove(gm);
}
return true;
} public GoMove DoPrev()
{
return _currVar.DoPrev();
} public GoMove PeekPrev()
{
return _currVar.PeekPrev();
} public GoMove DoNext()
{
return _currVar.DoNext();
} public void UpdateResult(GoMove gm)
{
_currVar.UpdateResult(gm);
} public void Reset()
{
// _currVarNum = 0;
_currVarId = ;
_currVar.Reset();
}
static public void RewindToStart()
{ }
}
}

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

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

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

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

  private void SaveFile()
{
SaveFileDialog saveDlg = new SaveFileDialog();
saveDlg.Filter = "sgf files (*.sgf)|*.sgf|All Files (*.*)|*.*";
saveDlg.DefaultExt = ".sgf";
DialogResult res = saveDlg.ShowDialog();
if (res == DialogResult.OK)
{
if (!(saveDlg.FileName).EndsWith(".sgf") && !(saveDlg.FileName).EndsWith(".SGF"))
MessageBox.Show("Unexpected file format", "Super Go Format", MessageBoxButtons.OK);
else
{
StreamWriter w = new StreamWriter(saveDlg.FileName, false);
string s = gameTree.Info;//这里应该递归掉gm的信息,但是gm目前不是全局变量.
w.WriteLine(s);
w.Close();
}
}
}

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

 /*------非递归BFS实现计算气------*/
/*
int CalcLibertyBfs(int x, int y, StoneColor c)
{
int lib=0;
int[] dx = { 1, 0, -1, 0 };
int[] dy = { 0, -1, 0, 1 };
Queue q = new Queue();
Point s=new Point(x,y);
Point next = new Point();
q.Enqueue(s);
while (q.Count > 0)
{
s = (Point)q.Dequeue();
for (int i = 0; i < 4; i++)
{
next.X = s.X + dx[i];
next.Y = s.Y + dy[i];
if (!OnBoard(next.X, next.Y))
{
continue;
}
if (Grid[next.X, next.Y].IsScanned())
{
continue;
}
if (!Grid[next.X, next.Y].HasStone())
{
lib++;
}
if (Grid[next.X, next.Y].Color() == c)
{
q.Enqueue(next);
}
Grid[next.X, next.Y].SetScanned();
}
}
return lib; }
*/

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

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

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

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

现代程序设计 homework-06的更多相关文章

  1. 标准C程序设计七---06

    Linux应用             编程深入            语言编程 标准C程序设计七---经典C11程序设计    以下内容为阅读:    <标准C程序设计>(第7版) 作者 ...

  2. 现代程序设计homework——04

    题目: 详见:http://www.cnblogs.com/xinz/p/3341551.html 题目本身确实很难,“很难想到一个比较优雅的算法”,这是一个老师请来专门讲解这道题的大牛的原话.确实, ...

  3. homework -06 围棋

    playPrev功能的实现 public void playPrev(ref GoMove gm) { Point p = gm.Point; m_colorToPlay = gm.Color; cl ...

  4. nVIDIA SDK White Paper ----Vertex Texture Fetch Water

    http://blog.csdn.net/soilwork/article/details/713842 nVIDIA SDK White Paper ----Vertex Texture Fetch ...

  5. 软工&plus;C&lpar;9&rpar;&colon; 助教指南,持续更新&period;&period;&period;

    上一篇:提问与回复 下一篇:从命令行开始逐步培养编程能力(Java) 目录: ** 0x00 Handshake ** 0x01 点评 ** 0x02 评分 ** 0x03 知识储备 ** 0x04 ...

  6. 20145219 《Java程序设计》第06周学习总结

    20145219 <Java程序设计>第06周学习总结 教材学习内容总结 InputStream与OutputStream 串流设计 1.串流:Java将输入/输出抽象化为串流,数据有来源 ...

  7. 读书笔记&lpar;06&rpar; - 语法基础 - JavaScript高级程序设计

    写在开头 本篇是小红书笔记的第六篇,也许你会奇怪第六篇笔记才写语法基础,笔者是不是穿越了. 答案当然是没有,笔者在此分享自己的阅读心得,不少人翻书都是从头开始,结果永远就只在前几章. 对此,笔者换了随 ...

  8. 2016CCPC东北地区大学生程序设计竞赛【01&sol;03&sol;05&sol;06&sol;08】

    吧啦啦啦啦啦啦啦啦啦啦啦能量,ACM,跨!变身!变成一个智障! 04正在酝酿中!!!马上更新!!!!!  01题意:有一个n个点的图,对于任意两个不同的点,他的权值是两个点下标的最小公倍数,求最小生出 ...

  9. &num; 20145210 《Java程序设计》第06周学习总结

    教材学习内容总结 第十章 输入\输出 10.1 InputStream与OutputStream •串流设计的概念 •java将输入\输出抽象化为串流,数据有来源及目的地,衔接两者的是串流对象 •从应 ...

  10. Python Revisited Day 06 &lpar;面向对象程序设计)

    目录 6.1 面向对象方法 duck typing 访问限制 __ 6.2 自定义类 6.2.1 属性与方法 预定义的特殊方法 __...__ 一般的方法名起始和结尾不应该使用俩个下划线,除非是预定义 ...

随机推荐

  1. ASP&period;NET MVC Model元数据&lpar;四&rpar;

    ASP.NET MVC Model元数据(四) 前言 前面的篇幅讲解了Model元数据生成的过程,并没有对Model元数据生成过程的内部和Model元数据结构的详细解释.看完本篇后将会对Model元数 ...

  2. SQL创建字段信息&lpar;表值函数&rpar;

    ALTER FUNCTION [dbo].[fnt_SplitString] ( @p1 varchar(Max), ) ) RETURNS @Table_Var TABLE ( c1 varchar ...

  3. Cardinal:一个用于移动项目开发的轻量 CSS 框架

    Cardinal 是一个适用于移动项目的 CSS 框架,包含很多有用的默认样式.矢量字体.可重用的模块以及一个简单的响应式模块系统.Cardinal 提供了一种在多种移动设备上实现可伸缩的字体和布局的 ...

  4. Android驱动入门-LED--HAL硬件访问服务层②

    硬件平台: FriendlyARM Tiny4412 Cortex-A9 操作系统: UBUNTU 14.04 LTS 时间:2016-09-21  16:58:56 为了避免访问冲突,则创建了硬件访 ...

  5. 北斗&sol;GPS

    北斗/GPS都是用的nmea通用协议. NMEA-0183协议定义的语句非常多,但是常用的或者说兼容性最广的语句只有$GPGGA.$GPGSA.$GPGSV.$GPRMC.$GPVTG.$GPGLL等 ...

  6. 【leetcode】Fraction to Recurring Decimal

    Fraction to Recurring Decimal Given two integers representing the numerator and denominator of a fra ...

  7. HDU 2586 &plus; HDU 4912 最近公共祖先

    先给个LCA模板 HDU 1330(LCA模板) #include <cstdio> #include <cstring> #define N 40005 struct Edg ...

  8. 2014年度辛星html教程夏季版第五节

    如果读者是一位后台开发者,那么肯定会知道什么叫表单,这里我们就介绍一下前台如何使用表单,表单的使用也是我们编写网页的必须经历的一关,而且,表单也往往是我们网站的漏洞和弱点出现的地方. ******** ...

  9. 桂林电子科技大学第三届ACM程序设计竞赛 G 路径

    链接:https://ac.nowcoder.com/acm/contest/558/G来源:牛客网 小猫在研究树. 小猫在研究路径. 给定一棵N个点的树,每条边有边权,请你求出最长的一条路径,满足经 ...

  10. 实习笔记 burpsuite

    1.通过设置拦截HTTPS协议消息: 拦截HTTPS协议消息,HTTPS在原有的基础上增加了安全套接字层SSL协议,通过CA证书来验证服务器的身份,在拦截设置中,绑定端口有三种模式,分别是仅本地回路模 ...