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