zoukankan      html  css  js  c++  java
  • 用 Silverlight 开发围棋在线对弈程序(一)UI 雏形

    Silverlight 开发围棋在线对弈程序

    作者: Neil Chen

    第一部分:UI雏形

    首先,介绍下围棋的简单规则:黑白双方交替落子,以占据棋盘上交叉点多者为胜。同时,双方为了争夺地盘,可能会发生“对杀”。一个棋子周围接触的空白交叉点数目叫做“气”,如果一个或多个棋子周围的气都被对方封死,气数=0,则这些棋子就称为死棋,需要从棋盘上移去。

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

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

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

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

    Aim small, miss small.

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

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

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

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

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

    Page.xaml:

    <UserControl

           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">

           <Grid

                  x:Name="LayoutRoot"

                  Background="White">

                  <Grid.ColumnDefinitions>

                         <ColumnDefinition

                                Width="0.75*" />

                         <ColumnDefinition

                                Width="0.25*" />

                  </Grid.ColumnDefinitions>

                  <!-- 棋盘区域 -->

                  <Border

                         Grid.Column="0">

                         <!-- 棋盘 -->

                         <Canvas

                                x:Name="canvasBoard"

                                Background="LightYellow"

                                Margin="10">

                         </Canvas>

                  </Border>

                  <!-- 操作区域 -->

                  <Border

                         Grid.Column="1">

                         <StackPanel

                                Margin="20"

                                Orientation="Vertical">

                               <Button

                                      x:Name="btnGo"

                                      Content="Go" />

                         </StackPanel>

                  </Border>

           </Grid>

    </UserControl>

     

    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);

     

                  }

           }

    }

     

    运行一下看看效果如何:
    ui1.png

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

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

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

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

                               <CheckBox

                                      x:Name="chkShowAxisLabels"

                                      Content="Show Axis Labels"

                                      Margin="0,10,0,0"

                                      IsChecked="true" />

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

    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<TextBlock> yAxisLabels = new List<TextBlock>(20);

                  private readonly List<TextBlock> xAxisLabels = new List<TextBlock>(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

           }

    }

     

    [第二部分:MVC]

  • 相关阅读:
    【笔记】网易微专业-Web安全工程师-04.WEB安全实战-7.SQL回显注入
    【笔记】网易微专业-Web安全工程师-04.WEB安全实战-6.文件上传
    【笔记】网易微专业-Web安全工程师-04.WEB安全实战-5.文件包含
    【笔记】网易微专业-Web安全工程师-04.WEB安全实战-4.CSRF
    zoom和transform:scale的区别
    图片上黑色透明遮罩的实现
    如何实现两行文本增多显示省略号
    H5如何实现一行三列布局
    H5瀑布流如何实现
    H5一行显示两个正方形
  • 原文地址:https://www.cnblogs.com/RChen/p/1425636.html
Copyright © 2011-2022 走看看