Skip to content

Instantly share code, notes, and snippets.

@fogleman
Created February 2, 2016 20:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fogleman/6e6518da6258e071dcdd to your computer and use it in GitHub Desktop.
Save fogleman/6e6518da6258e071dcdd to your computer and use it in GitHub Desktop.
Diffusion-Limited Aggregation
package main
import (
"fmt"
"image"
"image/color"
"image/png"
"math/rand"
"os"
)
type Model struct {
W, H int
Points []int
Grid []bool
Glue []bool
Size int
}
func NewModel(w, h, count int) *Model {
model := Model{}
model.W = w
model.H = h
model.Points = make([]int, count)
model.Grid = make([]bool, w*h)
model.Glue = make([]bool, w*h)
model.Size = 0
return &model
}
func (model *Model) Randomize() {
for i := range model.Points {
model.Points[i] = model.RandomPoint()
}
}
func (model *Model) Add(x, y int) {
model.Size++
model.Grid[y*model.W+x] = true
for dx := -1; dx <= 1; dx++ {
for dy := -1; dy <= 1; dy++ {
model.Set(x+dx, y+dy)
}
}
}
func (model *Model) Set(x, y int) {
if x < 0 || y < 0 || x >= model.W || y >= model.H {
return
}
model.Glue[y*model.W+x] = true
}
func (model *Model) RandomPoint() int {
n := model.W * model.H
for {
i := rand.Intn(n)
if !model.Glue[i] {
return i
}
}
}
func (model *Model) Step() int {
result := 0
for i, point := range model.Points {
x := point % model.W
y := point / model.W
if rand.Intn(2) == 0 {
if rand.Intn(2) == 0 {
x--
if x < 0 {
x += model.W
}
} else {
x++
if x >= model.W {
x -= model.W
}
}
} else {
if rand.Intn(2) == 0 {
y--
if y < 0 {
y += model.H
}
} else {
y++
if y >= model.H {
y -= model.H
}
}
}
point = y*model.W + x
model.Points[i] = point
if model.Glue[point] {
model.Add(x, y)
model.Points[i] = model.RandomPoint()
result++
}
}
return result
}
func (model *Model) Render(m int) *image.Paletted {
w := model.W
h := model.H
var palette []color.Color
palette = append(palette, color.RGBA{255, 255, 255, 255})
palette = append(palette, color.RGBA{0, 0, 0, 255})
im := image.NewPaletted(image.Rect(0, 0, w*m, h*m), palette)
for point, value := range model.Grid {
if !value {
continue
}
x := point % model.W
y := point / model.W
for dy := 0; dy < m; dy++ {
for dx := 0; dx < m; dx++ {
im.SetColorIndex(x*m+dx, y*m+dy, 1)
}
}
}
return im
}
func main() {
w := 1024
h := 1024
n := 1000
model := NewModel(w, h, n)
for x := 0; x < w; x++ {
model.Add(x, h/2)
}
model.Randomize()
i := 0
for model.Size < 20000 {
if model.Step() > 0 {
fmt.Println(i, model.Size)
}
i++
}
im := model.Render(2)
file, err := os.Create("out.png")
if err != nil {
panic(err)
}
defer file.Close()
png.Encode(file, im)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment