【雑記】可読性がそれなりにある短いライフゲームを

先日qiitaを散歩していると、短い行数で且つそれなりの可読性があるライフゲームを作るという記事を見かけたました。ちょっと古い記事ですが。

【C#】26行でライフゲームを書いてみる(コンソール表示可能) - Qiita
本記事は C# その2 Advent Calender2018 17日目の記事です。はじめにこんにちは@yoship1639です。普段は個人ゲーム開発を行っています。本記事は内容は技術的です…

これ、LINQ使ったらもうちょっといけるんじゃね?ということでやってみました。

れぎゅれーしょん

  • ライフゲーム
  • C#
  • それなりの可読性
  • 縦横ともに一画面になんとなく収まるぐらい
  • エラーハンドリングは考えない

ソース

class Program {
  const int kWidth = 10;
  const int kHeight = 10;

  public static void Main(string[] args) {
    var cells = (new bool[kHeight + 2]).Select(_ => (new bool[kWidth + 2]).ToList()).ToList();
    var accessor = new []{(-1, -1), (-1, 0), (-1, 1), (0, -1), (0, 1), (1, -1), (1, 0), (1, 1)};
    int CountOf(int x, int y) => accessor.Aggregate(0, (l, set) => l + (cells[set.Item1 + y][set.Item2 + x] ? 1 : 0));
    bool IsAlive(bool alive, int count) => (!alive && count == 3) || (alive && (count == 2 || count == 3));
    string[] sc = null;
    while ((sc = System.Console.ReadLine().Split(' '))[0] != "q") {
      if (sc.Length == 2) { cells[int.Parse(sc[1]) + 1][int.Parse(sc[0]) + 1] = true; }
      else {
        cells = cells.Select((line, y) > y == 0 || y == kHeight + 1 ? line :
          line.Select((alive, x) > x == 0 || x == kWidth + 1 ? false : IsAlive(alive, CountOf(x, y))).ToList()).ToList();
        System.Console.WriteLine(string.Join('\n', cells.Skip(1).Take(kHeight).Select(y => string.Join("", y.Skip(1).Take(kWidth).Select(x => x ? '■' : '□')))));
      }
    }
  }
}

 

概要

標準入力からとってくるところは元記事をそのまま使っています。エラーハンドリング、異常値チェックなども無しで踏襲しています。

とりあえず二次元配列には消えてもらう

二次元配列はLINQが微妙なので、ListのListにしています。

とりあえず番兵

まあ、あった方がいいよね。

周囲を数えるのはインデックスを用意

Aggregateで畳込めるしインデックスの配列を用意しています。Enumerable.Rangeで3×3のEnumerableを用意してもよかったかもしれません。

入力周りは元のまま

元のまま使わせてもらっています。

次世代へはLINQで1式で

番兵以外は周囲の生存数を数えて、生き死に判定して新しいリストを再代入しています。

SelectではなくForEachにして、直接Listの中を書き換えると番兵外しの三項条件演算子がSkip().Take()に変えられると思います。そっちの方がわかりやすかったかも。

まとめ

もっと詰め込みに詰め込めばまだまだ減らせそうですが、人間にはちょっと前衛的すぎることになりそうですので、個人的にはこの辺がギリギリラインではと勝手に思っています。

タイトルとURLをコピーしました