Skip to content

Instantly share code, notes, and snippets.

@mrxinu
Forked from peterhellberg/gfx-sprator.go
Created November 11, 2020 12:57
Show Gist options
  • Save mrxinu/24412603fd5f8e18bb7b122523c07a1f to your computer and use it in GitHub Desktop.
Save mrxinu/24412603fd5f8e18bb7b122523c07a1f to your computer and use it in GitHub Desktop.
Sprator using gfx inspired by https://github.com/yurkth/sprator
package main
import (
"flag"
"image"
"image/color"
"time"
"github.com/peterhellberg/gfx"
)
// Sprator algorithm as described at
// https://github.com/yurkth/sprator
//
// 1. Generate 4x8 white noise.
// 2. Change the state according to the following rules.
// - Any live cell with two or three neighbors survives.
// - Any dead cell with one or less live neighbors becomes a live cell.
// - All other live cells die in the next generation. Similarly, all other dead cells stay dead.
// 3. Repeat steps 2 several times.
// 4. Flip and add a outline, complete!
func main() {
var seed int64
var variant string
flag.Int64Var(&seed, "seed", time.Now().Unix(), "Seed value to use for the state")
flag.StringVar(&variant, "variant", "random", "Variant of the initial state [random, simplex]")
flag.Parse()
var state State
switch variant {
case "simplex":
state = SimplexState(seed)
default:
variant = "random"
state = RandomState(seed)
}
for i := 0; i < 2; i++ {
state = state.Next()
}
dst := gfx.NewImage(10, 10)
bc := gfx.BlockColors[int(seed)%len(gfx.BlockColors)]
t := gfx.ColorTransparent
for x := 1; x < 5; x++ {
for y := 1; y < 9; y++ {
if state.At(x-1, y-1) {
dst.Set(x, y, bc.Light)
dst.Set(5+5-x-1, y, bc.Light)
} else {
dst.Set(x, y, t)
dst.Set(5+5-x-1, y, t)
}
}
}
out := gfx.NewImage(10, 10)
for x := 0; x < 10; x++ {
for y := 0; y < 10; y++ {
if c := countNeighborhood(dst, x, y, bc.Light); c > 0 {
out.Set(x, y, bc.Dark)
}
}
}
gfx.DrawOver(out, out.Bounds(), dst, gfx.ZP)
src := gfx.NewScaledImage(out, 10)
fn := gfx.Sprintf("/tmp/gfx-sprator-%06d-%s.png", seed, variant)
gfx.Log("Saving generated sprator to %s", fn)
gfx.SavePNG(fn, src)
}
// ExampleState returns the starting state in the
// original README on https://github.com/yurkth/sprator
//
// ░░░░░░░░░░ ░░░░░░░░░░ ░░░░░░░░░░
// ░░▒▒▒▒▓▓▒▒ ░░▓▓▓▓▒▒▓▓ ░░▒▒▒▒▒▒▒▒
// ░░▓▓▒▒▒▒▒▒ ░░▒▒▒▒▓▓▓▓ ░░▓▓▒▒▒▒▓▓
// ░░▒▒▓▓▒▒▓▓ ░░▒▒▒▒▒▒▒▒ ░░▓▓▓▓▓▓▓▓
// ░░▒▒▓▓▓▓▒▒ ➤ ░░▒▒▓▓▒▒▒▒ ➤ ░░▓▓▒▒▓▓▓▓
// ░░▓▓▒▒▒▒▒▒ ➤ ░░▒▒▒▒▒▒▓▓ ➤ ░░▓▓▓▓▓▓▒▒
// ░░▓▓▒▒▓▓▒▒ ░░▒▒▒▒▒▒▒▒ ░░▓▓▓▓▓▓▓▓
// ░░▒▒▓▓▒▒▓▓ ░░▒▒▒▒▒▒▒▒ ░░▓▓▓▓▓▓▓▓
// ░░▒▒▒▒▒▒▓▓ ░░▓▓▓▓▓▓▒▒ ░░▒▒▓▓▒▒▓▓
// ░░░░░░░░░░ ░░░░░░░░░░ ░░░░░░░░░░
//
func ExampleState() State {
return State(0x8a516a14)
}
func RandomState(seed int64) (state State) {
gfx.RandSeed(seed)
for x := 0; x < 4; x++ {
for y := 0; y < 8; y++ {
state.Set(x, y, gfx.RandIntn(2) == 0)
}
}
return
}
func SimplexState(seed int64) (state State) {
simplex := gfx.NewSimplexNoise(seed)
for x := 0; x < 4; x++ {
for y := 0; y < 8; y++ {
state.Set(x, y, simplex.Noise2D(float64(x), float64(y)) > 0)
}
}
return
}
type State uint32
func (s State) At(x, y int) bool {
return hasBit(s, (y*4)+x)
}
func (s *State) Set(x, y int, b bool) {
if b {
*s = setBit(*s, (y*4)+x)
} else {
*s = clearBit(*s, (y*4)+x)
}
}
func (s State) Next() State {
var next State
for x := 0; x < 4; x++ {
for y := 0; y < 8; y++ {
n := s.Neighborhood(x, y)
if s.At(x, y) {
next.Set(x, y, n == 2 || n == 3)
} else {
next.Set(x, y, n <= 1)
}
}
}
return next
}
func (s State) Neighborhood(x, y int) int {
var n int
if y >= 1 && s.At(x, y-1) {
n++
}
if y <= 6 && s.At(x, y+1) {
n++
}
if x >= 1 && s.At(x-1, y) {
n++
}
if x <= 2 && s.At(x+1, y) {
n++
}
return n
}
func setBit(s State, pos int) State {
s |= (1 << pos)
return s
}
func clearBit(s State, pos int) State {
return s &^ (1 << pos)
}
func hasBit(s State, pos int) bool {
return (s & (1 << pos)) > 0
}
func countNeighborhood(src image.Image, x, y int, c color.Color) int {
var n int
e := func(c1, c2 color.Color) bool {
c1r, c1g, c1b, c1a := c1.RGBA()
c2r, c2g, c2b, c2a := c2.RGBA()
return c1r == c2r && c1g == c2g && c1b == c2b && c1a == c2a
}
if e(src.At(x, y-1), c) {
n++
}
if e(src.At(x, y+1), c) {
n++
}
if e(src.At(x-1, y), c) {
n++
}
if e(src.At(x+1, y), c) {
n++
}
return n
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment