KusoGame

# 原初
原初、混沌があった。
混沌は凝り固まり…うんこになった！
世界は💩に覆われようとしていた。
その時！🚽が現れた。
💩の世界に現れた🚽は、次の規則に縛られていた。

* **誕生**
💩に隣接する🚽が3つあれば、次の世代🚽が誕生する。

* **生存**
* 🚽に隣接する🚽が2つか3つならば、次の世代でも生存する。

* **過疎**
🚽に隣接する🚽が1つ以下ならば、💩にまみれて死滅する。

* **過密**
🚽に隣接する🚽が4つ以上ならば、過剰により死滅する。

**そう！たんなるライフゲーム！**

# Delphi
[一昨年は、Windows, macOS 向けアプリ](https://qiita.com/pik/items/4759d8597a434c9a691f)を、[昨年は、iOS, Android 向けアプリ](https://qiita.com/pik/items/4e815b0bca8af52f970a)を作ったので、今年は！CUI のアプリケーションも作れちゃうんだ是！ってところを見せつけたいと思います。

では、ご覧ください！
**Windows**
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12977/8a5c19a4-70c6-0958-9c9f-dde6986dcd15.gif" width=400>
**macOS**
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12977/ce8b7832-b8ec-27df-14ea-46364d22279b.gif" width=400>
**Linux (Ubuntu 18.04)**
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12977/a9430e29-2f84-ad73-570b-e8add4968aae.gif" width=400>

Qiita に載せるためフレームレートを落としたのでガックガクですが、本当はもっと綺麗に動きます（いつも言う）
中でも macOS がガックガクなのは僕のスキル不足です（スクリーンキャプチャした mov ファイルから アニメーション gif にする最適解が解らなかった）

# 苦労したところ
プログラムは一瞬で組めたけど、作業時間の95割は各コンソールで💩の絵文字を表示するところ！

**Windows**
cmd.exe ではかなり頑張ったものの絵文字が表示できなかったので、Windows Terminal + PowerShell にして `chcp 65001` したらあっさり表示された！

**macOS**
君は優秀！何もしなくて絵文字出た！
でも [zsh はエスケープシーケンスが特殊](https://stackoverflow.com/questions/30470306/how-can-i-prevent-ansi-escape-sequences-in-my-python-script-from-messing-with-my)なのでイーブン！

**Linux**
WSL でインストールされる Ubuntu を普通に動かすと cmd.exe ベースで動くので絵文字が出ない！
[Windows Terminal](https://www.microsoft.com/ja-jp/p/windows-terminal/9n0dx20hk701#activetab=pivot:overviewtab) を使うと無事絵文字が出た
…Windows Terminal が優秀なのでは？？

# ソース
短いので全文載せちゃう

```pascal
program LifeGameConsole;

uses
  System.SysUtils;

const
  // 盤面の大きさ
  N = 32 - 1;

  // 生死の文字
  STATE: array [Boolean] of String = ('💩', '🚽');

type
  // 盤面の状態を表す２次元配列
  TBoard = array [0.. N, 0.. N] of Boolean;

// 円環型座標取得
function GetPos(const iPos: Integer): Integer;
begin
  Result := iPos;
  if Result < 0 then
    Result := N;
  if Result > N then
    Result := 0;
end;

// 全画面消去
procedure Clear; inline;
begin
  {$IFDEF OSX}
  Writeln('%{'#$1b'[2J%}');
  {$ELSE}
  Writeln(#$1b'c');
  {$ENDIF}
end;

// 原点移動
procedure MoveOrg; inline;
begin
  {$IFDEF OSX}
  Writeln('%{'#$1b'[0;0H%}');
  {$ELSE}
  Writeln(#$1b'[0;0H');
  {$ENDIF}
end;

begin
  var Gen := 0;      // 世代
  var Board: TBoard; // 盤面
  var Next: TBoard;  // 次世代の盤面

  // ランダムで初期化
  Randomize;
  for var Y := 0 to N do
    for var X := 0 to N do
      Board[X, Y] := Random(2) > 0;

  // 画面クリア
  Clear;

  // メイン: 終了は Ctrl + C
  while True do
  begin
    // 原点に移動
    MoveOrg;

    // 世代表示
    Writeln(('Gen: ' + Gen.ToString + StringOfChar(' ', N)).Substring(0, N));
    Inc(Gen);

    // 盤面の表示と次世代判断
    for var Y := 0 to N do
    begin
      for var X := 0 to N do
      begin
        // 盤面表示
        Write(STATE[Board[X, Y]]);

        // 次世代の生死判断
        var C := 0;
        for var Q := Y - 1 to Y + 1 do
        begin
          var V := GetPos(Q);
          for var P := X - 1 to X + 1 do
            Inc(C, Ord(Board[GetPos(P), V]));
        end;

        Next[X, Y] := (C = 3) or ((C = 4) and Board[X, Y]);
      end;

      Writeln;
    end;

    // 世代交代
    Board := Next;

    Sleep(16);
  end;
end.
```

個人的に気に入っているのは次世代の生死判断のところです！
よろしくお願いいたします！

# さいごに
クソ**アプリ**アドベントカレンダーなのに、ゲームを作ってしまった！！！