Wireworld
Conway's Game of Life
It is capable of doing sophisticated computations with appropriate programs
(it is actually Turing complete),
and is much simpler to program for.

A Wireworld arena consists of a Cartesian grid of cells,
each of which can be in one of four states.
All cell transitions happen simultaneously.

The cell transition rules are this:



 Input State

 Output State

 Condition


 empty

 empty




 electron head 

 electron tail 




 electron tail 

 conductor




 conductor

 electron head 

 if 1 or 2 cells in the neighborhood of the cell are in the state “electron head”


 conductor

 conductor

 otherwise



Task

Create a program that reads a Wireworld program from a file and displays an animation of the processing. Here is a sample description file (using "H" for an electron head, "t" for a tail, "." for a conductor and a space for empty) you may wish to test with, which demonstrates two cycle-3 generators and an inhibit gate:

tH.........
.   .
   ...
.   .
Ht.. ......

While text-only implementations of this task are possible, mapping cells to pixels is advisable if you wish to be able to display large designs. The logic is not significantly more complex.




program Wireworld
  implicit none
 
  integer, parameter :: max_generations = 12
  integer :: nrows = 0, ncols = 0, maxcols = 0
  integer :: gen, ierr = 0
  integer :: i, j
  character(1), allocatable :: cells(:,:)
  character(10) :: form, sub
  character(80) :: buff
 
! open input file
  open(unit=8, file="wwinput.txt")
 
! find numbers of rows and columns in data
  do 
    read(8, "(a)", iostat=ierr) buff
    if(ierr /= 0) exit
    nrows = nrows + 1
    ncols = len_trim(buff)
    if(ncols > maxcols) maxcols = ncols
  end do
 
! allcate enough space to hold the data  
  allocate(cells(0:nrows+1, 0:maxcols+1))
  cells = " "
 
! load data
  rewind(8)
  do i = 1, nrows
    read(8, "(a)", iostat=ierr) buff
    if(ierr /= 0) exit
    do j = 1, maxcols
      cells(i, j) = buff(j:j)
    end do
  end do
  close(8)
 
! calculate format string for write statement
  write(sub, "(i8)") maxcols
  form = "(" // trim(adjustl(sub)) // "a1)"
 
  do gen = 0, max_generations
    write(*, "(/a, i0)") "Generation ", gen
    do i = 1, nrows
      write(*, form) cells(i, 1:maxcols)
    end do
    call nextgen(cells)
  end do
  deallocate(cells)
 
 contains
 
  subroutine Nextgen(cells)
    character, intent(in out) :: cells(0:,0:)
    character :: buffer(0:size(cells, 1)-1, 0:size(cells, 2)-1)
    integer :: i, j, h
 
     buffer = cells   ! Store current status
     do i = 1, size(cells, 1)-2
        do j = 1, size(cells, 2)-2
          select case (buffer(i, j))
            case(" ")
              ! no Change
 
            case("H")
              ! If a head change to tail  
              cells(i, j) = "t"
 
            case("t")
              ! if a tail change to conductor
              cells(i, j) = "."
 
            case (".")
              ! Count number of electron heads in surrounding eight cells.
              ! We can ignore that fact that we count the centre cell as
              ! well because we already know it contains a conductor.
              ! If surrounded by 1 or 2 heads change to a head
              h = sum(count(buffer(i-1:i+1, j-1:j+1) == "H", 1)) 
              if(h == 1 .or. h == 2) cells(i, j) = "H"
          end select       
        end do
     end do
  end subroutine Nextgen
end program Wireworld