Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 57 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,59 @@
# Mazes
# Mazes Chapter 2

Based on the book [Mazes for Programmers: Code Your Own Twisty Little Passages](https://pragprog.com/book/jbmaze/mazes-for-programmers)
Chapter 2 is all about building a grid class that contains cells. We can
populate our maze and print it out.

Running this produces a random maze with the btree algorithm

```
Binary Tree
+---+---+---+---+---+---+---+---+---+---+
| |
+ + + + + +---+---+---+---+ +
| | | | | | |
+---+ +---+---+ +---+---+ +---+ +
| | | | |
+---+ +---+---+---+---+---+ +---+ +
| | | |
+ + + +---+ +---+---+---+ + +
| | | | | | |
+---+ + +---+ +---+ +---+---+ +
| | | | | |
+---+---+---+---+---+---+---+---+---+ +
| |
+ +---+---+---+ + +---+ +---+ +
| | | | | |
+---+---+---+ + + +---+ + + +
| | | | | | |
+ +---+ +---+---+ + +---+ + +
| | | | | | |
+---+---+---+---+---+---+---+---+---+---+

Sidewinder
+---+---+---+---+---+---+---+---+---+---+
| |
+ + +---+---+ +---+---+ + + +
| | | | | | |
+ + +---+ +---+---+ +---+ + +
| | | | | | |
+ + + +---+ +---+---+---+ + +
| | | | | | |
+ + + + + +---+ +---+---+ +
| | | | | | | |
+ + +---+---+ + +---+ + +---+
| | | | | | |
+---+ + +---+ + + +---+ + +
| | | | | | | |
+---+ +---+ +---+ + +---+ + +
| | | | | | |
+---+ +---+ +---+ + + + +---+
| | | | | | |
+ + +---+ + +---+---+ +---+---+
| | | | | |
+---+---+---+---+---+---+---+---+---+---+
```

![Image output](test.png)

The following code is just a port of the ruby code in the book

All code are in the chapter branches
29 changes: 29 additions & 0 deletions btree.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package main

import (
"math/rand"
"time"
)

type BinaryTree struct{}

func (b *BinaryTree) On(g *Grid) {
rand.Seed(time.Now().UnixNano())
for c := range g.EachCell() {
neighbors := make([]*Cell, 0)
if c.North != nil {
neighbors = append(neighbors, c.North)
}
if c.East != nil {
neighbors = append(neighbors, c.East)
}
l := len(neighbors)
if l != 0 {
i := rand.Intn(l)
neighbor := neighbors[i]
if neighbor != nil {
c.Link(neighbor, true)
}
}
}
}
73 changes: 73 additions & 0 deletions cell.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package main

type Cell struct {
row, col int
North, South, East, West *Cell
links map[*Cell]bool
}

func NewCell(row, col int) *Cell {
c := new(Cell)
c.row, c.col = row, col
c.links = make(map[*Cell]bool)
return c
}

func (c Cell) Row() int {
return c.row
}

func (c Cell) Col() int {
return c.col
}

func (c *Cell) Link(cell *Cell, bidi bool) *Cell {
c.links[cell] = true

if bidi {
cell.Link(c, false)
}
return c
}

func (c *Cell) Unlink(cell *Cell, bidi bool) *Cell {
delete(c.links, cell)
if bidi {
cell.Unlink(c, false)
}
return c
}

func (c Cell) IsLinked(cell *Cell) bool {
for x := range c.links {
if x == cell {
return true
}
}
return false
}

func (c Cell) Links() []*Cell {
list := make([]*Cell, 0)
for x := range c.links {
list = append(list, x)
}
return list
}

func (c Cell) Neighbors() []*Cell {
list := make([]*Cell, 0)
if c.North != nil {
list = append(list, c.North)
}
if c.South != nil {
list = append(list, c.South)
}
if c.East != nil {
list = append(list, c.East)
}
if c.West != nil {
list = append(list, c.West)
}
return list
}
128 changes: 128 additions & 0 deletions grid.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
package main

import (
"math/rand"
"time"
)

type Grid struct {
Rows, Cols int
grid [][]*Cell
}

func NewGrid(rows, cols int) *Grid {
g := new(Grid)
g.Rows, g.Cols = rows, cols
g.prepareGrid()
g.configureCells()

return g
}

func (g *Grid) prepareGrid() {
rows := make([][]*Cell, g.Rows)

for r := range rows {
cols := make([]*Cell, g.Cols)
for c := range cols {
cols[c] = NewCell(r, c)
}
rows[r] = cols
}
g.grid = rows
}

func (g *Grid) configureCells() {
for r := range g.grid {
for c := range g.grid[r] {
g.grid[r][c].North = g.getCell(r-1, c)
g.grid[r][c].South = g.getCell(r+1, c)
g.grid[r][c].West = g.getCell(r, c-1)
g.grid[r][c].East = g.getCell(r, c+1)
}
}
}

func (g *Grid) getCell(row, col int) *Cell {
if row < 0 || row >= g.Rows {
return nil
}
if col < 0 || col >= g.Cols {
return nil
}
return g.grid[row][col]
}

func (g *Grid) Size() int {
return g.Rows * g.Cols
}

func (g *Grid) RandomCell() *Cell {
rand.Seed(time.Now().UnixNano())
row := rand.Intn(g.Rows)
col := rand.Intn(g.Cols)
return g.grid[row][col]
}

func (g *Grid) EachRow() chan []*Cell {
c := make(chan []*Cell)
go func() {
for _, r := range g.grid {
c <- r
}
close(c)
}()
return c
}

func (g *Grid) EachCell() chan *Cell {
c := make(chan *Cell)
go func() {
for r := range g.EachRow() {
for _, i := range r {
c <- i
}
}
close(c)
}()
return c
}

func (g *Grid) String() string {
output := "+"
for i := 0; i < g.Cols; i++ {
output += "---+"
}
output += "\n"

for r := range g.EachRow() {
top := "|"
bottom := "+"
for _, c := range r {
body := " "
eastBoundary := ""
if c.IsLinked(c.East) {
eastBoundary = " "
} else {
eastBoundary = "|"
}
top += body
top += eastBoundary

southBoundary := ""
if c.IsLinked(c.South) {
southBoundary = " "
} else {
southBoundary = "---"
}

corner := "+"
bottom += southBoundary
bottom += corner
}
output += top + "\n"
output += bottom + "\n"
}

return output
}
80 changes: 80 additions & 0 deletions imager.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package main

import (
"image"
"image/color"
"image/draw"
"image/png"
"log"
"os"
"os/exec"
)

var (
white color.Color = color.RGBA{255, 255, 255, 255}
black color.Color = color.RGBA{0, 0, 0, 255}
)

type Image struct {
size int
}

func NewImage(size int) *Image {
return &Image{size: size}
}

func (i *Image) DrawLine(img *image.RGBA, x1, y1, x2, y2 int, c color.Color) {
for i := x1; i < x2; i++ {
img.Set(i, y2, c)
}
for i := y1; i < y2; i++ {
img.Set(x2, i, c)
}
}

func (i *Image) DrawGrid(g *Grid) *image.RGBA {
width := i.size * g.Cols
height := i.size * g.Rows
background := white
wall := black

img := image.NewRGBA(image.Rect(0, 0, width+1, height+1))
draw.Draw(img, img.Bounds(), &image.Uniform{background}, image.ZP, draw.Src)

for c := range g.EachCell() {
x1 := c.Col() * i.size
y1 := c.Row() * i.size
x2 := (c.Col() + 1) * i.size
y2 := (c.Row() + 1) * i.size

if c.North == nil {
i.DrawLine(img, x1, y1, x2, y1, wall)
}
if c.West == nil {
i.DrawLine(img, x1, y1, x1, y2, wall)
}
if !c.IsLinked(c.East) {
i.DrawLine(img, x2, y1, x2, y2, wall)
}
if !c.IsLinked(c.South) {
i.DrawLine(img, x1, y2, x2, y2, wall)
}
}

return img
}

func (i *Image) Save(filename string, img *image.RGBA) {
w, _ := os.Create(filename)
defer w.Close()
png.Encode(w, img) //Encode writes the Image m to w in PNG format.
}

func Show(name string) {
command := "xdg-open"
cmd := exec.Command(command, name)
err := cmd.Run()
if err != nil {
log.Fatal(err)
}
}
21 changes: 21 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Not done yet, currently, what's below is just test code to see what's going on
package main

import "fmt"

func main() {
fmt.Println("Binary Tree")
g := NewGrid(10, 10)
b := new(BinaryTree)
b.On(g)
fmt.Println(g)
fmt.Println("Sidewinder")
g = NewGrid(10, 10)
s := new(Sidewinder)
s.On(g)
fmt.Println(g)
fmt.Println("Showing image")
i := NewImage(40)
i.Save("test.png", i.DrawGrid(g))
Show("test.png")
}
Loading