编写“线围棋”程序-2-可开局
棋盤有了,怎么支持在上面落子呢?
只要解決下面3個問題就可以了:
1.響應(yīng)鼠標點擊事件,獲得“下棋子”的動作源。
2.修改和記錄棋局狀態(tài)。
3.在棋盤上顯示棋局的狀態(tài)。
為此,直接增加一個“棋局類“,也就是對“一盤棋“對象的實現(xiàn)。
先把已經(jīng)編好的棋盤類移到一個新的單元里,不再放到窗體單元中,我喜歡這樣把成熟的程序逐漸移到新單元內(nèi)存放。
棋盤單元如下:
unit UnitBoardView;
interface
uses
? Windows, Messages, SysUtils, Variants, Types, Classes, Graphics;
Type
?TStringGoBoard = Class(TObject)???? //線棋盤類
?? Private
???? FMaxP : Integer;????????????????? //棋盤最大點樹
???? FRect : TRect;??????????????????? //棋盤區(qū)域位置
???? Function GetDD : Integer;???????? //相鄰交叉點間隔距離
???? Function GetBX0 : Integer;??????? //棋盤起畫點X
???? Function GetBY0 : Integer;??????? //棋盤起畫點Y
?? Protected
???? Procedure SetMaxP(AMaxP : Integer);
???? Property DD : Integer Read GetDD;???? //相鄰交叉點間隔距離
???? Property BX0 : Integer Read GetBX0;?? //棋盤起畫點X
???? Property BY0 : Integer Read GetBY0;?? //棋盤起畫點Y
?? Public
???? Procedure Drawto(ACanvas : TCanvas);? //畫到一個畫布上
???? Procedure DrawMove(ACanvas : TCanvas; APos : Integer; AStatus : Integer); //畫一步棋
???? Function Position(X,Y : Integer) : Integer;???????? //找一個下棋位置
???? Property MaxP : Integer Read FMaxP Write SetMaxP;
???? Property Rect : TRect Read FRect Write FRect;
?? End;
implementation
{TStringGoBoard}
Function TStringGoBoard.GetDD : Integer;???? //相鄰交叉點間隔距離
? begin
??? Result := ((Rect.Right - Rect.Left) - 20) div MaxP; //寬度兩邊各留10個像素
? end;
Function TStringGoBoard.GetBX0 : Integer;??????? //棋盤起畫點X
? begin
??? Result := Rect.Left + 10;
? end;
Function TStringGoBoard.GetBY0 : Integer;??????? //棋盤起畫點Y
? begin
??? Result := Rect.Top + (Rect.Bottom - Rect.Top) div 2;
? end;
Procedure TStringGoBoard.SetMaxP(AMaxP : Integer);
? begin
??? FMaxP := (AMaxP Div 2) * 2; //N必須是偶數(shù),也就是必須得到奇數(shù)個交叉點;
? end;
Procedure TStringGoBoard.Drawto(ACanvas : TCanvas); //畫到一個畫布上
var
? i,M: Integer;
? X0,Y0,BDD,CDD : Integer;
begin
? M := MaxP div 2;
? with ACanvas do
??? begin
????? Pen.Width := 1;
????? X0 := BX0;????????? //動態(tài)計算畫棋盤位置
????? Y0 := BY0;
????? BDD := DD;
????? CDD := BDD div 2;
????? moveto(X0,Y0);
????? LineTo(X0 + MaxP * BDD, Y0);
????? For i := 0 to MaxP do
??????? begin
????????? if (i = 0) or (i = MaxP) then
???????????? Pen.Width := 3?????????? //畫兩端的粗線
??????????? else
???????????? Pen.Width := 1;????????? //畫中間的細線
????????? moveto(X0 + i * BDD,Y0 - CDD);
????????? Lineto(X0 + i * BDD,Y0 + CDD);
????????? if i = M then?????????????? //在中點畫一個星(天元,呵呵!)
??????????? begin
????????????? Brush.Color := ClBlack;
????????????? Brush.Style := bsSolid;
????????????? Ellipse(X0 - 2 + i * BDD, Y0 -2, X0 +2 + i * BDD, Y0 +2);
??????????? end;
??????? end;
??? end;
end;
Procedure TStringGoBoard.DrawMove(ACanvas : TCanvas; APos : Integer; AStatus : Integer); //畫一步棋
var
? X0,Y0,BDD,CDD : Integer;
begin
? with ACanvas do
??? begin
????? X0 := BX0;
????? Y0 := BY0;
????? BDD := DD;
????? CDD := BDD div 2;
????? if AStatus = 1 then
???????? Brush.Color := ClBlack
??????? else
???????? Brush.Color := ClWhite;
????? Pen.Width := 1;
????? Pen.Color := Brush.Color;
????? Brush.Style := bsSolid;
????? Ellipse(X0 - CDD + APos * BDD, Y0 - CDD, X0 + CDD + APos * BDD, Y0 + CDD);
??? end;
end;
Function TStringGoBoard.Position(X,Y : Integer) : Integer;???????? //找一個下棋位置
? var
??? i : Integer;
??? X0,Y0,BDD,CDD,X1,Y1,X2,Y2 : Integer;
? begin
??? Result := -1;
??? X0 := BX0;
??? Y0 := BY0;
??? BDD := DD;
??? CDD := BDD div 2;
??? For i := 0 to MaxP do
????? begin
??????? X1 := X0 - CDD + i * BDD;
??????? Y1 := Y0 - CDD;
??????? X2 := X0 + CDD + i * BDD;
??????? Y2 := Y0 + CDD;
??????? if (X >= X1) and (X <= X2) and
?????????? (Y >= Y1) and (Y <= Y2) then
????????? begin
??????????? Result := i;
??????????? Exit;
????????? end;
????? end;
? end;
end.
里面已經(jīng)添加了顯示一步棋和根據(jù)鼠標位置找下棋點位置的方法了,這是支持下棋所必需要有的方法。
然后,繼續(xù)在窗體類的單元內(nèi)試驗新建的棋局類。為簡便起見,棋盤就當作棋局本身的一部分了。
新的窗體單元變成了這個樣子的:
unit Unit1;
interface
uses
? Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
? Dialogs, UnitBoardView;
type
TGame = Class(TObject)
? Private
??? FBoard : TStringGoBoard;??????????? //包含一個棋盤對象
??? FPosStatus : Array of Integer;????? //記錄棋子狀態(tài)的數(shù)組
??? FCurPlayer : Integer;??????????? ? ?? ? //當前行棋方,1:黑,2:白
? Protected
??? Function GetMaxP : Integer;
??? Procedure SetMaxP (AMaxP : Integer);
? Public
??? Constructor Create;
??? Destructor Destroy; Override;
??? Procedure SetPos(APos : Integer);???? //在位置上走一步棋
??? Procedure Drawto(ACanvas : TCanvas);? //把棋局畫在畫布上
??? Property Board : TStringGoBoard Read FBoard;
??? Property MaxP : Integer Read GetMaxP Write SetMaxP;? //最大棋盤位置
? end;
TForm1 = class(TForm)
??? procedure FormPaint(Sender: TObject);
??? procedure FormCreate(Sender: TObject);
??? procedure FormDestroy(Sender: TObject);
??? procedure FormResize(Sender: TObject);
??? procedure FormMouseDown(Sender: TObject; Button: TMouseButton;
????? Shift: TShiftState; X, Y: Integer);
? private
??? FGame : TGame;?????????????? //棋局對象
? public
??? { Public declarations }
? end;
var
? Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
begin
? FGame := TGame.Create;??????????? //窗口創(chuàng)建時是創(chuàng)建對局
? FGame.Board.Rect := ClientRect;?? //棋盤占整個窗口位置
? FGame.MaxP := 8;??????????????? //設(shè)為9點棋局
? //FGame.MaxP := 15;??????????????? //設(shè)為15點棋局
end;
procedure TForm1.FormPaint(Sender: TObject);
begin
? FGame.Drawto(Canvas);????????????? //畫棋局
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
? FGame.Free;?????????????????????? //窗口銷毀時銷毀棋局
end;
procedure TForm1.FormResize(Sender: TObject);
begin
? FGame.Board.Rect := ClientRect;??? //窗口變化大小是變化棋盤大小
? Repaint;?????????????????????????? //啟動重畫窗口
end;
procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
? Shift: TShiftState; X, Y: Integer);
var
? Pos : Integer;
begin
? if Button = mbLeft then
??? begin
????? Pos := FGame.Board.Position(X,Y);? //根據(jù)屏幕坐標得到下棋點坐標。
????? if Pos >= 0 then
??????? begin
????????? FGame.SetPos(Pos);????????? //在棋局上走一步棋
????????? Repaint;??????????????????? //顯示棋局
??????? end;
??? end;
end;
{TGame}
Constructor TGame.Create;
? begin
??? Inherited Create;
??? FCurPlayer := 1;???????????????? //默認黑為當前下子方
??? FBoard := TStringGoBoard.Create;
? end;
Destructor TGame.Destroy;
? begin
??? FBoard.Free;
??? Inherited Destroy;
? end;
Procedure TGame.SetPos(APos : Integer);
? begin
??? FPosStatus[APos] := FCurPlayer;
??? FCurPlayer := 3 - FCurPlayer;
? end;
Procedure TGame.Drawto(ACanvas : TCanvas);
? var
??? i : Integer;
? begin
??? FBoard.Drawto(ACanvas);?????????? //畫出棋盤
??? For i := 0 to MaxP do
????? begin
??????? if FPosStatus[i] <> 0? then
????????? begin
??????????? FBoard.DrawMove(ACanvas,i,FPosStatus[i]);?? //畫棋子
????????? end;
????? end;
? end;
Function TGame.GetMaxP : Integer;
? begin
??? Result := FBoard.MaxP;
? end;
Procedure TGame.SetMaxP (AMaxP : Integer);
? var
??? i : Integer;
? begin
??? FBoard.MaxP := AMaxP;????????? //設(shè)置棋盤大小
??? SetLength(FPosStatus, MaxP + 1 );??? //初始化記錄數(shù)組
??? For i := 0 to MaxP do
????? begin
??????? FPosStatus[i] := 0;
????? end;
? end;
end.
呵呵,我用了一個動態(tài)的整數(shù)數(shù)組來記錄棋局的狀態(tài)。
這個程序已經(jīng)可以用鼠標交替落子了,但還不能真正支持對弈,因為還不知道怎么提子。下一步就是要實現(xiàn)下棋規(guī)則了,最好支持自動提子,就可以用來玩了。
程序運行的效果如下:
?
?
?
轉(zhuǎn)載于:https://www.cnblogs.com/babituo/archive/2008/10/06/1304814.html
總結(jié)
以上是生活随笔為你收集整理的编写“线围棋”程序-2-可开局的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Tushare 基础用法
- 下一篇: 【推荐】“水果”公司的复兴 (乔布斯和苹