CSDN博客

img inelm

围棋打谱程序之棋盘类(包括提子,子串搜索,打劫,禁手等判断)

发表于2004/7/4 6:23:00  2281人阅读

?

/**************************************************************************************/
?* 功能:?棋盘类
?* 描述:?用于描述和计算棋盘上的棋子状态, 气, 子串
?*???提子等判断。
?* 作者:?Chen Rong
?* 时间:?2004-6-7 2:24
?*
?* History:
?*???2004-6-7 2:24 :实现了子串的搜索, 串的气判断。 使用了 ArrayList 类, 以后效率
?*???????如果要优化, 可改写成数组。
? **************************************************************************************/

using System;
using System.Collections;
using System.Drawing;

namespace ChenRong.Weiqi
{
?///


?/// Board 的摘要说明。
?///

?public class Board
?{
??public static readonly int Black = -1;
??public static readonly int Empty = 0;
??public static readonly int White = 1;

??// 棋子数组
??private int[,] stones;?
??// 最后一步杀死的棋子数
??public int LastKillCount = 0;

??// 上下左右偏移量数组, 用于判断某位置周围四个点的情况
??private int[,] offsets = new int[4, 2] { { -1, 0 }, { 1, 0 }, { 0, -1 }, { 0, 1} };

??// 构造函数(constructor)
??public Board()
??{
???this.stones = new int[19, 19];
???this.SetForNewGame();
??}

??// 复制棋盘
??public Board(Board board)
??{
???this.stones = board.stones;
???this.LastKillCount = board.LastKillCount;
??}

??// 初始化
??public void SetForNewGame()
??{
???for (int i = 0; i < 19; i++)
???{
????for (int j = 0; j < 19; j++)
????{
?????stones[i, j] = Board.Empty;
????}
???}
???this.LastKillCount = 0;
??}

??// 得到棋盘上某个位置的状态
??public int GetPointContent(int row, int col)
??{
???return this.stones[row, col];
??}

??// 判断一个着点是否有效??注: 有待改进, 还需要判断不能自杀, 不能连续提劫等规则限制, 目前先不考虑
??public bool IsValidMove(int color, int row, int col)
??{
???if (this.stones[row, col] != Board.Empty)???
????return false;
???else
???{
????// 复制一个棋盘, 作为备份
????Board board = new Board(this);
????// 在复制的棋盘演练: 试落一子????
????board.stones[row, col] = color;
????ArrayList chuanSelf = board.FindChuan(row, col);

????// 不会自杀, 则返回
????if (board.CountChuanGas(chuanSelf) > 0)??
????{
?????return true;
????}
????// 如果落子会自杀, 判断是否会杀死地方的子, 如果不能则这一手不是有效着点
????// (先不考虑打劫的复杂判断)
????else
????{
?????// 恢复状态, 试落下一子, 看能否提别人的子
?????board.stones[row, col] = Board.Empty;
?????board.MakeMove(color, row, col);
?????if (board.LastKillCount > 0)
??????return true;
?????else
?????{
??????// 必须使用下面这一句把它恢复到空状态, 不加则会出错, 不知道为什么??
??????this.stones[row, col] = Board.Empty;
??????return false;
?????}
????}????
???}???
??}

??// 走一步, 并提去死子
??public void MakeMove(int color, int row, int col)
??{???
???this.stones[row, col] = color;

???ArrayList stonesDead = new ArrayList();??// 死子集合
???ArrayList stonesVisited = new ArrayList();?// 访问过的点的集合

???// 开始判断并提去死子
???int newx, newy;
???for (int i = 0; i < 4; i++)
???{
????newx = row + offsets[i, 0];
????newy = col + offsets[i, 1];????

????if (newx >= 0 && newx < 19 && newy >= 0 && newy < 19)
????{
?????if (this.stones[newx, newy] == (- color))
?????{
??????// 如果目前位置已经在前面某个方向的探索过程中找到, 则不用判断了。
??????// 因为不同方向的棋子可能是属于同一个串的
??????if (! stonesVisited.Contains(new Point(newx, newy)))
??????{
???????// 寻找包含该位置的串
???????ArrayList chuan = this.FindChuan(newx, newy);
???????// 算串的气
???????int chuanGas = this.CountChuanGas(chuan);
???????// 加到已访问的列表
???????stonesVisited.AddRange(chuan);

???????if (chuanGas == 0)
???????{
????????stonesDead.AddRange(chuan);
???????}
??????}
?????}
????}
???}

???// 提掉死子
???for (int i = 1; i <= stonesDead.Count; i++)
???{
????Point p = (Point) stonesDead[i - 1];
????this.stones[p.X, p.Y] = Board.Empty;
???}

???// 更新提子数
???this.LastKillCount = stonesDead.Count;
??}

??// 算气
??public int CountGas(int row, int col)
??{
???int gas = 0;
???int newx, newy;
???for (int i = 0; i < 4; i++)
???{
????newx = row + this.offsets[i, 0];
????newy = col + this.offsets[i, 1];

????if (newx >= 0 && newx < 19 && newy >= 0 && newy < 19)
????{
?????if (this.stones[newx, newy] == Board.Empty)
??????gas++;
????}
???}
???return gas;
??}


??///


??/// 棋子串搜索
??/// 寻找包含该位置的棋子串
??///

??/// <备注>
??///??广度优先的遍历算法
??///
??/// 起始点的 X 坐标
??/// 起始点的 Y 坐标
??/// 搜索到的棋子串(没找到则返回 null)?
??public ArrayList FindChuan(int row, int col)
??{
???ArrayList chuan = null;??????
???int color = this.stones[row, col];?// 当前的颜色

???if (this.stones[row, col] == color)
???{
????chuan = new ArrayList();
????// 加入当前点
????chuan.Add(new Point(row, col));
????// 定义两个游标
????int begin = 0;
????int end = 0;
????
????int findCount;?// 发现的邻居数目, 用于循环结束的判断条件
????do
????{
?????findCount = 0;
?????// begin 到 end 之间的一些点表示没有探索过四周的那些点
?????for (int i = begin; i <= end; i++)
?????{
??????// 对左右上下四个方向进行探索
??????for (int j = 0; j < 4; j++)
??????{
???????int newx = ((Point) chuan[i]).X + offsets[j, 0];
???????int newy = ((Point) chuan[i]).Y + offsets[j, 1];
???????
???????// 如果该点在棋盘内, 且颜色相同, 且现有的串中没有, 则加入串
???????if (newx >= 0 && newx < 19 && newy >= 0 && newy < 19
????????&& this.stones[newx, newy] == color
????????&& ! chuan.Contains(new Point(newx, newy)))
???????{
????????chuan.Add(new Point(newx, newy));
????????// 寻找到的邻居计数器加 1
????????findCount += 1;
???????}
??????}
?????}
?????// 设定下一个循环要列举的开始和结束游标
?????begin = end + 1;
?????end = end + findCount;
????}
????// 如果本轮搜索的所有点都没有邻居了, 也就表示串搜索结束了, 跳出循环
????while (findCount > 0);
???}

???// 测试: 返回搜到的字串中棋子数目
???// return chuan.Count;

???return chuan;??
??}

??// 算串的气
??public int CountChuanGas(ArrayList chuan)
??{
???if (chuan == null)
????return 0;
???int gas = 0;
???for (int i = 0; i < chuan.Count; i++)
???{
????gas += this.CountGas(((Point) chuan[i]).X, ((Point) chuan[i]).Y);
???}
???return gas;
??}
?}
}

0 0

相关博文

我的热门文章

img
取 消
img