用Silverlight开发围棋在线对弈程序(一)UI 雏形 -电脑资料

时间:2013-08-03 05:15:45
染雾
分享
WORD下载 PDF下载 投诉

首先,介绍下围棋的简单规则:黑白双方交替落子,以占据棋盘上交叉点多者为胜,

用Silverlight开发围棋在线对弈程序(一)UI 雏形

。同时,双方为了 争夺地盘,可能会发生“对杀”。一个棋子周围接触的空白交叉点数目叫做“气”,如果一个或多个棋子 周围的气都被对方封死,气数=0,则这些棋子就称为死棋,需要从棋盘上移去。

一个围棋棋谱大致如下图所示(截图自Tom围棋网站):

图片看不清楚?请点击这里查看原图(大图)。

在上图中,棋子上的数字一般在棋谱中显示,用于帮助了解棋局进行的次序。

下面我们来尝试用 Silverlight 2.0 开发一个围棋在线对弈程序。

首先,我们来创建围棋程序的 UI 部分。毕竟,这是最直观的东西。而且我喜欢边做边重构的开发方 式,这样,不至于因为花了过多的时间做设计,而减慢了实际开发的进度。让我们先从一个小小的原型起 步,然后不断的应用设计思维去改进它,最终达到目标。正如一部电影里的台词所说的:

Aim small, miss small.

好了,现在大概分析一下:

1.我们打算在界面的左侧显示棋盘,而右侧是功能区域。

2.棋盘是由19道横线,19道竖线,以及9个星位的标志组成的。为了方便查找棋盘上的位置,我们在棋 盘的四周可能需要加上坐标。目前我们先只在左侧和上方加上坐标。右边和下面的位置留在那里。

对于棋盘的显示,我们打算用一个 Canvas 来实现。而其中的线条,圆点,棋子等视觉元素,只需往 其中添加相应的 Line, Ellipse, Label 即可。

我们假定整个程序的大小为 800 * 600 (以后也许再考虑是否有必要支持任意比例的缩放)。现在, 跟随直觉,我写了下面一些代码用于构建 UI:

Page.xaml:

       x:Class="WoodFoxWeiQi.UI.Page"
       xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
       xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
       Width="800"
       Height="600">
                     x:Name="LayoutRoot"
              Background="White">
             
                                                 Width="0.75*" />
                                                 Width="0.25*" />
             

             
                                   Grid.Column="0">
                    
                                                 x:Name="canvasBoard"
                            Background="LightYellow"
                            Margin="10">
                    
             
             
                                   Grid.Column="1">
                                                 Margin="20"
                            rientation="Vertical">
                                                             x:Name="btnGo"
                                  Content="Go" />
                    
             
      

Page.xaml.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
namespace WoodFoxWeiQi.UI
{
       public partial class Page : UserControl
       {
              public Page()
              {
                     InitializeComponent();
                     canvasBoard.MouseLeftButtonDown += new MouseButtonEventHandler(canvasBoard_MouseLeftButtonDown);
                     canvasBoard.SizeChanged += new SizeChangedEventHandler(canvasBoard_SizeChanged);
                     btnGo.Click += new RoutedEventHandler (btnGo_Click);
              }
              // 因为 Canvas 的尺寸是根据父控件的尺寸在运行时计算得到的,所以需 要在 SizeChanged 方法里
              // 才能获得其实际尺寸
              void canvasBoard_SizeChanged(object sender, SizeChangedEventArgs e)
              {
                     canvasBoard.Children.Clear();
                     CreateBoardElements();
              }
              double boardSize;    // 棋盘宽度(不包含坐标)
              double cellSize;     // 网格宽度
              double starSize;     // 星位的小圆点的直径
              double stoneSize;    // 棋子直径
              // 创建棋盘上的网格线,星位,坐标等显示元素
              private void CreateBoardElements()
              {
                     // 确保使用一个正方形区域作为棋盘显示区域
                     boardSize = Math.Min(canvasBoard.ActualHeight, canvasBoard.ActualWidth);
                     // 根据棋盘尺寸计算出相应的其他尺寸
                     cellSize = boardSize / 20;
                     starSize = cellSize / 4;
                     stoneSize = cellSize * 0.8;
                     for (int i = 1; i <= 19; i++)
                     {
                           // 添加水平网格线
                           var lineHorizontal = new Line();
                           lineHorizontal.X1 = cellSize;
                           lineHorizontal.X2 = cellSize * 19;
                            lineHorizontal.Y1 = lineHorizontal.Y2 = cellSize * i;
                           lineHorizontal.Stroke = new SolidColorBrush(Colors.Black);
                           lineHorizontal.StrokeThickness = 1.0;
                           canvasBoard.Children.Add (lineHorizontal);
                           // 添加垂直网格线
                           var lineVertical = new Line();
                           lineVertical.Y1 = cellSize;
                           lineVertical.Y2 = cellSize * 19;
                           lineVertical.X1 = lineVertical.X2 = cellSize * i;
                           lineVertical.Stroke = new SolidColorBrush(Colors.Black);
                           lineVertical.StrokeThickness = 1.0;
                           canvasBoard.Children.Add (lineVertical);
                     }
                     // 添加9个星位的标志
                     for (int i = 4; i <= 16; i += 6)
                     {
                           for (int j = 4; j <= 16; j += 6)
                           {
                                  double x = i * cellSize - starSize / 2;
                                  double y = j * cellSize - starSize / 2;
                                  Ellipse ellipseStar = new Ellipse();
                                  ellipseStar.Stroke = new SolidColorBrush(Colors.Black);
                                  ellipseStar.Fill = new SolidColorBrush(Colors.Black);
                                  ellipseStar.Width = ellipseStar.Height = starSize;
                                  ellipseStar.SetValue (Canvas.LeftProperty, x);
                                  ellipseStar.SetValue (Canvas.TopProperty, y);
                                  canvasBoard.Children.Add (ellipseStar);
                           }
                     }
                     // 画横坐标
                     for (int i = 1; i <= 19; i++)
                     {
                           var txtLabel = new TextBlock();
                           txtLabel.FontSize = 11.0;
                           txtLabel.FontWeight = FontWeights.Thin;
                           txtLabel.Text = i.ToString();
                          txtLabel.

SetValue(Canvas.LeftProperty, i * cellSize - txtLabel.ActualWidth / 2);
                          txtLabel.SetValue(Canvas.TopProperty, cellSize / 2 - txtLabel.ActualHeight / 2);
                           txtLabel.Text = i.ToString();
                           canvasBoard.Children.Add(txtLabel);
                     }
                     // 画纵坐标
                     char c = 'A';
                     for (int i = 1; i <= 19; i++)
                     {
                           var txtLabel = new TextBlock();
                           txtLabel.FontSize = 11.0;
                           txtLabel.FontWeight = FontWeights.Thin;
                           txtLabel.Text = i.ToString();
                          txtLabel.SetValue(Canvas.LeftProperty, cellSize / 2 - txtLabel.ActualWidth / 2);
                          txtLabel.SetValue(Canvas.TopProperty, i * cellSize - txtLabel.ActualHeight / 2);
                           txtLabel.Text = (c++).ToString();
                           canvasBoard.Children.Add(txtLabel);
                     }
              }
              void canvasBoard_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
              {
                     var pos = e.GetPosition(canvasBoard);
                     MessageBox.Show("Clicked on board, X: " + pos.X + ", Y: " + pos.Y);
              }
              private void btnGo_Click(object sender, RoutedEventArgs e)
              {
                     // 放置一个测试的棋子(白子)
                     Ellipse e1 = new Ellipse();
                     e1.Stroke = new SolidColorBrush(Colors.Black);
                     e1.Fill = new SolidColorBrush(Colors.White);
                     e1.Width = e1.Height = stoneSize;
                     double x = 17 * cellSize - stoneSize / 2;
                     double y = 4 * cellSize - stoneSize / 2;
                     e1.SetValue(Canvas.LeftProperty, x);
                     e1.SetValue(Canvas.TopProperty, y);
                     canvasBoard.Children.Add(e1);
                     // 再放一个黑子,带手数显示的
                     Ellipse e2 = new Ellipse();
                     e2.Stroke = new SolidColorBrush(Colors.Black);
                     e2.Fill = new SolidColorBrush(Colors.Black);
                     e2.Width = e2.Height = stoneSize;
                     double x2 = 16 * cellSize - stoneSize / 2;
                     double y2 = 4 * cellSize - stoneSize / 2;
                     e2.SetValue(Canvas.LeftProperty, x2);
                     e2.SetValue(Canvas.TopProperty, y2);
                     canvasBoard.Children.Add(e2);
                     // 绘制手数显示的 Label
                     TextBlock lbl2 = new TextBlock();
                     lbl2.FontSize = 10.0;
                     lbl2.FontWeight = FontWeights.Thin;
                     lbl2.Text = "203";
                     lbl2.Foreground = new SolidColorBrush (Colors.White);
                     lbl2.SetValue(Canvas.LeftProperty, 16 * cellSize - lbl2.ActualWidth / 2);
                     lbl2.SetValue(Canvas.TopProperty, 4 * cellSize - lbl2.ActualHeight / 2);
                     canvasBoard.Children.Add(lbl2);
              }
       }
}

运行一下看看效果如何:

图片看不清楚?请点击这里查看原图(大图),

电脑资料

《用Silverlight开发围棋在线对弈程序(一)UI 雏形》()。

看起来不赖。在这个界面中,如果点击 ”Go” 按钮,则会在棋盘上摆放两个测试用的棋子,其中黑 棋上还标有表示棋步的数字。但是,我们的目标是要做一个能下棋的程序,因此,我们下面要加一些控制 代码,比如,在用户点击某个位置的时候,落下棋子(如果该位置是允许落子的),以及控制棋局的开始 、结束、认输等操作的按钮以及相关动作处理逻辑。

不过,在开始之前,有必要重构一下上面的 UI 代码,因为它看起来比较乱,一个方法里包含了太多 的代码,如果这样继续下去的话,程序很快会变成一堆乱麻而难以为继。

由于很多对象的创建过程是类似的,因此我们可以将它提取到独立的方法中加以重用。另外,因为我 们需要能够控制某些界面元素的显示/隐藏(比如坐标),将这些对象保存到当前窗体的字段里是一个不 错的主意。

我们还添加了一个 CheckBox,用来控制坐标的显示和隐藏。Xaml 中添加的代码如下:

x:Name="chkShowAxisLabels"
Content="Show Axis Labels"
Margin="0,10,0,0"
IsChecked="true" />

重构后的代码 Page.xaml.cs (每个方法代码大概5~10行左右):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
namespace WoodFoxWeiQi.UI
{
       public partial class Page : UserControl
       {
              public Page()
              {
                     InitializeComponent();
                     canvasBoard.MouseLeftButtonDown += canvasBoard_MouseLeftButtonDown;
                     canvasBoard.SizeChanged += canvasBoard_SizeChanged;
                     btnGo.Click += btnGo_Click;
                     chkShowAxisLabels.Checked += chkShowAxisLabels_Checked;
                     chkShowAxisLabels.Unchecked += chkShowAxisLabels_Checked;
              }
              #region Fields
              private readonly Brush brush_White = new SolidColorBrush (Colors.White);
              private readonly Brush brush_Black = new SolidColorBrush (Colors.Black);
              private readonly List yAxisLabels = new List(20);
              private readonly List xAxisLabels = new List(20);
              double boardSize;    // 棋盘宽度(不包含坐标)
              double cellSize;     // 网格宽度
              double starSize;     // 星位的小圆点的直径
              double stoneSize;    // 棋子直径
              #endregion
              // 因为 Canvas 的尺寸是根据父控件的尺寸在运行时计算得到的,所以需 要在 SizeChanged 方法里
              // 才能获得其实际尺寸
              void canvasBoard_SizeChanged(object sender, SizeChangedEventArgs e)
              {
                     canvasBoard.Children.Clear();
                     CreateBoardElements();
              }
              void canvasBoard_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
              {
                     var pos = e.GetPosition(canvasBoard);
                     MessageBox.Show("Clicked on board, X: " + pos.X + ", Y: " + pos.Y);
              }
              void btnGo_Click(object sender, RoutedEventArgs e)
              {
                     // 放置一个测试的棋子(白子)
                    var e1 = BuildCircle(stoneSize, 17 * cellSize, 4 * cellSize, brush_Black, brush_White);
                     // 再放一个黑子,带手数显示的
                    var e2 = BuildCircle(stoneSize, 16 * cellSize, 4 * cellSize, brush_Black, brush_Black);
                     // 绘制手数显示的 Label
                     var lbl2 = BuildLabel("203", brush_White, 10.0, 16 * cellSize, 4 * cellSize);
              }
              // 显示或隐藏坐标轴
              void chkShowAxisLabels_Checked(object sender, RoutedEventArgs e)
              {
                     var show = chkShowAxisLabels.IsChecked.HasValue && chkShowAxisLabels.IsChecked.Value;
                     foreach (var label in xAxisLabels.Union (yAxisLabels))
                     {
                           label.Visibility = show ? Visibility.Visible : Visibility.Collapsed;
                     }
              }
              #region Builder methods for children elements
              // 创建棋盘上的网格线,星位,坐标等显示元素
              void CreateBoardElements()
              {
                     CalculateSizes();
                     BuildGridLines();
                     BuildStarPointMarks();
                     BuildXAxisLabels();
                     BuildYAxisLabels();
              }
              // 计算必要的一些尺寸定义值
              void CalculateSizes()
              {
                     // 确保使用一个正方形区域作为棋盘显示区域
                     boardSize = Math.Min(canvasBoard.ActualHeight, canvasBoard.ActualWidth);
                     // 根据棋盘尺寸计算出相应的其他尺寸
                     cellSize = boardSize / 20;
                     starSize = cellSize / 4;
                     stoneSize = cellSize * 0.8;
              }
              // 添加网格线
              void BuildGridLines()
              {
                     for (var i = 1; i <= 19; i++)
                     {
                           // 添加水平网格线
                           BuildLine(cellSize, cellSize * i, cellSize * 19, cellSize * i);
                           // 添加垂直网格线
                           BuildLine(cellSize * i, cellSize, cellSize * i, cellSize * 19);
                     }
              }
              // 添加9个星位的标志
              void BuildStarPointMarks()
              {
                     for (var i = 4; i <= 16; i += 6)
                     {
                           for (var j = 4; j <= 16; j += 6)
                           {
                                  BuildCircle(starSize, i * cellSize, j * cellSize, brush_Black, brush_Black);
                           }
                     }
              }
              // 画横坐标
              void BuildXAxisLabels()
              {
                     for (var i = 1; i <= 19; i++)
                     {
                           var lbl = BuildLabel(i.ToString(), brush_Black, 11.0, i * cellSize, cellSize / 2);
                           xAxisLabels.Add(lbl);
                     }
              }
              // 画纵坐标
              void BuildYAxisLabels()
              {
                     var c = 'A';
                     for (var i = 1; i <= 19; i++)
                     {
                           var text = (c++).ToString();
                           var lbl = BuildLabel(text, brush_Black, 11.0, cellSize / 2, i * cellSize);
                           yAxisLabels.Add(lbl);
                     }
              }
              #endregion
              #region Basic builder methods
              Line BuildLine(double x1, double y1, double x2, double y2)
              {
                     var line = new Line {
                           X1 = x1,
                           X2 = x2,
                           Y1 = y1,
                           Y2 = y2,
                           Stroke = brush_Black,
                           StrokeThickness = 1.0
                     };
                     canvasBoard.Children.Add(line);
                     return line;
              }
             Ellipse BuildCircle(double diameter, double centerX, double centerY, Brush stroke, Brush fill)
              {
                     var ellipse = new Ellipse { Stroke = stroke, Fill = fill };
                     ellipse.Width = ellipse.Height = diameter;
                     ellipse.SetValue(Canvas.LeftProperty, centerX - diameter / 2);
                     ellipse.SetValue(Canvas.TopProperty, centerY - diameter / 2);
                     canvasBoard.Children.Add(ellipse);
                     return ellipse;
              }
              // 创建 Label
              TextBlock BuildLabel(string text, Brush foreground, double fontSize,
                     double centerX, double centerY)
              {
                     var lbl = new TextBlock {
                           FontSize = fontSize,
                           FontWeight = FontWeights.Thin,
                           Text = text,
                           Foreground = foreground
                     };
                     lbl.SetValue(Canvas.LeftProperty, centerX - lbl.ActualWidth / 2);
                     lbl.SetValue(Canvas.TopProperty, centerY - lbl.ActualHeight / 2);
                     canvasBoard.Children.Add(lbl);
                     return lbl;
              }
              #endregion
       }
}

用Silverlight开发围棋在线对弈程序(一)UI 雏形 -电脑资料

手机扫码分享

Top