• Delphi – 我的代码之简单五子棋


    技术交流,DH讲解.

    今天来实现一个简单的五子棋,直接用GDI来画的一个游戏.
    首先我们来想下怎么存放数据,哪些地方是白棋,哪些地方是黑棋,哪些地方没有下棋?
    对,我们用一个二维数组,如果数组中某一个位置的值为0代表没有下棋,为1代表是白棋,为2代表是黑棋.
    好就这么说定了,为了使用方便,我们打算做成一个控件,因为要画界面所以我们从TGraphicControl继承下来.
    看一下类定义的代码:

    Type
      TLastPlayer= (LpP1, LpP2);
      TGameEvent= Procedure(S: TObject; P: TLastPlayer) Of Object;
    
      TFiveGame= Class(TGraphicControl)
      Private
        // 如果是空,就是0,白棋就是1,黑棋就是2
        FData: Array Of Array Of Byte;
        // 棋盘的长和宽
        FRows, FColumns: Integer;
        // 格子的宽度/
        FCellWidth: Integer;
        // 是否自动大小
        FAutoSize: Boolean;
        // 棋盘线条的颜色.
        FLineColor: TColor;
        // 2个选手的颜色
        FPlayerOneColor: TColor;
        FPlayerTwoColor: TColor;
        // 边距
        FHDistance, FVDistance: Integer;
        // 上次操作的选手
        FLastPlayer: TLastPlayer;
        // 三个事件
        FWinEvent: TGameEvent;
        FErrorEvent: TGameEvent;
        FSuccessEvent: TGameEvent;
        Procedure SetRows(Const Value: Integer);
        Procedure SetColumns(Const Value: Integer);
        Procedure SetCellWidth(Const Value: Integer);
        Procedure SetAutoSize(Const Value: Boolean);
        Procedure SetLineColor(Const Value: TColor);
        Procedure SetPlayerOneColor(Const Value: TColor);
        Procedure SetPlayerTwoColor(Const Value: TColor);
        Procedure SetHDistance(Const Value: Integer);
        Procedure SetVDistance(Const Value: Integer);
        Procedure Paint; Override;
        Function AddChessMan(X, Y, V: Integer): Boolean;
        Procedure MyButtonDown(Sender: TObject; Button: TMouseButton;
          Shift: TShiftState; X, Y: Integer);
        Function Judge(X, Y, V: Integer): Boolean;
      Protected
    
      Public
        Constructor Create(AOwner: TComponent); Override;
        Destructor Destroy; Override;
        //
        Procedure ReStart;
        Function AddP1Chessman(X, Y: Integer): Boolean;
        Function AddP2Chessman(X, Y: Integer): Boolean;
      Published
        Property Rows: Integer Read FRows Write SetRows;
        Property Columns: Integer Read FColumns Write SetColumns;
        Property CellWidth: Integer Read FCellWidth Write SetCellWidth;
        Property AutoSize: Boolean Read FAutoSize Write SetAutoSize;
        Property LineColor: TColor Read FLineColor Write SetLineColor;
        Property PlayerOneColor
          : TColor Read FPlayerOneColor Write SetPlayerOneColor;
        Property PlayerTwoColor
          : TColor Read FPlayerTwoColor Write SetPlayerTwoColor;
        Property HDistance: Integer Read FHDistance Write SetHDistance;
        Property VDistance: Integer Read FVDistance Write SetVDistance;
        Property WinEvent: TGameEvent Read FWinEvent Write FWinEvent;
        Property LastPlayer: TLastPlayer Read FLastPlayer Write FLastPlayer;
        Property ErrorEvent: TGameEvent Read FErrorEvent Write FErrorEvent;
        Property SuccessEvent: TGameEvent Read FSuccessEvent Write FSuccessEvent;
      End;

    我们这样定义了一个类,接下来看看怎么实现它的:

    { TFiveGame }
    // 增加一颗棋子
    Function TFiveGame.AddChessMan(X, Y, V: Integer): Boolean;
    Begin
      Result:= False;
      If (X< 0)Or (Y< 0)Or (X> Columns- 1)Or (Y> Rows- 1) Then
        Exit;
      If FData[X, Y]<> 0 Then
        Exit;
      FData[X, Y]:= Byte(V);
      Result:= True;
    End;
    
    // 一号选手增加棋子
    Function TFiveGame.AddP1Chessman(X, Y: Integer): Boolean;
    Begin
      Result:= AddChessMan(X, Y, 1);
    End;
    
    // 二号选手增加棋子
    Function TFiveGame.AddP2Chessman(X, Y: Integer): Boolean;
    Begin
      Result:= AddChessMan(X, Y, 2)
    End;
    
    Constructor TFiveGame.Create(AOwner: TComponent);
    Begin
      Inherited;
      // 初始化
      FAutoSize:= False;
      FRows:= 5;
      FColumns:= 5;
      FCellWidth:= 30;
      FLineColor:= ClRed;
      FPlayerOneColor:= ClBlack;
      FPlayerTwoColor:= ClYellow;
      FHDistance:= 20;
      FVDistance:= 20;
      FLastPlayer:= LpP2;
      SetLength(FData, FRows, FColumns);
      // 要响应鼠标,必须加上这个
      ControlStyle:= ControlStyle+ [CsReplicatable, CsCaptureMouse, CsClickEvents];
      Self.OnMouseDown:= MyButtonDown;
    End;
    
    Destructor TFiveGame.Destroy;
    Begin
    
      Inherited;
    End;
    
    // 判断是否胜利
    Function TFiveGame.Judge(X, Y, V: Integer): Boolean;
    Var
      C1, C2: Integer;
      X1, Y1: Integer;
    
      Procedure Reset;
      Begin
        C1:= 0;
        C2:= 0;
        X1:= X;
        Y1:= Y;
      End;
    
    Begin
      Result:= True;
      // 这个编译指令是代码折叠,但是D7以及之前版本没有这个编译指令.不要惊恐
      // 横向
      {$IFDEF D7UP}
      {$REGION '横向'}
      {$ENDIF}
      Begin
        Reset;
        // 向左
        Dec(X1);
        While X1>= 0 Do
        Begin
          If FData[X1, Y]<> V Then
            Break;
          Inc(C1);
          If C1= 4 Then
            Exit;
          Dec(X1);
        End;
        // 向右
        X1:= X+ 1;
        While X1< Columns Do
        Begin
          If FData[X1, Y]<> V Then
            Break;
          Inc(C2);
          If C1+ C2= 4 Then
            Exit;
          Inc(X1);
        End;
      End;
      {$IFDEF D7UP}
      {$ENDREGION}
      // 竖向
      {$REGION '竖向'}
      {$ENDIF}
      Begin
        Reset;
        // 向上
        Dec(Y1);
        While Y1>= 0 Do
        Begin
          If FData[X, Y1]<> V Then
            Break;
          Inc(C1);
          If C1= 4 Then
            Exit;
          Dec(Y1);
        End;
        // 向下
        Y1:= Y+ 1;
        While Y1< Rows Do
        Begin
          If FData[X, Y1]<> V Then
            Break;
          Inc(C2);
          If C1+ C2= 4 Then
            Exit;
          Inc(Y1);
        End;
      End;
      {$IFDEF D7UP}
      {$ENDREGION}
      // 斜向1
      {$REGION '斜向1'}
      {$ENDIF}
      Begin
        Reset;
        Dec(X1);
        Dec(Y1);
        While (X1>= 0)And (Y1>= 0) Do
        Begin
          If FData[X1, Y1]<> V Then
            Break;
          Inc(C1);
          If C1= 4 Then
            Exit;
          Dec(X1);
          Dec(Y1);
        End;
        X1:= X+ 1;
        Y1:= Y+ 1;
        While (X1< Columns)And (Y1< Rows) Do
        Begin
          If FData[X1, Y1]<> V Then
            Break;
          Inc(C2);
          If C1+ C2= 4 Then
            Exit;
          Inc(X1);
          Inc(Y1)
        End;
      End;
      {$IFDEF D7UP}
      {$ENDREGION}
      // 斜向2
      {$REGION '斜向2'}
      {$ENDIF}
      Begin
        Reset;
        Dec(X1);
        Inc(Y1);
        While (X1>= 0)And (Y1< Rows) Do
        Begin
          If FData[X1, Y1]<> V Then
            Break;
          Inc(C1);
          If C1= 4 Then
            Exit;
          Dec(X1);
          Inc(Y1);
        End;
        X1:= X+ 1;
        Y1:= Y- 1;
        While (X1< Columns)And (Y1>= 0) Do
        Begin
          If FData[X1, Y1]<> V Then
            Break;
          Inc(C2);
          If C1+ C2= 4 Then
            Exit;
          Inc(X1);
          Dec(Y1);
        End;
      End;
      {$IFDEF D7UP}
      {$ENDREGION}
      {$ENDIF}
      Result:= False;
    End;
    
    Procedure TFiveGame.MyButtonDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    Var
      I, J, K: Integer;
      B: Boolean;
    Begin
      // 不是左键
      If Button<> MbLeft Then
        Exit;
      // 计算x,y的位置
      If (X< HDistance)Or (X> HDistance+ Columns* CellWidth) Then
        Exit;
      If (Y< VDistance)Or (Y> VDistance+ Rows* CellWidth) Then
        Exit;
      I:= (X- HDistance)Div CellWidth;
      J:= (Y- VDistance)Div CellWidth;
      // 加棋子
      Case FLastPlayer Of
        LpP1:
          Begin
            B:= AddP2Chessman(I, J);
            If B Then
              FLastPlayer:= LpP2
          End;
        LpP2:
          Begin
            B:= AddP1Chessman(I, J);
            If B Then
              FLastPlayer:= LpP1
          End;
      End;
      // 结果处理
      If B Then
      Begin
        Invalidate;
        If Assigned(FSuccessEvent) Then
          FSuccessEvent(Self, FLastPlayer);
        If Judge(I, J, Ord(FLastPlayer)+ 1) Then
          If Assigned(FWinEvent) Then
            FWinEvent(Self, FLastPlayer);
      End
      Else
        If Assigned(FErrorEvent) Then
          FErrorEvent(Self, FLastPlayer);
    End;
    
    Procedure TFiveGame.Paint;
    
      Procedure DrawBkg;
      Var
        I: Integer;
        OldColor: TColor;
      Begin
        With Canvas Do
        Begin
          OldColor:= Pen.Color;
          Pen.Color:= LineColor;
          Rectangle(HDistance, VDistance, HDistance+ Columns* CellWidth,
            VDistance+ Rows* CellWidth);
          For I:= 1 To Columns- 1 Do
          Begin
            MoveTo(HDistance+ I* CellWidth, VDistance);
            LineTo(HDistance+ I* CellWidth, VDistance+ Rows* CellWidth);
          End;
          For I:= 1 To Rows- 1 Do
          Begin
            MoveTo(HDistance, VDistance+ I* CellWidth);
            LineTo(HDistance+ Columns* CellWidth, VDistance+ I* CellWidth);
          End;
          Pen.Color:= OldColor;
        End;
      End;
    
      Procedure DrawChessMan(X, Y, V: Integer);
      Var
        C1, C2: TColor;
      Begin
        With Canvas Do
        Begin
          C1:= Brush.Color;
          C2:= Pen.Color;
          Case V Of
            1:
              Brush.Color:= PlayerOneColor;
            2:
              Brush.Color:= PlayerTwoColor;
          End;
          Pen.Color:= Brush.Color;
          Ellipse(HDistance+ X* CellWidth+ 1, VDistance+ Y* CellWidth+ 1,
            HDistance+ (X+ 1)* CellWidth- 1, VDistance+ (Y+ 1)* CellWidth- 1);
          Pen.Color:= C2;
          Brush.Color:= C1;
        End;
      End;
    
    Var
      J: Integer;
      K: Integer;
    Begin
      //如果自动大小 就调整大小
      If AutoSize Then
      Begin
        Width:= HDistance* 2+ Columns* CellWidth;
        Height:= VDistance* 2+ Rows* CellWidth;
      End;
      // 画棋盘
      DrawBkg;
      // 画棋子
      For J:= 0 To Rows- 1 Do
        For K:= 0 To Columns- 1 Do
          If FData[J, K]<> 0 Then
            DrawChessMan(J, K, FData[J, K]);
    
    End;
    
    Procedure TFiveGame.ReStart;
    Var
      I: Integer;
      J: Integer;
    Begin
      For I:= 0 To Rows- 1 Do
        For J:= 0 To Columns- 1 Do
          FData[I, J]:= 0;
      Invalidate;
    End;
    
    Procedure TFiveGame.SetAutoSize(Const Value: Boolean);
    Begin
      If FAutoSize= Value Then
        Exit;
      FAutoSize:= Value;
      Invalidate;
    End;
    
    Procedure TFiveGame.SetCellWidth(Const Value: Integer);
    Begin
      If FCellWidth= Value Then
        Exit;
      FCellWidth:= Value;
      Invalidate;
    End;
    
    Procedure TFiveGame.SetColumns(Const Value: Integer);
    Begin
      If FColumns= Value Then
        Exit;
      FColumns:= Value;
      SetLength(FData, FRows, FColumns);
      Invalidate;
    End;
    
    Procedure TFiveGame.SetHDistance(Const Value: Integer);
    Begin
      If FHDistance= Value Then
        Exit;
      FHDistance:= Value;
      Invalidate;
    End;
    
    Procedure TFiveGame.SetPlayerOneColor(Const Value: TColor);
    Begin
      If FPlayerOneColor= Value Then
        Exit;
      FPlayerOneColor:= Value;
      Invalidate;
    End;
    
    Procedure TFiveGame.SetLineColor(Const Value: TColor);
    Begin
      If FLineColor= Value Then
        Exit;
      FLineColor:= Value;
      Invalidate;
    End;
    
    Procedure TFiveGame.SetPlayerTwoColor(Const Value: TColor);
    Begin
      If FPlayerTwoColor= Value Then
        Exit;
      FPlayerTwoColor:= Value;
      Invalidate;
    End;
    
    Procedure TFiveGame.SetRows(Const Value: Integer);
    Begin
      If FRows= Value Then
        Exit;
      FRows:= Value;
      SetLength(FData, FRows, FColumns);
      Invalidate;
    End;
    
    Procedure TFiveGame.SetVDistance(Const Value: Integer);
    Begin
      If FVDistance= Value Then
        Exit;
      FVDistance:= Value;
      Invalidate;
    End;

    要想把这个类加到控件面板上面去就需要再添加一个Register全局函数,我这里没有添加,所以也不演示那句话了.

    类给出来了,我们看看怎么使用这个类.
    定义一个该类的对象:

    FiveGame:TFiveGame;

    窗体创建的时候的时候,实例化这个对象:

    procedure TForm1.FormCreate(Sender: TObject);
    begin
      FiveGame:=TFiveGame.Create(Self);
      FiveGame.Parent:=Self;
      FiveGame.Align:=alClient;
      FiveGame.WinEvent:=OnWin;
      FiveGame.ErrorEvent:=Onerror;
      FiveGame.SuccessEvent:=OnSuccess;
    end;

    窗体结束的时候不要忘记释放这个对象哟.代码我就不贴了,给出一个完整代码下载的链接吧.
    image
    下载地址:点这里

    代码很简单,也很不完善,打算有空加入人机对战和联网对战,然后界面再改漂亮一些吧,比如用贴图或者用DX来弄.
    这里只是一个抛砖引玉吧.

    我是DH,今天到这里.

  • 相关阅读:
    Ionic开发Hybrid App问题总结
    >>> 主页链接
    微信小程序之WebSocket
    Keepalived+LVS+nginx搭建nginx高可用集群
    centos7 dns(bind)安装配置
    samba安装配置
    redis数据备份还原
    gitlab部署
    gitlab数据迁移
    kubeadm部署一个Kubernetes集群
  • 原文地址:https://www.cnblogs.com/huangjacky/p/1629768.html
Copyright © 2020-2023  润新知