diff --git a/data/data.go b/data/data.go index d7e5e00..ec757b3 100644 --- a/data/data.go +++ b/data/data.go @@ -2,6 +2,7 @@ package data import ( "embed" + "encoding/json" "image" "log" "path/filepath" @@ -9,10 +10,12 @@ import ( ) // FS is our exported FS. -//go:embed images/* +//go:embed images/* mapping.json var fs embed.FS var Images map[string]image.Image +var Mapping map[string][]string +var Tiles []string func Init() { Images = make(map[string]image.Image) @@ -37,4 +40,19 @@ func Init() { Images[name] = img } } + // Load mapping. + f, err := fs.Open("mapping.json") + if err != nil { + log.Fatal(err) + } + d := json.NewDecoder(f) + err = d.Decode(&Mapping) + if err != nil { + log.Fatal(err) + } + + // Add all types to the common map. + for k := range Mapping { + Mapping[""] = append(Mapping[""], k) + } } diff --git a/data/images/deep-water.png b/data/images/deep-water.png new file mode 100644 index 0000000..3495649 Binary files /dev/null and b/data/images/deep-water.png differ diff --git a/data/images/dirt.png b/data/images/dirt.png new file mode 100644 index 0000000..4591081 Binary files /dev/null and b/data/images/dirt.png differ diff --git a/data/images/flowers.png b/data/images/flowers.png new file mode 100644 index 0000000..29fc243 Binary files /dev/null and b/data/images/flowers.png differ diff --git a/data/mapping.json b/data/mapping.json new file mode 100644 index 0000000..f00a956 --- /dev/null +++ b/data/mapping.json @@ -0,0 +1,40 @@ +{ + "deep-water": [ + "water", + "deep-water" + ], + "water": [ + "sand", + "deep-water", + "water" + ], + "sand": [ + "sand", + "water", + "dirt" + ], + "dirt": [ + "dirt", + "grass", + "sand" + ], + "grass": [ + "dirt", + "grass", + "saplings", + "flowers" + ], + "flowers": [ + "grass", + "saplings" + ], + "saplings": [ + "grass", + "saplings", + "trees" + ], + "trees": [ + "saplings", + "trees" + ] +} \ No newline at end of file diff --git a/gobl.go b/gobl.go index 4e66b46..945732e 100644 --- a/gobl.go +++ b/gobl.go @@ -12,7 +12,7 @@ func main() { Exec("./gwfc") Task("watch"). - Watch("internal/*/*.go", "data/*.go", "data/images/*"). + Watch("internal/*/*.go", "data/*", "data/images/*"). Signaler(SigQuit). Run("build"). Run("run") diff --git a/internal/gwfc/Game.go b/internal/gwfc/Game.go index e637b9c..cb7776d 100644 --- a/internal/gwfc/Game.go +++ b/internal/gwfc/Game.go @@ -1,9 +1,11 @@ package gwfc import ( + crand "crypto/rand" + "encoding/binary" "gwfc/data" + "log" "math/rand" - "time" "github.com/hajimehoshi/ebiten/v2" "golang.org/x/exp/slices" @@ -14,6 +16,7 @@ type Game struct { Images map[string]*ebiten.Image Map Map cTiles [][2]int + maxSources int stepRate int tickDelay int tileWidth int @@ -24,11 +27,17 @@ func (g *Game) Init() { ebiten.SetWindowSize(1280, 720) ebiten.SetWindowResizable(true) - rand.Seed(time.Now().UnixMilli()) + var b [8]byte + _, err := crand.Read(b[:]) + if err != nil { + log.Fatal(err) + } + rand.Seed(int64(binary.LittleEndian.Uint64(b[:]))) g.Images = make(map[string]*ebiten.Image) g.stepRate = 0 + g.maxSources = 1 data.Init() @@ -50,9 +59,10 @@ func (g *Game) ResetMap() { g.Map.Size(w/2/g.tileWidth, h/2/g.tileHeight) g.cTiles = nil - t := rand.Intn(8) + t := 1 + rand.Intn(g.maxSources) for i := 0; i < t; i++ { - g.cTiles = append(g.cTiles, [2]int{rand.Intn(g.Map.w), rand.Intn(g.Map.h)}) + x, y := rand.Intn(g.Map.w), rand.Intn(g.Map.h) + g.cTiles = append(g.cTiles, [2]int{x, y}) } } @@ -60,24 +70,44 @@ func (g *Game) getRandomTile(s []string) string { return s[rand.Intn(len(s))] } -func (g *Game) iterFunc(c [2]int, t *Tile) { - types := g.Map.GetAdjacentTypes(c[0], c[1]) - t.processed = true - if len(types) == 0 { - t.tile = g.getRandomTile([]string{"sand", "water", "grass", "saplings", "trees"}) - } else if slices.Contains(types, "water") { - t.tile = g.getRandomTile([]string{"water", "sand"}) - } else if slices.Contains(types, "sand") { - t.tile = g.getRandomTile([]string{"sand", "water", "grass"}) - } else if slices.Contains(types, "grass") { - t.tile = g.getRandomTile([]string{"saplings", "grass", "sand"}) - } else if slices.Contains(types, "trees") { - t.tile = g.getRandomTile([]string{"trees", "saplings", "grass"}) - } else if slices.Contains(types, "saplings") { - t.tile = g.getRandomTile([]string{"trees", "saplings", "grass"}) - } else { - t.tile = g.getRandomTile([]string{"sand", "water", "grass", "saplings", "trees"}) +func (g *Game) getMatchingValidAdjacentTiles(x, y int, s string) []string { + neighbors := make([]*Tile, 0) + possible := data.Mapping[""] + for x2 := -1; x2 < 2; x2++ { + for y2 := -1; y2 < 2; y2++ { + if (x2 == -1 && y2 == -1) || (x2 == 1 && y2 == 1) || (x2 == -1 && y2 == 1) || (x2 == 1 && y2 == -1) || (x2 == 0 && y2 == 0) { + continue + } + + t := g.Map.Get(x+x2, y+y2) + if t != nil { + neighbors = append(neighbors, t) + } + } } + + for _, t := range neighbors { + var temp []string + for _, s := range possible { + if slices.Contains(data.Mapping[t.tile], s) { + + temp = append(temp, s) + } + } + possible = temp + } + + if len(possible) == 0 { + possible = data.Mapping[""] + } + + return possible +} + +func (g *Game) iterFunc(c [2]int, t *Tile) { + types := g.getMatchingValidAdjacentTiles(c[0], c[1], t.tile) + t.processed = true + t.tile = g.getRandomTile(types) } // Update updates the game state. diff --git a/internal/gwfc/Map.go b/internal/gwfc/Map.go index 8f9f1fb..b68b708 100644 --- a/internal/gwfc/Map.go +++ b/internal/gwfc/Map.go @@ -49,7 +49,7 @@ func (m *Map) GetAdjacentTypes(x, y int) (s []string) { } t := m.Get(x+x2, y+y2) - if t != nil { + if t != nil && t.tile != "" { s = append(s, t.tile) } }