x01.Weiqi.8: 一點改進,x01.Weiqi.8:改進
原來的代碼全部刪除,進行了深層次重構,得其意而忘其言。得意之處有二:
1.關於顯示
以 StoneSize 屬性為依托,在 set 中加了一句:Width = Height = m_StoneSize * 19;以此來控制棋盤大小。所有的對象在 Init() 方法中創建,而具體的渲染在 Redraw() 方法中完成。這種創建與重繪相分開的辦法,使調整大小時進行重繪更簡單易行。這兩個方法的代碼如下:

![]()
1 void Init()
2 {
3 // 線
4 for (int i = 0; i < 19; i++) {
5 m_LinesH[i] = new Line();
6 m_LinesH[i].Stroke = Brushes.Black;
7 m_Canvas.Children.Add(m_LinesH[i]);
8
9 m_LinesV[i] = new Line();
10 m_LinesV[i].Stroke = Brushes.Black;
11 m_Canvas.Children.Add(m_LinesV[i]);
12 }
13
14 // 星
15 for (int j = 0; j < 3; j++) {
16 for (int i = 0; i < 3; i++) {
17 m_Stars[i, j] = new Ellipse();
18 m_Stars[i, j].Fill = Brushes.Black;
19 m_Canvas.Children.Add(m_Stars[i, j]);
20 }
21 }
22
23 for (int i = 0; i < 19; i++) {
24 for (int j = 0; j < 19; j++) {
25 m_Stones[i, j] = new Ellipse();
26 m_Stones[i, j].Visibility = Visibility.Hidden;
27 m_Canvas.Children.Add(m_Stones[i, j]);
28
29 m_Numbers[i, j] = new TextBlock();
30 m_Numbers[i, j].Background = Brushes.Transparent;
31 m_Numbers[i, j].Visibility = Visibility.Hidden;
32 m_Canvas.Children.Add(m_Numbers[i, j]);
33
34 m_Steps[i, j] = new Step();
35 m_Steps[i, j].Row = i;
36 m_Steps[i, j].Col = j;
37 m_EmptySteps.Add(m_Steps[i, j]);
38 m_AllSteps.Add(m_Steps[i, j]);
39 }
40 }
41
42 // 當前標志
43 m_CurrentRect.Visibility = System.Windows.Visibility.Hidden;
44 m_CurrentRect.Fill = Brushes.Red;
45 m_Canvas.Children.Add(m_CurrentRect);
46
47 for (int i = 0; i < 19; i++) {
48 for (int j = 0; j < 19; j++) {
49 Rectangle rect = new Rectangle();
50 rect.Visibility = System.Windows.Visibility.Hidden;
51 m_EmptyRects[i, j] = rect;
52 m_Canvas.Children.Add(m_EmptyRects[i,j]);
53
54 }
55 }
56 }
Init()

![]()
1 public void Redraw()
2 {
3 // 畫線
4 for (int i = 0; i < 19; i++) {
5 Line l = m_LinesH[i];
6 int y = i * StoneSize + StoneSize / 2;
7 l.X1 = StoneSize / 2;
8 l.Y1 = y;
9 l.X2 = 19 * StoneSize - StoneSize / 2;
10 l.Y2 = y;
11
12 l = m_LinesV[i];
13 int x = i * StoneSize + StoneSize / 2;
14 l.X1 = x;
15 l.Y1 = StoneSize / 2;
16 l.X2 = x;
17 l.Y2 = 19 * StoneSize - StoneSize / 2;
18 }
19
20 // 畫星
21 for (int j = 0; j < 3; j++) {
22 for (int i = 0; i < 3; i++) {
23 Ellipse e = m_Stars[i, j];
24 e.Width = e.Height = StoneSize / 3;
25 double left = 4 * StoneSize + j * 6 * StoneSize - StoneSize / 2 - e.Width / 2;
26 double top = 4 * StoneSize + i * 6 * StoneSize - StoneSize / 2 - e.Height / 2;
27 Canvas.SetLeft(e, left);
28 Canvas.SetTop(e, top);
29 }
30 }
31
32 // Stones and Numbers
33 for (int i = 0; i < 19; i++) {
34 for (int j = 0; j < 19; j++) {
35 var stone = m_Stones[i, j];
36 stone.Width = stone.Height = StoneSize;
37 Canvas.SetLeft(stone, j * StoneSize);
38 Canvas.SetTop(stone, i * StoneSize);
39
40 ShowNumber(i, j, m_Steps[i, j].StepCount);
41 }
42 }
43
44 // 點目標志
45 if (IsShowMesh)
46 for (int i = 0; i < 19; i++) {
47 for (int j = 0; j < 19; j++) {
48 var rect = m_EmptyRects[i, j];
49 rect.Width = rect.Height = m_CurrentRect.Width;
50 double offset = (StoneSize - rect.Width) / 2.0;
51 Canvas.SetLeft(rect, j * StoneSize + offset);
52 Canvas.SetTop(rect, i * StoneSize + offset);
53 }
54 }
55 }
56
57 public bool NextOne(int row, int col)
58 {
59 if (m_Steps[row, col].StoneColor != StoneColor.Empty)
60 return false;
61 if (m_BanOnce.Row == row && m_BanOnce.Col == col) {
62 return false;
63 }
64 m_BanOnce.Row = m_BanOnce.Col = -1;
65
66 DrawStep(row, col);
67 bool isBlack;
68 if (m_Steps[row, col].StoneColor == StoneColor.Black) {
69 m_BlackSteps.Add(m_Steps[row, col]);
70 isBlack = true;
71 } else {
72 m_WhiteSteps.Add(m_Steps[row, col]);
73 isBlack = false;
74 }
75 m_EmptySteps.Remove(m_Steps[row, col]);
76
77 UpdateBlackBlocks();
78 UpdateWhiteBlocks();
79 if (isBlack) {
80 if (!UpdateDeadBlocks(m_WhiteBlocks))
81 UpdateDeadBlocks(m_BlackBlocks);
82 } else {
83 if (!UpdateDeadBlocks(m_BlackBlocks))
84 UpdateDeadBlocks(m_WhiteBlocks);
85 }
86
87 MoveCurrentRect();
88
89 m_StepCount++;
90
91 StoneColor selfColor = isBlack ? StoneColor.Black : StoneColor.White;
92 bool isKillSelf = m_DeadBlocks.ContainsKey(m_StepCount - 1)
93 && m_DeadBlocks[m_StepCount - 1].Steps.Count == 1
94 && m_DeadBlocks[m_StepCount - 1].Steps[0].StoneColor == selfColor;
95 if (isKillSelf) {
96 m_DeadBlocks.Remove(m_StepCount - 1);
97 BackOne();
98 return false;
99 }
100
101 return true;
102 }
Redraw()
2.關於提子
以 LinkSteps()方法為依托,提子不再是上下左右一通亂吃了,而是采用集合的辦法,只需看看一塊棋有沒有氣即可。其代碼如下:

![]()
1 // +
2 // + + + 與 step 相連的棋子,包含自身
3 // + 根據 color 參數決定是所有,同色,黑色,白色,還是空色。
4 List<Step> LinkSteps(Step step, StoneColor color = StoneColor.Empty)
5 {
6 List<Step> links = new List<Step>();
7 for (int i = -1; i < 2; i++) {
8 for (int j = -1; j < 2; j++) {
9 if (i == j || i == -j) {
10 continue;
11 }
12 if (InRange(step.Row + i, step.Col + j)) {
13 links.Add(m_Steps[step.Row + i, step.Col + j]);
14 }
15 }
16 }
17 links.Add(step);
18 if (color == StoneColor.All) {
19 return links;
20 } else {
21 links.RemoveAll(l => l.StoneColor != color);
22 return links;
23 }
24 }
LinkSteps()
當然,關於劫爭,關於悔棋,非深入代碼,不能明白。但 LinkSteps()是構成集合的基礎。從集合的觀點,研究圍棋,相信比其他方法更為可行。