编写“线围棋”程序-2-可开局

棋盘有了,怎么支持在上面落子呢?

只要解决下面3个问题就可以了:

1.响应鼠标点击事件,获得“下棋子”的动作源。

2.修改和记录棋局状态。

3.在棋盘上显示棋局的状态。

为此,直接增加一个“棋局类“,也就是对“一盘棋“对象的实现。

先把已经编好的棋盘类移到一个新的单元里,不再放到窗体单元中,我喜欢这样把成熟的程序逐渐移到新单元内存放。

棋盘单元如下:

unit UnitBoardView;

interface

uses
  Windows, Messages, SysUtils, Variants, Types, Classes, Graphics;

Type
 TStringGoBoard = Class(TObject)     //线棋盘类
   Private
     FMaxP : Integer;                  //棋盘最大点树
     FRect : TRect;                    //棋盘区域位置
     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必须是偶数,也就是必须得到奇数个交叉点;
  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;          //动态计算画棋盘位置
      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.


里面已经添加了显示一步棋和根据鼠标位置找下棋点位置的方法了,这是支持下棋所必需要有的方法。

然后,继续在窗体类的单元内试验新建的棋局类。为简便起见,棋盘就当作棋局本身的一部分了。

新的窗体单元变成了这个样子的:

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;      //记录棋子状态的数组
    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;            //窗口创建时是创建对局
  FGame.Board.Rect := ClientRect;   //棋盘占整个窗口位置
  FGame.MaxP := 8;                //设为9点棋局
  //FGame.MaxP := 15;                //设为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);  //根据屏幕坐标得到下棋点坐标。
      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;          //设置棋盘大小
    SetLength(FPosStatus, MaxP + 1 );    //初始化记录数组
    For i := 0 to MaxP do
      begin
        FPosStatus[i] := 0;
      end;
  end;

end.

呵呵,我用了一个动态的整数数组来记录棋局的状态。

这个程序已经可以用鼠标交替落子了,但还不能真正支持对弈,因为还不知道怎么提子。下一步就是要实现下棋规则了,最好支持自动提子,就可以用来玩了。

程序运行的效果如下:

 

 

 

转载于:https://www.cnblogs.com/babituo/archive/2008/10/06/1304814.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/423679.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java面试题 21 下列说法正确的有()

下列说法正确的有&#xff08;&#xff09; A 能被java.exe成功运行的java class文件必须有main()方法 B J2SDK就是Java API C:Appletviewer.exe可利用jar选项运行.jar文件 D能被Appletviewer成功运行的java class文件必须有main()方法 蒙蔽树上蒙蔽果&#xff0c;蒙蔽树下…

[翻译]SQL Server 未公开的两个存储过程sp_MSforeachtable 和 sp_MSforeachdb

SQL Server 未公开的两个存储过程sp_MSforeachtable 和 sp_MSforeachdb 您是否曾经写过代码来处理数据库中的所有表&#xff1f;处理一个 SQL Server实例中的所有数据库的代码又该如何写&#xff1f;然则&#xff0c;您是否知道有多种方法可以解决这问题&#xff1f;您可以创建…

Java面试题 22 牛客 Java是一门支持反射的语言,基于反射为Java提供了丰富的动态性支持

Java面试题 22 牛客 Java是一门支持反射的语言,基于反射为Java提供了丰富的动态性支持&#xff0c;下面关于Java反射的描述&#xff0c;哪些是错误的&#xff1a;( ) A Java反射主要涉及的类如Class, Method, Filed,等&#xff0c;他们都在java.lang.reflet包下 B 通…

java面试题24 关于Java中的数组,

java面试题24 关于Java中的数组&#xff0c;下面的一些描述&#xff0c;哪些描述是准确的&#xff1a;&#xff08; &#xff09; A 数组是一个对象&#xff0c;不同类型的数组具有不同的类 B 数组长度是可以动态调整的 C 数组是一个连续的存储结构 D:一个固定长度的…

[开发技巧3]不显示报表直接打印

水晶报表9.2VB6 使用Application可以进行打印 在将数据赋给报表模板后&#xff0c;调用PrintOut方法 赋给报表数据objCRReport.Database.SetDataSource rst 此句打印&#xff0c;会出现打印提示框objCRReport.PrintOut 不提示&#xff0c;直接打印到默认打印机CallobjCRReport.…

SQL开发中容易忽视的一些小地方( 三)

目的&#xff1a;这篇文章我想说说我在工作中关于in和union all 的用法. 索引定义 &#xff1a; 微软的SQL SERVER提供了两种索引&#xff1a;聚集索引(clustered index&#xff0c;也称聚类索引、簇集索引)和非聚集索引(nonclustered index&#xff0c;也称非聚类索引、非簇集…

java面试题26 java语言的下面几种数组复制方法中,哪个效率最高?

java面试题26 java语言的下面几种数组复制方法中&#xff0c;哪个效率最高&#xff1f; A for 循环逐一复制 B System.arraycopy C Array.copyOf D 使用clone方法 效率&#xff1a;System.arraycopy > clone > Arrays.copyOf > for循环 1、System.arraycopy的用法…

pycharm使用笔记2-远程连接(转)

原文地址:https://blog.csdn.net/jinxiaonian11/article/details/70208920 随着科技的发展&#xff0c;远程办公已经是一种趋势&#xff0c;远程开发能力对于每一个程序员来说都是必不可少的。有时候就算在公司&#xff0c;在进行开发的时候有许多的数据都是储存在服务器上的&a…

java面试题27 java中下面哪些是Object类的方法()

java面试题27 java中下面哪些是Object类的方法&#xff08;&#xff09; A notify() B notifyAll() C sleep() D wait() 蒙蔽树上蒙蔽果&#xff0c;蒙蔽树下你和我。遇到这种题&#xff0c;我默默的打开了编译工具 Object类中方法&#xff1a; protected Object clone()…

shiro学习(1):shiro简介

Apache Shiro是Java的一个安全框架。对比另一个安全框架Spring Sercurity&#xff0c;它更简单和灵活。 Shiro可以帮助我们完成&#xff1a;认证、授权、加密、会话管理、Web集成、缓存等。 Apache Shiro特性 Authentication&#xff1a;身份认证/登录&#xff0c;验证用户是…

微软启动了自爆程序,让我们一起帮它倒计时

……“公元2008年10月20日&#xff0c;注定成为人类信息技术史上不平凡的一天&#xff0c;因为在这一天&#xff0c;曾经创造了无数辉煌的计算机软件帝国微软公司&#xff0c;启动了自爆程序&#xff0c;剩下的&#xff0c;就是倒计时了……” ——《地球人类信息技术编年史》 …

python字典遍历的几种方法(转)

源地址&#xff1a;https://www.cnblogs.com/stuqx/p/7291948.html&#xff08;1&#xff09;遍历key值>>> a {a: 1, b: 2, c: 3} >>> for key in a:print(key:a[key])a:1 b:2 c:3 >>> for key in a.keys():print(key:a[key])a:1 b:2 c:3在使用上&a…

shiro学习(2):第一个shiro程序

工具idea 首先创建maven项目 配置文件 <?xml version"1.0" encoding"UTF-8"?><project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http…

shiro学习(3):用户权限

工具idea 首先创建maven项目 配置文件 <?xml version"1.0" encoding"UTF-8"?><project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http…

WPF学习笔记(三)

1.1 事件概括 第一节中我们给窗体添加了一个按钮&#xff0c;不过好像Button点个几下也只有些发光样式的变化&#xff0c;什么你还把系统皮肤去掉了&#xff1f;算了承认下确实够寒碜&#xff0c;那让我们再动动手。 1.1.1 路由事件简述 public HelloWorld() { Button button …

shiro学习(4):shiro认证流程

Shiro登录校验流程实现与分析 什么是Shiro Apache Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码和会话管理。使用Shiro的易于理解的API,您可以快速、轻松地获得任何应用程序,从最小的移动应用程序到最大的网络和企业应用程序。 三个核心组件 Subject, Se…

在ASP.NET MVC中实现Select多选

我们知道&#xff0c;在ASP.NET MVC中实现多选Select的话&#xff0c;使用Html.ListBoxFor或Html.ListBox方法就可以。在实际应用中&#xff0c;到底该如何设计View Model&#xff0c; 控制器如何接收多选Select的选中项呢&#xff1f; 实现效果如下&#xff1a; 初始状态某些选…

shiro学习(5):ini文件和自定义realm

工具idea 首先创建maven项目 配置文件 <?xml version"1.0" encoding"UTF-8"?><project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http…

关于python中带下划线的变量和函数 的意义

转载:https://www.cnblogs.com/wangshuyi/p/6096362.html总结:变量:1. 前带_的变量: 标明是一个私有变量, 只用于标明, 外部类还是可以访问到这个变量2. 前带两个_ ,后带两个_ 的变量: 标明是内置变量,3. 大写加下划线的变量: 标明是 不会发生改变的全局变量函数:1. 前带…

歌谣对自己的“自勉“

前言 为什么突然想写一篇文章呢&#xff0c;可能是源于个人吧&#xff0c;每天睡觉前都会思考一下是否达到了以后想要的生活。很显然答案是没有&#xff0c;不然我现在也不和大家在一起侃侃而谈。讲真&#xff08;这是我室友经常说的一句话&#xff09;&#xff0c;我是参与安…