Created
March 7, 2020 11:45
-
-
Save peterhellberg/3c5b30465a258f6b688a8f11955b12ba to your computer and use it in GitHub Desktop.
Sprator using gfx inspired by https://github.com/yurkth/sprator
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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
Seed 0 to 2047: