Delphiでお手軽プログラミング

Delphiでお手軽プログラミングメニュー

リバーシをプログラミングする(WindowsでもAndroidでも動く)


Delphiを起動してプロジェクトを作成し、オブジェクトを配置し、プロパティを設定する。

Delphiを起動し[ファイル]→[新規作成]→[マルチデバイスアプリケーション-Delphi]をクリックします。
[空のアプリケーション]を選択して[OK]ボタンを押します。

Form1の widthプロパティを"320"に設定します。
Form1の heightプロパティを"500"に設定します。

ツールパレットからTScaledLayoutをドラッグ&ドロップします。
ScaledLayout1のPosition.Xプロパティを"0"に設定します。
ScaledLayout1のPosition.Yプロパティを"0"に設定します。
ScaledLayout1のWidthプロパティを"320"に設定します。
ScaledLayout1のHeightプロパティを"500"に設定します。

ツールパレットからTLayoutをScaledLayout1にドラッグ&ドロップします。
Layout1のAlignプロパティを"Top"に設定します。
Layout1のHeightプロパティを"50"に設定します。

ツールパレットからTButtonをLayout1にドラッグ&ドロップします。
Button1のAlignプロパティを"MostLeft"に設定します。
Button1のMargins.Bottom,Margins.Left,Margins.Right,Margins.Topプロパティを"2"に設定します。
Button1のTextプロパティを"開始"に設定します。

ツールパレットからTButtonをLayout1にドラッグ&ドロップします。
Button2のAlignプロパティを"Left"に設定します。
Button2のMargins.Bottom,Margins.Left,Margins.Right,Margins.Topプロパティを"2"に設定します。

ツールパレットからTMemoをScaledLayout1にドラッグ&ドロップします。
Memo1のAlignプロパティを"Bottom"に設定します。
Memo1のHeightプロパティを"130"に設定します。

ツールパレットからTImageをScaledLayout1にドラッグ&ドロップします。
Image1のAlignプロパティを"Client"に設定します。
(重要)Image1のMultiResBitmapプロパティに、何でもいいので小さい画像ファイルを設定します。
Image1のWrapModeプロパティを"Fit"に設定します。

ツールパレットからTTimerをフォームへドラッグ&ドロップします。
Timer1のEnabledプロパティを"False"に設定します。


プログラミング

unit Unit1;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.StdCtrls,
  FMX.Objects, FMX.Controls.Presentation, FMX.ScrollBox, FMX.Memo, FMX.Layouts;

type
  TForm1 = class( TForm)
    ScaledLayout1: TScaledLayout;
    Layout1: TLayout;
    Memo1: TMemo;
    Image1: TImage;
    Button1: TButton;
    Button2: TButton;
    Timer1: TTimer;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);
    procedure Image1MouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Single);
    procedure Button2Click(Sender: TObject);
  private
    { private 宣言 }
    com_iro:Integer; //PCの色 1:白,2:黒
    user_iro:Integer;//ユーザーの色 1:白,2:黒
    //PCの順番1、ユーザーの順番2
    OrderPcUser:integer;
    //盤の状態を保持する 0まだおかれてない、1白、2黒
    fBoard:array[0..7] of array[0..7] of Integer;
    //PCの番の時に呼ぶ関数
    procedure PcCalculate();
    //配列fBoardに基づき、絵を描く
    procedure DrawBoard();
    //順番を入れ替える(ラベルにも表示する)
    procedure OrderChange();
    //開始(初期化処理)
    procedure GameStart();
    //指定したx,y座標に色(iro=1:白,2:黒)が置けるか
    //裏返す方向はdx,dyで指定する
    //置けるならTrue、置けないならFalseを返す
    function CanPutPiece(x,y, OkuIro, dx,dy: integer): boolean;
    //全ての方向に対してCanPutPieceを呼び出す
    function CanPutPieces(x,y, iro:integer):boolean;
    //指定したx,y座標に色(iro=1:白,2:黒)が置けるなら裏返す
    //置けるならTrue、置けないならFalseを返す
    function ReversePiece(x, y, iro,dx,dy: integer): Boolean;
    //全ての方向に対してReversePieceを呼び出す
    function ReversePieces(x, y, iro: integer): Boolean;
    //全て駒を置いた、又はもう駒を置けないか確認する
    //未だ駒を置ける場合はFalse、置けない場合はTrueを返す
    function CheckPieces():boolean;
    //PCとユーザーの駒の数を集計して表示する
    function PieceCount():boolean;
    //ユーザーの置ける場所が無いか確認する。無ければTrue
    function Cannot_UserPutPiece():boolean;
    //コンピューターの置ける場所が無いか確認する。無ければTrue
    function Cannot_ComPutPiece: boolean;

  public
    { public 宣言 }
  end;

var
  Form1: TForm1;

  //PCの手
  ai:array[0..63] of TPoint = (
    (X:0;Y:0),(X:0;Y:7),(X:7;Y:7),(X:7;Y:0),
    (X:2;Y:2),(X:2;Y:5),(X:5;Y:5),(X:5;Y:2),
    (X:2;Y:0),(X:0;Y:2),(X:0;Y:5),(X:2;Y:7),
    (X:5;Y:7),(X:7;Y:5),(X:7;Y:2),(X:5;Y:0),
    (X:3;Y:1),(X:1;Y:3),(X:1;Y:4),(X:3;Y:6),
    (X:4;Y:6),(X:6;Y:4),(X:6;Y:3),(X:4;Y:1),
    (X:3;Y:0),(X:0;Y:3),(X:0;Y:4),(X:3;Y:7),
    (X:4;Y:7),(X:7;Y:4),(X:7;Y:3),(X:4;Y:0),
    (X:3;Y:2),(X:2;Y:3),(X:2;Y:4),(X:3;Y:5),
    (X:4;Y:5),(X:5;Y:4),(X:5;Y:3),(X:4;Y:2),
    (X:2;Y:1),(X:1;Y:2),(X:1;Y:5),(X:2;Y:6),
    (X:5;Y:6),(X:6;Y:5),(X:6;Y:2),(X:5;Y:1),
    (X:1;Y:0),(X:0;Y:1),(X:0;Y:6),(X:1;Y:7),
    (X:6;Y:7),(X:7;Y:6),(X:7;Y:1),(X:6;Y:0),
    (X:1;Y:1),(X:1;Y:6),(X:6;Y:6),(X:6;Y:1),
    (X:3;Y:3),(X:3;Y:4),(X:4;Y:4),(X:4;Y:3)
  );

implementation

{$R *.fmx}

{ TForm1 }

procedure TForm1.PcCalculate;
var i: Integer;
    dx,dy:integer;
begin
  if OrderPcUser=2 then exit;
  dx:=-1;
  dy:=-1;
  //ai.x,ai.y座標の順に、そこにこまが置けるか調べる
  for i := 0 to 63 do
  begin
    if fBoard[ai[i].X,ai[i].Y]=0 then
    begin
      if CanPutPieces(ai[i].X,ai[i].Y,com_iro) then
      begin
        //こまが置けるのでその座標を変数に保持する
        dx:=ai[i].X;
        dy:=ai[i].Y;
        break;
      end;
    end;
  end;
  if dx=-1 then
  begin
    //こまが置けないのでパスする
    Memo1.Lines.Add('PC:駒を置く場所が無いのでパス');
    Memo1.GoToTextEnd;
  end
  else
  begin
    //こまが置けるのでこまを置く
    fBoard[dx,dy]:=com_iro;
    //裏返す
    ReversePieces(dx,dy,com_iro);
  end;
  OrderChange();
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  GameStart();
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  if OrderPcUser=2 then
    if Cannot_UserPutPiece() then
      OrderChange();
end;

function TForm1.Cannot_ComPutPiece: boolean;
var x,y:integer;
    flag:boolean;
begin
  flag:=false;
  for x := 0 to 7 do
    for y := 0 to 7 do
    begin
      if fBoard[x,y]=0 then
      begin
        if CanPutPieces(x,y,com_iro) then
          flag:=true;
      end;
    end;
  result:=not flag;
end;

procedure TForm1.DrawBoard;
var x,y:integer;
begin
  Image1.Bitmap.Canvas.BeginScene();

  Image1.Bitmap.Canvas.Fill.Color:=TAlphaColorRec.Green;
  Image1.Bitmap.Canvas.Fill.Kind:=TBrushKind.Solid;
  Image1.Bitmap.Canvas.FillRect(
    RectF(0,0,Image1.Bitmap.Width,Image1.Bitmap.Height),
    0,0,[],1
  );

  Image1.Bitmap.Canvas.Stroke.Color:=TAlphaColorRec.White;
  Image1.Bitmap.Canvas.Stroke.Thickness:=6;
  Image1.Bitmap.Canvas.Stroke.Kind:=TBrushKind.Solid;

  for x := 0 to 8 do
  begin
    Image1.Bitmap.Canvas.DrawLine(
      PointF(x*80,0),PointF(x*80,640),1);
  end;
  for y := 0 to 8 do
  begin
    Image1.Bitmap.Canvas.DrawLine(
      PointF(0,y*80),PointF(640,y*80),1);
  end;

  //駒の色を描画する
  for x := 0 to 7 do
  begin
    for y := 0 to 7 do
    begin
      if fBoard[x,y]=1 then
      begin
        Image1.Bitmap.Canvas.Fill.Color:=TAlphaColorRec.White;
        Image1.Bitmap.Canvas.Fill.Kind:=TBrushKind.Solid;
        Image1.Bitmap.Canvas.Stroke.Color:=TAlphaColorRec.Black;
        Image1.Bitmap.Canvas.Stroke.Thickness:=2;
        Image1.Bitmap.Canvas.Stroke.Kind:=TBrushKind.Solid;

        //楕円塗りつぶし
        Image1.Bitmap.Canvas.FillEllipse(
          RectF(x*80+10,y*80+10,x*80+60,y*80+60),1);

        //楕円境界線描画
        Image1.Bitmap.Canvas.DrawEllipse(
          RectF(x*80+10,y*80+10,x*80+60,y*80+60),1);

      end;
      if fBoard[x,y]=2 then
      begin
        Image1.Bitmap.Canvas.Fill.Color:=TAlphaColorRec.Black;
        Image1.Bitmap.Canvas.Fill.Kind:=TBrushKind.Solid;
        Image1.Bitmap.Canvas.Stroke.Color:=TAlphaColorRec.White;
        Image1.Bitmap.Canvas.Stroke.Thickness:=2;
        Image1.Bitmap.Canvas.Stroke.Kind:=TBrushKind.Solid;

        //楕円塗りつぶし
        Image1.Bitmap.Canvas.FillEllipse(
          RectF(x*80+10,y*80+10,x*80+60,y*80+60),1);

        //楕円境界線描画
        Image1.Bitmap.Canvas.DrawEllipse(
          RectF(x*80+10,y*80+10,x*80+60,y*80+60),1);
      end;
    end;
  end;
  Image1.Bitmap.Canvas.EndScene;
  PieceCount();
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  Timer1.Enabled:=False;
  Image1.Bitmap.Width:=640;
  Image1.Bitmap.Height:=640;
  Randomize;
  OrderPcUser:=0;
  GameStart();
end;

procedure TForm1.Image1MouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Single);
var bx,by,ww:integer;
begin
  ww:=trunc(Image1.Width);
  if Image1.Width>Image1.Height then
  begin
    ww:=trunc(Image1.Height);
  end;
  if OrderPcUser=2 then
  begin
    bx:= trunc(x)*8 div ww;
    by:= trunc(y)*8 div ww;
    if (fBoard[bx,by]=0) and (CanPutPieces(bx,by,user_iro)) then
    begin
      fBoard[bx,by]:=user_iro;
      ReversePieces(bx,by,user_iro);
      OrderChange();
    end
    else
    begin
      Memo1.Lines.Add('指定した場所には置けません');
      Memo1.GoToTextEnd;
    end;
  end;
end;


function TForm1.CheckPieces: boolean;
//全て駒を置いた、又はもう駒を置けないか確認する
//未だ駒を置ける場合はFalse、置けない場合はTrueを返す
var flag:boolean;
    x,y:integer;
begin
  flag:=True;
  for x := 0 to 7 do
    for y := 0 to 7 do
      if fBoard[x,y]=0 then flag:=False;
  //盤面が空いていて白も黒も置けない場合が無いかチェック
  if flag=False then
  begin
    if Cannot_UserPutPiece and Cannot_ComPutPiece then
      flag:=True;
  end;
  Result:= flag;
end;

function TForm1.PieceCount: boolean;
//PCとユーザーの駒の数を集計して表示する
var x,y:integer;
    pc,user:integer;
begin
  pc:=0;
  user:=0;
  for x := 0 to 7 do
    for y := 0 to 7 do
    begin
      if fBoard[x,y]=user_iro then
        inc(user)
      else if fBoard[x,y]= com_iro then
        inc(pc);
    end;
  Memo1.Lines.Add('あなた:'+inttostr(user)+'個 PC:'+inttostr(pc)+'個');
  if CheckPieces then
  begin
    Memo1.Lines.Add('ゲーム終了');
    OrderPcUser:=0;
  end;
  Memo1.GoToTextEnd;
  Result:=True;
end;

function TForm1.CanPutPiece(x, y, OkuIro, dx, dy: integer): boolean;
//指定したx,y座標に色(iro=1:白,2:黒)が置けるか
//裏返す方向はdx,dyのみチェックし、置けるならTrue、置けないならFalseを返す
var KaesuIro:Integer;//裏返す対象の色
    Flag:Integer;
    SearchPoint:TPoint;//探索座標
begin
  Result:=False;
  //裏返す対象の色を設定
  KaesuIro:=1;
  if OkuIro=1 then KaesuIro:=2;
  Flag:=0;
  SearchPoint.X:=x+dx;
  SearchPoint.Y:=y+dy;
  while (SearchPoint.X>=0) and (SearchPoint.X<=7) and
        (SearchPoint.Y>=0) and (SearchPoint.Y<=7) do
  begin
    //駒が無かったら終了
    if fBoard[SearchPoint.X,SearchPoint.Y]=0 then Break
    else if fBoard[SearchPoint.X,SearchPoint.Y]=KaesuIro then
       Flag:=1 //ひっくり返す色だった場合はflagを1にする
    else if fBoard[SearchPoint.X,SearchPoint.Y]=OkuIro then
    begin
      //ひっくり返す色が間にあったのでflagを2にする
      if Flag=1 then Flag:=2;
      Break;
    end;
    SearchPoint.X:=SearchPoint.X+dx;
    SearchPoint.Y:=SearchPoint.Y+dy;
  end;
  //駒を置いてひっくり返すことが出来るのでTrueを返す
  if Flag=2 then
  begin
    Result:=True;
  end;
end;

function TForm1.CanPutPieces(x, y, iro: Integer): Boolean;
var Flag:Boolean;
begin
  Flag:=false;
  if CanPutPiece(x,y,iro, 0,-1) then Flag:=True;
  if CanPutPiece(x,y,iro,-1,-1) then Flag:=True;
  if CanPutPiece(x,y,iro,-1, 0) then Flag:=True;
  if CanPutPiece(x,y,iro,-1, 1) then Flag:=True;
  if CanPutPiece(x,y,iro, 0, 1) then Flag:=True;
  if CanPutPiece(x,y,iro, 1, 1) then Flag:=True;
  if CanPutPiece(x,y,iro, 1, 0) then Flag:=True;
  if CanPutPiece(x,y,iro, 1,-1) then Flag:=True;
  Result:=Flag;
end;


function TForm1.ReversePiece(x, y, iro, dx, dy: integer): Boolean;
//指定したx,y座標におければ裏返す。
//置く駒の色(iro)は1白、2黒、指定した方向(dx,dy)を確認する
//置けるならTrue、置けないならFalseを返す
var SearchPoint:TPoint;
begin
  Result:=CanPutPiece(x,y,iro,dx,dy);
  //裏返る場合
  if Result then
  begin
    SearchPoint.X:=x+dx;
    SearchPoint.Y:=y+dy;
    while fBoard[SearchPoint.X,SearchPoint.Y]<>iro do
    begin
      fBoard[SearchPoint.X,SearchPoint.Y]:=iro;
      SearchPoint.X:=SearchPoint.X+dx;
      SearchPoint.Y:=SearchPoint.Y+dy;
    end;
  end;
end;

function TForm1.ReversePieces(x, y, iro: integer): boolean;
var flag:Boolean;
begin
  flag:=False;
  if ReversePiece(x,y,iro, 0,-1) then flag:=True;
  if ReversePiece(x,y,iro,-1,-1) then flag:=True;
  if ReversePiece(x,y,iro,-1, 0) then flag:=True;
  if ReversePiece(x,y,iro,-1, 1) then flag:=True;
  if ReversePiece(x,y,iro, 0, 1) then flag:=True;
  if ReversePiece(x,y,iro, 1, 1) then flag:=True;
  if ReversePiece(x,y,iro, 1, 0) then flag:=True;
  if ReversePiece(x,y,iro, 1,-1) then flag:=True;
  DrawBoard();
  result:=flag;
end;


procedure TForm1.OrderChange;
begin
  if OrderPcUser=1 then OrderPcUser:=2
  else if OrderPcUser=2 then OrderPcUser:=1;
  if OrderPcUser=1 then Memo1.Lines.Add('PCの番');
  if OrderPcUser=2 then Memo1.Lines.Add('あなたの番');
  Memo1.GoToTextEnd;
  if OrderPcUser=1 then Timer1.Enabled:=True;
end;

procedure TForm1.Timer1Timer(Sender: TObject);
begin
  Timer1.Enabled:=False;
  PcCalculate();
end;

procedure TForm1.GameStart;
//開始(初期化処理)
var x,y:integer;
begin
  Memo1.Lines.Clear;
  for x := 0 to 7 do
    for y := 0 to 7 do
      fBoard[x,y]:=0;

  //リバーシの最初の置き方
  fBoard[3,3]:=1;
  fBoard[4,4]:=2;
  fBoard[3,4]:=2;
  fBoard[4,3]:=1;

  OrderPcUser:=Random(2)+1;

  user_iro:=Random(2)+1;
  if user_iro=1 then com_iro:=2
  else com_iro:=1;

  DrawBoard();

  if user_iro=1 then
    Memo1.Lines.Add('あなたの色:白')
  else
    Memo1.Lines.Add('あなたの色:黒');

  if OrderPcUser=1 then
    Memo1.Lines.Add('PCの番')
  else
    Memo1.Lines.Add('あなたの番');

  Memo1.GoToTextEnd;

  if OrderPcUser=1 then Timer1.Enabled:=True;
end;


function TForm1.Cannot_UserPutPiece: boolean;
//ユーザーの置ける場所が無いか確認する。無ければTrue
var x,y:integer;
    flag:boolean;
begin
  flag:=False;
  for x := 0 to 7 do
    for y := 0 to 7 do
    begin
      if fBoard[x,y]=0 then
      begin
        if CanPutPieces(x,y,user_iro) then
          flag:=True;
      end;
    end;
  Result:=not flag;
end;


end.

実行ボタンを押す(WindowsでもAndroidでも動作します)

実行ボタンを押すと、コンパイルして起動します。
クリック、またはタップすると駒を配置できます。
 

Copyright 2021 Mam