18
16

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

ワンライナーでライフゲーム

Last updated at Posted at 2015-09-01

ターミナルのカーソル位置を移動する方法を知って、ターミナルで動くものを書いてみたくなったのでライフゲームを書いてみました。

ライフゲームの詳細は Wikipedia 参照。
この解説動画も分かりやすくて面白いです! → ライフゲームの世界1【複雑系】

コード

lifegame
ruby -e 'h,w=`stty size`.split.map &:to_i;trap 2,:exit;f=h.times.map{w.times.map{rand<0.5}};loop{print f.map{|r|r.map{|e|e ??*:" "}*""}*?\n+"\e[;H";f=h.times.map{|y|w.times.map{|x|n=(-1..1).inject(0){|s,i|s+(-1..1).count{|j| f[(y+i)%h][(x+j)%w]}};f[y][x]??a[n-4]:n==3}};sleep 0.05}'

少し見やすくするとこんな感じです。

lifegame.rb
h,w =`stty size`.split.map &:to_i #ターミナルの行数、列数を取得
trap 2,:exit; # Ctrl + Cしたら終了
f = h.times.map{w.times.map{rand<0.5}} #ターミナルと同じサイズの配列にランダムな真偽値を入れる
loop{
  print f.map{|r|r.map{|e|e ??*:" "}*""}*?\n+"\e[1;1H" #ターミナルに出力して1行目に戻る
  f=h.times.map{|y|
    w.times.map{|x|
      n=(-1..1).inject(0){|s,i|s+(-1..1).count{|j| f[(y+i)%h][(x+j)%w]}} #周囲3×3マスの生存セルの数 (自分を含む)
      f[y][x]??a[n-4]:n==3 #周囲のセルの数によって生死が決まる (生きてたら2つor3つで生存, 死んでたら3つで復活)
    }
  }
  sleep 0.05
}

終了はControl + Cです。
Macのターミナルで動作確認しましたが、他では動かないかもしれません。

普通に書いたライフゲーム をできる限り短くしたものです。
普通に書いたほうはステータス行を作ってターン数や生存セル数を表示したりしてます。
(ちなみに間違えてgistに匿名で送信してしまったので編集も削除もできません。)

1セルずつ描画する方法もやってみましたが重かったので一気に描画することにしました。

追記

配列作成の処理を統一したりして少し縮まりました。

lifegame
ruby -e 'h,w,f=`stty size`.split.map &:to_i;loop{f=h.times.map{|y|w.times.map{|x|next rand<0.5 if !f;n=(a=-1..1).inject(0){|s,i|s+a.count{|j|f[(y+i)%h][(x+j)%w]}};f[y][x]??a[n-4]:n==3}};print f.map{|r|r.map{|e|e ??*:" "}*""}*?\n+"\e[;H";sleep 0.05}'
lifegame.rb
h,w,f=`stty size`.split.map &:to_i
loop{
  f=h.times.map{|y|
    w.times.map{|x|
      next rand<0.5 if !f
      n=(a=-1..1).inject(0){|s,i|s+a.count{|j|f[(y+i)%h][(x+j)%w]}}
      f[y][x]??a[n-4]:n==3
    }
  }
  print f.map{|r|r.map{|e|e ??*:" "}*""}*?\n+"\e[;H"
  sleep 0.05
}

任意の場所にカーソルを移動する方法

\e[n;mHnmの部分を書き換えて出力するとカーソルが移動します。
例えば、\e[1;2Hで1行目の2列目(2文字目)に移動します。
その後の文字列でカーソル位置の文字列が書き換えられます。

数値は1から始まります。
数値が1未満だったり省略して\e[;2Hのようになっている場合は1になります。

文字を書き換えてみるテスト.rb
puts "\e[2J" #画面消去
print "\e[;H" #画面左上に移動

puts "XXX"
puts "XOX ←3秒後に「O」を「X」に書き換えます。"
puts "XXX"

sleep 3

puts "\e[2;2HX" #「O」を「X」に書き換え
puts

エスケープシーケンスでもっとめんどくさいことをする場合はcursesライブラリを使います。

参考

ANSI escape code - Wikipedia
ライフゲーム - Wikipedia
curses による端末制御
ターミナルでゆのっちが降る

18
16
0

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
18
16

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?