zoukankan      html  css  js  c++  java
  • x01.Weiqi.1 提子算法

    吃饭是为了活着,而活着不是为了吃饭。人生的意义,在于与神对话。有人跳舞,有人卖油,有人杀牛。而我,选择了编程。编程,当然要研究人工智能。人工智能的切入点,是棋类游戏。据说,五子棋算得尽,围棋算不尽。那么,就从算不尽开始吧。

    使用 Griphics画线和圆,悔棋时闪烁不已。Dispose!

    使用 19 * 19 的 UniformGrid填以 361 个 Tile,两步就不堪重负。Dispose!

    最终,采用了用户控件。先建立一个 WPF 应用项目,添加两个 UserControl,分别取名为 Chess 和 Board,将 Chess.xaml 中的 Grid 改为 <Ellipse  Name=”m_Ellipse” />,Board.xaml 中的Grid 改为 <Canvas  Name=”m_Canvas” />。

    进入 Chess.xaml.cs 代码文件,修改如下:

    Chess
    namespace x01.Weiqi
    {
    publicpartialclass Chess : UserControl
    {
    public Chess(Brush fillBrush, int size =38)
    {
    InitializeComponent();
    m_Ellipse.Fill
    = fillBrush;
    m_Ellipse.Width
    = m_Ellipse.Height = size;
    }
    }
    }

    进入 Board.xaml.cs 代码文件, 修改如下:

    namespace x01.Weiqi

    {

        public partial class Board : UserControl

        {

    Ready
    // 为灵活调整而设
    publicint ChessSize{get;set;}

    bool m_IsBlack =false;
    Pos m_NotInPos
    =new Pos(-1, -1);
    Step[,] m_Steps
    =new Step[19, 19];
    int m_Count =0;
    List
    <Pos> m_DeadPos =new List<Pos>();
    List
    <DeadStep> m_DeadSteps =new List<DeadStep>();

    struct DeadStep
    {
    publicint Count;
    public ChessColor Color;

    // key 为死子 Count,value 为死子 Column,Row
    public Dictionary<int, Pos> DeadInfo;
    }

    // 本欲用 Point,但 double 类型不方便
    struct Pos
    {
    publicint X;
    publicint Y;

    public Pos(int x, int y)
    {
    X
    = x;
    Y
    = y;
    }
    }

    enum ChessColor
    {
    Black, White, Empty
    }

    // 每一步的棋子信息
    struct Step
    {
    public Chess Chess;
    public ChessColor Color;
    publicbool IsDead;
    publicint Count;
    publicint Column;
    publicint Row;
    }

    public Board(int size =38)
    {
    InitializeComponent();

    ChessSize
    = size;
    Init();
    }

    void Init()
    {
    Width
    = Height = ChessSize *19;
    Background
    =new SolidColorBrush(Color.FromArgb(0x5e, 0xef, 0xdf, 0x56));

    for (int i =0; i <19; i++)
    {
    for (int j =0; j <19; j++)
    {
    m_Steps[i, j].Chess
    =null;
    m_Steps[i, j].Color
    = ChessColor.Empty;
    m_Steps[i, j].IsDead
    =false;
    m_Steps[i, j].Count
    =-1;
    m_Steps[i, j].Row
    =-1;
    m_Steps[i, j].Column
    =-1;
    }
    }

    // 画线
    for (int i =0; i <19; i++)
    {
    Line l
    =new Line();
    l.Stroke
    = Brushes.Black;
    int y = i * ChessSize + ChessSize /2;
    l.X1
    = ChessSize /2;
    l.Y1
    = y;
    l.X2
    =19* ChessSize - ChessSize /2;
    l.Y2
    = y;
    m_Canvas.Children.Add(l);

    l
    =new Line();
    l.Stroke
    = Brushes.Black;
    int x = i * ChessSize + ChessSize /2;
    l.X1
    = x;
    l.Y1
    = ChessSize /2;
    l.X2
    = x;
    l.Y2
    =19* ChessSize - ChessSize /2;
    m_Canvas.Children.Add(l);
    }

    // 画星
    for (int j =0; j <3; j++)
    for (int i =0; i <3; i++)
    {
    Ellipse e
    =new Ellipse();
    e.Fill
    = Brushes.Black;
    e.Width
    =8;
    e.Height
    =8;
    double left =4* ChessSize - ChessSize /2+ j *6* ChessSize;
    double top =4* ChessSize - ChessSize /2+ i *6* ChessSize;
    Canvas.SetLeft(e, left
    -4);
    Canvas.SetTop(e, top
    -4);
    m_Canvas.Children.Add(e);
    }
    }

     

    BackOne
    protectedoverridevoid OnMouseRightButtonDown(MouseButtonEventArgs e)
    {
    base.OnMouseRightButtonDown(e);

    BackOne();
    }

    privatevoid BackOne()
    {
    if (m_Count ==0)
    {
    return;
    }

    int count = m_Count--;
    int index =-1;

    foreach (var dead in m_DeadSteps)
    {
    if (dead.Count == count)
    {
    index
    = m_DeadSteps.Count -1;
    Brush brush;
    if (dead.Color == ChessColor.Black)
    {
    brush
    = Brushes.Black;
    }
    else
    {
    brush
    = Brushes.White;
    }

    foreach (var info in dead.DeadInfo)
    {
    int col = info.Value.X;
    int row = info.Value.Y;

    Ellipse e
    =new Ellipse();
    e.Fill
    = brush;
    e.Width
    = e.Height = ChessSize;
    m_Steps[col, row].Chess.Content
    = e;
    m_Steps[col, row].Color
    = dead.Color;
    m_Steps[col, row].Count
    = info.Key;
    m_Steps[col, row].Column
    = col;
    m_Steps[col, row].Row
    = row;
    }
    }
    }

    if (index !=-1)
    {
    m_DeadSteps.RemoveAt(index);
    }

    foreach (var item in m_Steps)
    {
    if (item.Chess !=null&& item.Count == count)
    {
    int col = item.Column;
    int row = item.Row;
    m_Steps[col, row].Chess.Content
    =null;
    m_Steps[col, row].Count
    =-1;
    m_Steps[col, row].Color
    = ChessColor.Empty;
    m_Steps[col, row].Row
    =-1;
    m_Steps[col, row].Column
    =-1;
    m_IsBlack
    =!m_IsBlack;
    }
    }
    }

     

    Eat
    protectedoverridevoid OnMouseLeftButtonDown(MouseButtonEventArgs e)
    {
    base.OnMouseLeftButtonDown(e);

    int col = (int)e.GetPosition(this).X / ChessSize;
    int row = (int)e.GetPosition(this).Y / ChessSize;

    if (m_Steps[col, row].Color != ChessColor.Empty)
    {
    return;
    }

    if (m_NotInPos.X == col && m_NotInPos.Y == row)
    {
    return;
    }
    else
    {
    m_NotInPos.X
    =-1;
    m_NotInPos.Y
    =-1;
    }

    DrawChess(col, row);

    if (!EatOther(col, row))
    {
    if (EatSelf(col, row))
    {
    // 自杀一子为禁入
    if (m_DeadPos.Count ==1)
    {
    BackOne();
    }
    }
    }
    }

    privatevoid DrawChess(int col, int row)
    {
    int left = col * ChessSize;
    int top = row * ChessSize;

    Brush brush;
    if (m_IsBlack =!m_IsBlack)
    {
    brush
    = Brushes.Black;
    m_Steps[col, row].Color
    = ChessColor.Black;
    }
    else
    {
    brush
    = Brushes.White;
    m_Steps[col, row].Color
    = ChessColor.White;
    }

    if (m_Steps[col, row].Chess ==null)
    {
    Chess chess
    =new Chess(brush, ChessSize);
    Canvas.SetLeft(chess, left);
    Canvas.SetTop(chess, top);
    m_Canvas.Children.Add(chess);
    m_Steps[col, row].Chess
    = chess;
    }
    elseif (m_Steps[col, row].Chess.Content ==null)
    {
    Ellipse e
    =new Ellipse();
    e.Fill
    = brush;
    e.Width
    = e.Height = ChessSize;
    m_Steps[col, row].Chess.Content
    = e;
    }
    else
    {
    thrownew Exception(string.Format("Cannot Draw Chess at: col = {0}, row = {1}.", col, row));
    }

    m_Steps[col, row].Count
    =++m_Count;
    m_Steps[col, row].Column
    = col;
    m_Steps[col, row].Row
    = row;
    }

    privatebool EatOther(int col, int row)
    {
    // 上、下、左、右各吃一通。
    bool ok1 =false;
    if (col !=0&& m_Steps[col, row].Color != m_Steps[col -1, row].Color)
    {
    ok1
    = EatSelf(col -1, row);
    }
    bool ok2 =false;
    if (col !=18&& m_Steps[col, row].Color != m_Steps[col +1, row].Color)
    {
    ok2
    = EatSelf(col +1, row);
    }
    bool ok3 =false;
    if (row !=0&& m_Steps[col, row].Color != m_Steps[col, row -1].Color)
    {
    ok3
    = EatSelf(col, row -1);
    }
    bool ok4 =false;
    if (row !=18&& m_Steps[col, row].Color != m_Steps[col, row +1].Color)
    {
    ok4
    = EatSelf(col, row +1);
    }

    return ok1 || ok2 || ok3 || ok4;
    }

    privatebool EatSelf(int col, int row)
    {
    ClearForEat();
    if (CanEat(col, row, m_Steps[col, row].Color))
    {
    DeadStep deadStep;
    deadStep.Count
    = m_Count;
    deadStep.Color
    = m_Steps[col, row].Color;
    deadStep.DeadInfo
    =new Dictionary<int, Pos>();
    if (m_DeadPos.Count ==1)
    {
    Pos pos;
    pos.X
    = m_DeadPos[0].X;
    pos.Y
    = m_DeadPos[0].Y;

    m_NotInPos.X
    = pos.X;
    m_NotInPos.Y
    = pos.Y;

    foreach (var item in m_Steps)
    {
    // 变色而已,m_Count 为上一步
    if (item.Count == m_Count)
    {
    ClearForEat();
    if (CanEat(pos.X, pos.Y, item.Color))
    {
    // 因有一子变色,故减一。实际 Count 至少为 3
    if (m_DeadPos.Count -1>0)
    {
    m_NotInPos.X
    =-1;
    m_NotInPos.Y
    =-1;
    }
    }
    }
    }

    deadStep.DeadInfo.Add(m_Steps[pos.X, pos.Y].Count,
    new Pos(pos.X, pos.Y));

    m_Steps[pos.X, pos.Y].Color
    = ChessColor.Empty;
    m_Steps[pos.X, pos.Y].Chess.Content
    =null;
    }
    else
    {
    foreach (var item in m_DeadPos)
    {
    deadStep.DeadInfo.Add(m_Steps[item.X, item.Y].Count,
    new Pos(item.X, item.Y));

    m_Steps[item.X, item.Y].Color
    = ChessColor.Empty;
    m_Steps[item.X, item.Y].Chess.Content
    =null;
    }
    }
    m_DeadSteps.Add(deadStep);

    returntrue;
    }

    returnfalse;
    }

    void ClearForEat()
    {
    foreach (var item in m_DeadPos)
    {
    m_Steps[item.X, item.Y].IsDead
    =false;
    }
    m_DeadPos.Clear();
    }

    bool CanEat(int col, int row, ChessColor currentColor)
    {
    if (m_Steps[col, row].Color == ChessColor.Empty)
    {
    returnfalse;
    }

    m_DeadPos.Add(
    new Pos(col, row));
    m_Steps[col, row].IsDead
    =true;

    // 边界问题,头疼问题。笨人笨法,分别处理之
    return CanEatLeft(col, row, currentColor) && CanEatRight(col, row, currentColor)
    && CanEatUp(col, row, currentColor) && CanEatDown(col, row, currentColor);
    }

    bool CanEatLeft(int col, int row, ChessColor currentColor)
    {
    if (col !=0)
    {
    if (m_Steps[col -1, row].Color == ChessColor.Empty)
    {
    returnfalse;
    }
    elseif (m_Steps[col -1, row].Color == currentColor && m_Steps[col -1, row].IsDead ==false)
    {
    m_DeadPos.Add(
    new Pos(col -1, row));
    m_Steps[col
    -1, row].IsDead =true;
    if (!CanEatUp(col -1, row, currentColor))
    {
    returnfalse;
    }
    if (!CanEatDown(col -1, row, currentColor))
    {
    returnfalse;
    }
    if (!CanEatLeft(col -1, row, currentColor))
    {
    returnfalse;
    }
    }
    }

    returntrue;
    }

    bool CanEatRight(int col, int row, ChessColor currentColor)
    {
    if (col !=18)
    {
    if (m_Steps[col +1, row].Color == ChessColor.Empty)
    {
    returnfalse;
    }
    elseif (m_Steps[col +1, row].Color == currentColor && m_Steps[col +1, row].IsDead ==false)
    {
    m_DeadPos.Add(
    new Pos(col +1, row));
    m_Steps[col
    +1, row].IsDead =true;
    if (!CanEatUp(col +1, row, currentColor))
    {
    returnfalse;
    }
    if (!CanEatDown(col +1, row, currentColor))
    {
    returnfalse;
    }
    if (!CanEatRight(col +1, row, currentColor))
    {
    returnfalse;
    }
    }
    }

    returntrue;
    }

    bool CanEatUp(int col, int row, ChessColor currentColor)
    {
    if (row !=0)
    {
    if (m_Steps[col, row -1].Color == ChessColor.Empty)
    {
    returnfalse;
    }
    elseif (m_Steps[col, row -1].Color == currentColor && m_Steps[col, row -1].IsDead ==false)
    {
    m_DeadPos.Add(
    new Pos(col, row -1));
    m_Steps[col, row
    -1].IsDead =true;
    if (!CanEatLeft(col, row -1, currentColor))
    {
    returnfalse;
    }
    if (!CanEatRight(col, row -1, currentColor))
    {
    returnfalse;
    }
    if (!CanEatUp(col, row -1, currentColor))
    {
    returnfalse;
    }
    }
    }

    returntrue;
    }

    bool CanEatDown(int col, int row, ChessColor currentColor)
    {
    if (row !=18)
    {
    if (m_Steps[col, row +1].Color == ChessColor.Empty)
    {
    returnfalse;
    }
    elseif (m_Steps[col, row +1].Color == currentColor && m_Steps[col, row +1].IsDead ==false)
    {
    m_DeadPos.Add(
    new Pos(col, row +1));
    m_Steps[col, row
    +1].IsDead =true;
    if (!CanEatLeft(col, row +1, currentColor))
    {
    returnfalse;
    }
    if (!CanEatRight(col, row +1, currentColor))
    {
    returnfalse;
    }
    if (!CanEatDown(col, row +1, currentColor))
    {
    returnfalse;
    }
    }
    }

    returntrue;
    }

        }

    }

    编译生成后,将工具栏上的 Board 控件拖入主窗口即可。

    Board 图示如下:

                        

    首先吃对方 EatOther,吃对方又可转化为吃自己 EatSelf, 吃自己的关键在于 CanEat, CanEat 的实现,采用分而治之的方针: CanEatUp, CanEatDown, CanEatLeft, CanEatRight。上下左右,各吃一通!

     

                   句三年得,

                   一吟泪双流。

                   知音如不赏,

                   归卧故山秋。

     

    代码可从 http://www.cnblogs.com/china_x01 的 Download/Code/x01.Weiqi 获取。

    效果图如下:

                  

    Copyright (c) 2011 by x01 (china_x01@qq.com),未经本人许可,请勿擅自转载。

     

  • 相关阅读:
    iPad开发学习之一环境搭建和基本概念
    介绍一款网页布局设计的工具Balsamiq Mockups
    JS怎么判断是哪个元素触发了点击事件?
    古希腊神话剧本
    WPS知识点
    PPT动画中点击、之前、之后的区别
    JS给网页中的选项添加标点
    调音师、调灯师
    输入密码后,可以修改指定列,其余信息不允许修改
    HiveQL详解
  • 原文地址:https://www.cnblogs.com/china_x01/p/2041088.html
Copyright © 2011-2022 走看看