Stuff
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
maze.png
|
||||||
37
main.go
37
main.go
@@ -5,32 +5,45 @@ import (
|
|||||||
"image/color"
|
"image/color"
|
||||||
"image/png"
|
"image/png"
|
||||||
"os"
|
"os"
|
||||||
|
"test-maze/mazer"
|
||||||
)
|
)
|
||||||
|
|
||||||
const SIZE_X = 128
|
const SIZE_X = 48
|
||||||
const SIZE_Y = 128
|
const SIZE_Y = 48
|
||||||
const CELL_SIZE = 16
|
const CELL_SCALE = 10
|
||||||
const CELL_SCALE = 8
|
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
matrix := mazer.GenerateMaze(SIZE_X, SIZE_Y)
|
||||||
|
|
||||||
img := image.NewRGBA(image.Rect(0, 0, SIZE_X*CELL_SCALE, SIZE_Y*CELL_SCALE))
|
img := image.NewRGBA(image.Rect(0, 0, SIZE_X*CELL_SCALE, SIZE_Y*CELL_SCALE))
|
||||||
|
|
||||||
white := color.RGBA{R: 255, G: 255, B: 255, A: 255}
|
white := color.RGBA{R: 255, G: 255, B: 255, A: 255}
|
||||||
black := color.RGBA{R: 0, G: 0, B: 0, A: 255}
|
black := color.RGBA{R: 0, G: 0, B: 0, A: 255}
|
||||||
|
|
||||||
for y := 0; y < SIZE_Y*CELL_SCALE; y++ {
|
for cellY := 0; cellY < SIZE_Y; cellY++ {
|
||||||
for x := 0; x < SIZE_X*CELL_SCALE; x++ {
|
startY := cellY * CELL_SCALE
|
||||||
stripeIndex := (x / CELL_SIZE) % 2
|
for cellX := 0; cellX < SIZE_X; cellX++ {
|
||||||
if stripeIndex == 0 {
|
startX := cellX * CELL_SCALE
|
||||||
img.SetRGBA(x, y, white)
|
|
||||||
} else {
|
p := black
|
||||||
img.SetRGBA(x, y, black)
|
if matrix[cellY][cellX] == 1 {
|
||||||
|
p = white
|
||||||
|
}
|
||||||
|
|
||||||
|
for dy := 0; dy < CELL_SCALE; dy++ {
|
||||||
|
row := img.Pix[(startY+dy)*img.Stride:]
|
||||||
|
for dx := 0; dx < CELL_SCALE; dx++ {
|
||||||
|
offset := (startX + dx) * 4
|
||||||
|
row[offset+0] = p.R
|
||||||
|
row[offset+1] = p.G
|
||||||
|
row[offset+2] = p.B
|
||||||
|
row[offset+3] = p.A
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
f, err := os.Create("stripes.png")
|
f, err := os.Create("maze.png")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|||||||
173
mazer/maze.go
173
mazer/maze.go
@@ -1,124 +1,105 @@
|
|||||||
package mazer
|
package mazer
|
||||||
|
|
||||||
import (
|
import "math/rand/v2"
|
||||||
"math/rand/v2"
|
|
||||||
)
|
|
||||||
|
|
||||||
func GenerateMaze(width int, height int) {
|
func GenerateMaze(width int, height int) [][]int {
|
||||||
|
if width <= 0 || height <= 0 {
|
||||||
|
return [][]int{}
|
||||||
|
}
|
||||||
|
|
||||||
// Init array
|
cells := make([]int, width*height)
|
||||||
matrix := make([][]int, height)
|
matrix := make([][]int, height)
|
||||||
// 2. Allocate each inner slice (width)
|
for y := 0; y < height; y++ {
|
||||||
for i := range matrix {
|
rowStart := y * width
|
||||||
matrix[i] = make([]int, width)
|
matrix[y] = cells[rowStart : rowStart+width]
|
||||||
}
|
}
|
||||||
|
|
||||||
startPoint := rand.IntN(width + 1)
|
// Keep a full black border: path only exists inside [1..width-2] x [1..height-2].
|
||||||
matrix[0][startPoint] = 1
|
if width < 3 || height < 3 {
|
||||||
|
return matrix
|
||||||
// Start moving until out of moves
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func pickRandomDirection(matrix [][]int, posX int, posY int) []int {
|
|
||||||
height := len(matrix)
|
|
||||||
if posY == height-1 {
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
validDirs := getValidDirections(matrix, posX, posY)
|
startX, startY := 1, 1
|
||||||
if len(validDirs) == 0 {
|
endX, endY := width-2, height-2
|
||||||
return []int{0, 1}
|
|
||||||
|
parent := make([]int, width*height)
|
||||||
|
for i := range parent {
|
||||||
|
parent[i] = -1
|
||||||
|
}
|
||||||
|
visited := make([]bool, width*height)
|
||||||
|
|
||||||
|
dx := [4]int{0, -1, 1, 0}
|
||||||
|
dy := [4]int{1, 0, 0, -1}
|
||||||
|
|
||||||
|
type node struct {
|
||||||
|
x int
|
||||||
|
y int
|
||||||
|
dirs [4]uint8
|
||||||
|
next int
|
||||||
}
|
}
|
||||||
|
|
||||||
return validDirs[rand.IntN(len(validDirs))]
|
stack := make([]node, 1, (width-2)*(height-2))
|
||||||
}
|
stack[0] = node{x: startX, y: startY, dirs: shuffledDirections()}
|
||||||
|
startIdx := startY*width + startX
|
||||||
|
endIdx := endY*width + endX
|
||||||
|
visited[startIdx] = true
|
||||||
|
|
||||||
func getValidDirections(matrix [][]int, posX int, posY int) [][]int {
|
found := false
|
||||||
height := len(matrix)
|
for len(stack) > 0 {
|
||||||
width := len(matrix[0])
|
last := len(stack) - 1
|
||||||
validDirs := make([][]int, 0, 4)
|
top := &stack[last]
|
||||||
|
|
||||||
possibleDirs := [][]int{
|
if top.x == endX && top.y == endY {
|
||||||
{0, 1}, // Down
|
found = true
|
||||||
{-1, 0}, // Left
|
break
|
||||||
{1, 0}, // Right
|
|
||||||
{0, -1}, // Up
|
|
||||||
}
|
|
||||||
prevX, prevY, hasPrev := getPreviousPathCell(matrix, posX, posY)
|
|
||||||
if hasPrev && prevX == posX && prevY == posY+1 {
|
|
||||||
// If we just moved up, force the next step to be side/down (no repeated up).
|
|
||||||
possibleDirs = [][]int{
|
|
||||||
{-1, 0}, // Left
|
|
||||||
{1, 0}, // Right
|
|
||||||
{0, 1}, // Down
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
neighborDirs := [][]int{
|
if top.next == 4 {
|
||||||
{0, -1},
|
stack = stack[:last]
|
||||||
{0, 1},
|
|
||||||
{-1, 0},
|
|
||||||
{1, 0},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, dir := range possibleDirs {
|
|
||||||
newX := posX + dir[0]
|
|
||||||
newY := posY + dir[1]
|
|
||||||
|
|
||||||
if newX < 0 || newX >= width || newY < 0 || newY >= height {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if matrix[newY][newX] == 1 {
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
tooClose := false
|
d := top.dirs[top.next]
|
||||||
for _, neighborDir := range neighborDirs {
|
top.next++
|
||||||
neighborX := newX + neighborDir[0]
|
|
||||||
neighborY := newY + neighborDir[1]
|
|
||||||
|
|
||||||
if neighborX < 0 || neighborX >= width || neighborY < 0 || neighborY >= height {
|
nx := top.x + dx[d]
|
||||||
continue
|
ny := top.y + dy[d]
|
||||||
}
|
if nx <= 0 || nx >= width-1 || ny <= 0 || ny >= height-1 {
|
||||||
if neighborX == posX && neighborY == posY {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if matrix[neighborY][neighborX] == 1 {
|
|
||||||
tooClose = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if tooClose {
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
validDirs = append(validDirs, dir)
|
nIdx := ny*width + nx
|
||||||
}
|
if visited[nIdx] {
|
||||||
|
|
||||||
return validDirs
|
|
||||||
}
|
|
||||||
|
|
||||||
func getPreviousPathCell(matrix [][]int, posX int, posY int) (int, int, bool) {
|
|
||||||
height := len(matrix)
|
|
||||||
width := len(matrix[0])
|
|
||||||
dirs := [][]int{
|
|
||||||
{0, -1},
|
|
||||||
{0, 1},
|
|
||||||
{-1, 0},
|
|
||||||
{1, 0},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, dir := range dirs {
|
|
||||||
x := posX + dir[0]
|
|
||||||
y := posY + dir[1]
|
|
||||||
if x < 0 || x >= width || y < 0 || y >= height {
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if matrix[y][x] == 1 {
|
|
||||||
return x, y, true
|
visited[nIdx] = true
|
||||||
|
parent[nIdx] = top.y*width + top.x
|
||||||
|
stack = append(stack, node{x: nx, y: ny, dirs: shuffledDirections()})
|
||||||
|
}
|
||||||
|
|
||||||
|
if !found {
|
||||||
|
matrix[startY][startX] = 1
|
||||||
|
return matrix
|
||||||
|
}
|
||||||
|
|
||||||
|
for idx := endIdx; idx != -1; idx = parent[idx] {
|
||||||
|
x := idx % width
|
||||||
|
y := idx / width
|
||||||
|
matrix[y][x] = 1
|
||||||
|
if idx == startIdx {
|
||||||
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0, 0, false
|
return matrix
|
||||||
|
}
|
||||||
|
|
||||||
|
func shuffledDirections() [4]uint8 {
|
||||||
|
dirs := [4]uint8{0, 1, 2, 3}
|
||||||
|
for i := 3; i > 0; i-- {
|
||||||
|
j := rand.IntN(i + 1)
|
||||||
|
dirs[i], dirs[j] = dirs[j], dirs[i]
|
||||||
|
}
|
||||||
|
return dirs
|
||||||
}
|
}
|
||||||
|
|||||||
BIN
stripes.png
BIN
stripes.png
Binary file not shown.
|
Before Width: | Height: | Size: 5.2 KiB |
Reference in New Issue
Block a user