Task: Abelian sandpile model




Go: package main

import (
    "fmt"
    "log"
    "os"
    "strings"
)

const dim = 16 

func check(err error) {
    if err != nil {
        log.Fatal(err)
    }
}


func drawPile(pile [][]uint) {
    chars:= []rune(" ░▓█")
    for _, row := range pile {
        line := make([]rune, len(row))
        for i, elem := range row {
            if elem > 3 { 
                elem = 3
            }
            line[i] = chars[elem]
        }
        fmt.Println(string(line))
    }
}



func writePile(pile [][]uint) {
    file, err := os.Create("output.ppm")
    check(err)
    defer file.Close()
    
    fmt.Fprintf(file, "P3\n%d %d\n255\n", dim, dim)
    bcolors := []string{"125 0 25 ", "125 80 0 ", "186 118 0 ", "224 142 0 "}
    var line strings.Builder
    for _, row := range pile {        
        for _, elem := range row {
            line.WriteString(bcolors[elem])
        }
        file.WriteString(line.String() + "\n")
        line.Reset() 
    }
}


func handlePile(x, y uint, pile [][]uint) {
    if pile[y][x] >= 4 {
        pile[y][x] -= 4
        
        
        if y > 0 {
            pile[y-1][x]++
            if pile[y-1][x] >= 4 {
                handlePile(x, y-1, pile)
            }
        }
        if x > 0 {
            pile[y][x-1]++
            if pile[y][x-1] >= 4 {
                handlePile(x-1, y, pile)
            }
        }
        if y < dim-1 {
            pile[y+1][x]++
            if pile[y+1][x] >= 4 {
                handlePile(x, y+1, pile)
            }
        }
        if x < dim-1 {
            pile[y][x+1]++
            if pile[y][x+1] >= 4 {
                handlePile(x+1, y, pile)
            }
        }

        
        
        

        
        
        handlePile(x, y, pile)
    }
}

func main() {
    
    pile := make([][]uint, dim)
    for i := 0; i < dim; i++ {
        pile[i] = make([]uint, dim)
    }

    
    hdim := uint(dim/2 - 1)
    pile[hdim][hdim] = 16
    handlePile(hdim, hdim, pile)
    drawPile(pile)

    
    
    
}







Fortran: module abelian_sandpile_m

  implicit none

  private
  public :: pile

  type :: pile
    
    
    

    integer, allocatable :: grid(:,:)
    integer              :: n(2)

  contains
    procedure :: init
    procedure :: run

    procedure, private :: process_node
    procedure, private :: inside
  end type

contains

  logical function inside(this, i)
    class(pile), intent(in) :: this
    integer,     intent(in) :: i(2)

    inside = ((i(1) > 0) .and. (i(1) <= this%n(1)) .and. (i(2) > 0) .and. (i(2) <= this%n(2)) )
  end function

  recursive subroutine process_node(this, i)
    

    class(pile), intent(inout) :: this
    integer,     intent(in)    :: i(2)
      

    integer :: i0(2,2), j(2), d, k

    
    if (this%grid(i(1),i(2)) >= 4) then
      
      i0 = reshape([1,0,0,1], [2,2])

      
      this%grid(i(1),i(2)) = this%grid(i(1),i(2))-4

      
      do d = 1, 2               
        do k = -1, 1, 2         
          j = i+k*i0(:,d)       
          if (this%inside(j)) this%grid(j(1),j(2)) = this%grid(j(1),j(2)) + 1
        end do
      end do

      
      do d = 1, 2               
        do k = -1, 1, 2         
          j = i+k*i0(:,d)       
          if (this%inside(j)) call this%process_node(j)
        end do
      end do

      
      call this%process_node(i)
    end if
  end subroutine

  subroutine run(this)
    

    class(pile), intent(inout) :: this

    
    call this%process_node(this%n/2)
  end subroutine

  subroutine init(this, nx, ny, h)
    class(pile), intent(out) :: this
    integer,     intent(in)  :: nx, ny
      
    integer,     intent(in)  :: h
      

    this%n = [nx, ny]
    allocate (this%grid(nx,ny), source=0)
    this%grid(nx/2, ny/2) = h
  end subroutine

end module