Edited at

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


はじめに

特に目的はないのですが、@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