Add grid data structure and supporting functions

main
JD Cantrell 2 years ago
parent 149e261322
commit ac867ec315

1
.gitignore vendored

@ -15,3 +15,4 @@
# Dependency directories (remove the comment below to include it)
# vendor/
*.png

@ -0,0 +1,28 @@
package main
import (
"fmt"
"math/rand"
"time"
"go-mazes/grid"
)
func main() {
rand.Seed(time.Now().UnixNano())
g := grid.Make(100, 100)
grid.GenerateBinaryTree(g)
cell := grid.RandomCell(g)
fmt.Println("Random Cell", cell)
cell = grid.RandomCell(g)
fmt.Println("Random Cell", cell)
cell = grid.RandomCell(g)
fmt.Println("Random Cell", cell)
fmt.Println("Grid Size", grid.Size(g))
// grid.Print(g)
grid.WritePng(g, "binary_tree.png")
}

@ -0,0 +1,3 @@
module go-mazes
go 1.18

@ -0,0 +1,30 @@
package grid
import (
"math/rand"
)
func GenerateBinaryTree(g Grid) {
for i := 0; i < len(g.Cells); i++ {
dir := rand.Intn(2)
if g.Cells[i].north == nil && g.Cells[i].east == nil {
continue
}
if dir == 1 && g.Cells[i].north == nil {
dir = 0
} else if dir == 0 && g.Cells[i].east == nil {
dir = 1
}
if dir == 1 {
LinkCell(&g.Cells[i], g.Cells[i].north)
LinkCell(g.Cells[i].north, &g.Cells[i])
} else {
LinkCell(&g.Cells[i], g.Cells[i].east)
LinkCell(g.Cells[i].east, &g.Cells[i])
}
}
}

@ -0,0 +1,167 @@
package grid
import (
"fmt"
"math/rand"
"strings"
)
type Cell struct {
x int
y int
north *Cell
south *Cell
west *Cell
east *Cell
links []*Cell
}
type Grid struct {
Rows int
Columns int
Cells []Cell
}
func getCellIdx(x, y, cols int) int {
return y*cols + x
}
func LinkCell(cell1 *Cell, cell2 *Cell) {
cell1.links = append(cell1.links, cell2)
}
func IsLinked(cell1 Cell, cell2 *Cell) bool {
for i := range cell1.links {
if cell1.links[i] == cell2 {
return true
}
}
return false
}
func Make(rows int, columns int) Grid {
grid := Grid{Rows: rows, Columns: columns}
// initialize cells
for i := 0; i < rows; i += 1 {
for j := 0; j < columns; j += 1 {
grid.Cells = append(grid.Cells, Cell{x: j, y: i})
}
}
//initialize neighbors
for i := 0; i < columns; i += 1 {
for j := 0; j < rows; j += 1 {
idx := getCellIdx(i, j, columns)
if j > 0 {
grid.Cells[idx].north = &grid.Cells[getCellIdx(i, j-1, columns)]
}
if j+1 != rows {
grid.Cells[idx].south = &grid.Cells[getCellIdx(i, j+1, columns)]
}
if i > 0 {
grid.Cells[idx].west = &grid.Cells[getCellIdx(i-1, j, columns)]
}
if i+1 != columns {
grid.Cells[idx].east = &grid.Cells[getCellIdx(i+1, j, columns)]
}
}
}
return grid
}
func GetCell(g Grid, x int, y int) Cell {
idx := getCellIdx(x, y, g.Columns)
return g.Cells[idx]
}
func Size(g Grid) int {
return len(g.Cells)
}
func RandomCell(g Grid) Cell {
idx := getCellIdx(rand.Intn(g.Columns), rand.Intn(g.Rows), g.Columns)
return g.Cells[idx]
}
func Print(g Grid) {
for y := 0; y < g.Rows; y += 1 {
row_top := ""
row_middle := ""
row_middle_label := ""
for x := 0; x < g.Columns; x += 1 {
cell := GetCell(g, x, y)
right_end := "╣"
middle := "╬"
horz := "═"
vert := "║"
if y == 0 {
right_end = "╗"
middle = "╦"
}
if x == 0 {
if y == 0 {
middle = "╔"
} else {
middle = "╠"
}
}
walls := map[string]bool{
"north": !IsLinked(cell, cell.north) || cell.north == nil,
"east": !IsLinked(cell, cell.east) || cell.east == nil,
"south": !IsLinked(cell, cell.south) || cell.south == nil,
"west": !IsLinked(cell, cell.west) || cell.west == nil,
}
// draw north
if walls["north"] {
row_top += middle + strings.Repeat(horz, 3)
} else {
row_top += middle + strings.Repeat(" ", 3)
}
if walls["west"] {
row_middle += vert + strings.Repeat(" ", 3)
row_middle_label += vert + fmt.Sprintf("%3d", x+y*g.Rows)
} else {
row_middle += strings.Repeat(" ", 4)
row_middle_label += fmt.Sprintf(" %3d", x+y*g.Rows)
}
if x == g.Columns-1 {
row_top += right_end
row_middle += vert
row_middle_label += vert
}
// draw south
}
fmt.Println(row_top)
fmt.Println(row_middle)
fmt.Println(row_middle_label)
fmt.Println(row_middle)
if y == g.Rows-1 {
bottom := ""
left_end := "╚"
right_end := "╝"
middle := "╩"
horz := "═"
for x := 0; x < g.Columns; x += 1 {
if x == 0 {
bottom += left_end + horz + horz + horz
} else {
bottom += middle + horz + horz + horz
}
}
bottom += right_end
fmt.Println(bottom)
}
}
}

@ -0,0 +1,82 @@
package grid
import (
"fmt"
"image"
"image/color"
"image/png"
"os"
)
var palette = []color.Color{
color.Black,
color.RGBA{0x00, 0xb3, 0x68, 0xff},
color.RGBA{0xff, 0x57, 0x92, 0xff},
color.RGBA{0x00, 0xbd, 0xd6, 0xff},
color.RGBA{0x00, 0x94, 0x56, 0xff},
color.RGBA{0x58, 0x42, 0xff, 0xff},
color.RGBA{0x00, 0x95, 0xa8, 0xff},
color.RGBA{0xe6, 0x41, 0x00, 0xff},
color.RGBA{0xb3, 0x69, 0x4d, 0xff},
}
func vert(img *image.RGBA, x int, y int, length int, colorIdx uint8) {
for i := 0; i < length; i++ {
img.Set(x, y+i, palette[colorIdx])
}
}
func horz(img *image.RGBA, x int, y int, length int, colorIdx uint8) {
for i := 0; i < length; i++ {
img.Set(x+i, y, palette[colorIdx])
}
}
var cellSize = 10
func drawCell(img *image.RGBA, colorIdx uint8, x int, y int, top bool, right bool, bottom bool, left bool) {
imgX := x * cellSize
imgY := y * cellSize
if top {
horz(img, imgX, imgY, cellSize, colorIdx)
}
if bottom {
horz(img, imgX, imgY+cellSize-1, cellSize, colorIdx)
}
if left {
vert(img, imgX, imgY, cellSize, colorIdx)
}
if right {
vert(img, imgX+cellSize-1, imgY, cellSize, colorIdx)
}
}
func WritePng(g Grid, filename string) {
img := image.NewRGBA(
image.Rect(0, 0, cellSize*g.Columns, cellSize*g.Rows),
)
for x := 0; x < g.Columns; x++ {
for y := 0; y < g.Rows; y++ {
cell := GetCell(g, x, y)
walls := map[string]bool{
"north": !IsLinked(cell, cell.north) || cell.north == nil,
"east": !IsLinked(cell, cell.east) || cell.east == nil,
"south": !IsLinked(cell, cell.south) || cell.south == nil,
"west": !IsLinked(cell, cell.west) || cell.west == nil,
}
drawCell(img, 1, x, y, y == 0, walls["east"], walls["south"], x == 0)
}
}
fh, err := os.Create(filename)
if err != nil {
fmt.Println("cannot create gif")
} else {
png.Encode(fh, img)
}
}
Loading…
Cancel
Save