まずは

できそうなことからやってみます.2020/04~

ライフゲーム(fortran)

Fortranの勉強し始めたとき,遊んだライフゲームを書いてみます.


まずは,

ライフゲームとは

1970年にケンブリッジ大のコンウェイが発明したセルオートマトン.初期条件を与えれば一定の規則で世代が進み,を表すセルが更新されていきます(参照 ライフゲーム - Wikipedia1.1974年にはTime誌が「ライフゲイムの大群が数百万ドルの貴重なコンピュータ時間を食ってしまっている」と苦言を呈したほど流行ったらしいです2

Fortranで実装,gnuplotで描画しました.

代表的なパターン

有名なパターンをいくつか紹介します.白いセルが「生(1)」を,黒いセルが「死(0)」を表しています.個人的にはたった5つの「生」でスタートし,煩雑な模様を展開するR pentominoが面白いです.

f:id:shino424:20200320164411g:plain
例1:Nebula

f:id:shino424:20200325144737g:plain
例2:R pentomino

f:id:shino424:20200320164933g:plain
例3:Glider(周期境界条件

f:id:shino424:20200325144729g:plain
例4:Puffer train

ソースコード

プログラムはQiita記事を参考にさせて頂きました3

描画領域を正方形にして,初期条件を乱数ではなく,Excelで作成した init_field.txt から読み込ませています. また,境界の条件はcshifteoshiftを使い分けて,固定境界か周期境界かを選べます.Gliderとかは周期境界にしました.

Fortran90/95

! Conway's Game of Life

  module lifegame
      implicit none
      integer :: n
      integer, allocatable :: field( : , :  )
      integer, allocatable :: neighbors( : , :  )    
  contains

      subroutine init_field( size )
          integer, intent( in ) :: size
          integer i
          integer ios
          n = size
          allocate( field( n, n ) )
          allocate( neighbors( n, n ) )
          open(10, file="init_field.txt")
          do i=0, n
              read(10, *, iostat=ios) field
              if (ios .lt. 0) exit
          end do
          close(10)
      end subroutine init_field

      subroutine print_field()
          implicit none
          integer :: i
          do i = 1, n
            write (*, '( * ( i0, :, " " ) )' ) field( :, i )
          end do
      end subroutine print_field

      subroutine one_epoch
          implicit none
          integer :: dx, dy, i
          neighbors = 0
          do concurrent ( dx = -1 : 1, dy = -1 : 1 )
            ! 周期境界条件(cshift)
              neighbors = neighbors + cshift( cshift(field, dx, 1), dy, 2 )
            ! 固定境界条件(eoshift, 境界の外は死(0))
            ! neighbors = neighbors + eoshift( eoshift(field, dx, 0, 1), dy, 0, 2 ) 
          end do
          where( neighbors == 3 )
              field = 1
          elsewhere( neighbors == 4 )
              field = field
          elsewhere
              field = 0
          endwhere
      end subroutine one_epoch

  end module lifegame


  ! MainProgram
  program main
      use lifegame
      implicit none
      integer :: epoch, size
      integer :: i

      write( *, * ) "# size?"
      read( *, * ) size
      write( *, * ) "# epoch?"
      read( *, * ) epoch

      call init_field( size )
      call print_field

      do i = 1, epoch
          call one_epoch
          write (*, *)
          call print_field
      end do

      stop
  end program main



Excelファイルはこんな感じで作成して,テキストファイル(init_field.txt)に出力しました. 以下はGliderの例.

f:id:shino424:20200418175757p:plain



以下,gnuplotでgifアニメを作成します. gnuplot

reset

set term gif animate size 560, 400    # 出力をgifアニメに設定
set output "field.gif"                # 出力ファイル名

set size square
set nozeroaxis
set notics
unset colorbox

set palette grey                      # gray0 = 黒
set title font "Arial,30"
set key below

do for [n=0:1000:1] {
   plot "field.log" index n matrix with image title sprintf("generation %d", n)
}


おわりに

昨年から上記のライフゲームのプログラムとか

Fortran90/95プログラミング

Fortran90/95プログラミング

でやんわりとFortranの勉強始めました.


参考