LoginSignup
5
4

More than 3 years have passed since last update.

C# で書かれたライフゲームを Delphi に移植してみる

Last updated at Posted at 2019-06-26

はじめに

特に目的はないのですが、@yoship1639 さんの 【C#】26行でライフゲームを書いてみる(コンソール表示可能) という記事中のライフゲームを Delphi に移植してみようと思いました。

使用した Delphi は 10.3 Rio です。無償版の Community Edition でももちろん動作します。

ライフゲームを書く

操作はオリジナルと同じです。

  • コンソール表示可能
  • [Enter]で次世代に移行
  • X Yでフィールド[Y, X]にセルの設置
  • qで終了

ソースコード

基本的な機能しか使っていないので Windows, macOS, Linux のいずれでも動作すると思います。オリジナルの C# のソースコードと見比べてみるのも楽しいと思います。

LifeGame.pas
program LifeGame;

{$APPTYPE CONSOLE}

uses
  System.SysUtils;

const
  W = 10; // ヨコ
  H = 10; // タテ
  CELLSTR: array [Boolean] of string = (' .', ' o');

var
  f, pf: array [0..Pred(H), 0..Pred(W)] of Boolean; // フィールド

begin
  repeat
    var buf: string;
    Readln(buf);
    var sc: TArray<string> := buf.Split([' ']);
    if Length(sc) = 0 then
    begin
      Writeln;
      for var y:= 0 to Pred(H) do
      begin
        WriteLn;
        for var x := 0 to Pred(W) do
        begin
          var c := 0;
          for var yy := Pred(y) to Succ(y) do
            for var xx := Pred(x) to Succ(x) do
            begin
              if (yy < 0) or (yy >= H) or (xx < 0) or (xx >= W) or ((x = xx) and (y = yy)) then
                Continue;
              Inc(c, Ord(pf[yy, xx]));
            end;
          f[y, x] := ((c = 2) and pf[y, x]) or (c = 3);
          Write(CELLSTR[f[y, x]]);
        end;
      end;
      pf := f;
    end
    else if Length(sc) >= 2 then
      pf[sc[1].ToInteger, sc[0].ToInteger] := True
    else if sc[0] = 'q' then
      Break;
  until False;
end.

48 行でしたね。空行とか削ればもう少し短くなりますが、読みやすさ優先で。フィールドの型を Boolean にしたくらいでほぼベタ移植です。

ソースコード (その2)

コンソール API を使ってみました。

LifeGame.pas
program LifeGame;

{$APPTYPE CONSOLE}

{$IFDEF MSWINDOWS}
  {$DEFINE USECONSOLEAPI}
{$ENDIF}

uses
  {$IFDEF USECONSOLEAPI}
  Winapi.Windows,
  {$ENDIF}
  System.SysUtils;

const
  W = 10; // ヨコ
  H = 10; // タテ
  CELLSTR: array [Boolean] of string = (' .', ' o');

var
  f, pf: array [0..Pred(H), 0..Pred(W)] of Boolean; // フィールド

begin
  {$IFDEF USECONSOLEAPI}
  var stdout := GetStdHandle(STD_OUTPUT_HANDLE);
  var cd: TCoord := Default(TCoord); // (X:0; Y:0)
  {$ENDIF}
  repeat
    var buf: string;
    Readln(buf);
    var sc: TArray<string> := buf.Split([' ']);
    if Length(sc) = 0 then
    begin
      {$IFDEF USECONSOLEAPI}
      SetConsoleCursorPosition(stdout, cd);
      {$ELSE}
      Writeln;
      {$ENDIF}
      for var y:= 0 to Pred(H) do
      begin
        WriteLn;
        for var x := 0 to Pred(W) do
        begin
          var c := 0;
          for var yy := Pred(y) to Succ(y) do
            for var xx := Pred(x) to Succ(x) do
            begin
              if (yy < 0) or (yy >= H) or (xx < 0) or (xx >= W) or ((x = xx) and (y = yy)) then
                Continue;
              Inc(c, Ord(pf[yy, xx]));
            end;
          f[y, x] := ((c = 2) and pf[y, x]) or (c = 3);
          Write(CELLSTR[f[y, x]]);
        end;
      end;
      {$IFDEF USECONSOLEAPI}
      SetConsoleCursorPosition(stdout, cd);
      Write(StringOfChar(' ', W));
      SetConsoleCursorPosition(stdout, cd);
      {$ELSE}
      Writeln;
      {$ENDIF}
      pf := f;
    end
    else if Length(sc) >= 2 then
      pf[sc[1].ToInteger, sc[0].ToInteger] := True
    else if sc[0] = 'q' then
      Break;
  until False;
end.

フィールドが同じ位置に描画されるので変化を確認しやすいと思います。

おわりに

実はライフゲーム(Conway's Game of Life) も Pascal も 1970 年生まれなんですよね。
上記コードをさらに 標準 Pascal に移植しようとしたら文字列がないのでそこそこ大変なのでやめました (w

なお、VCL や FireMonkey を使ったライフゲームは DocWiki にサンプルがありますので、こちらも試してみてください。
image.png

See also:

5
4
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
4