From c0a9f788ee0b49285ea76d1c1cc139d2c7341d52 Mon Sep 17 00:00:00 2001 From: Wari Wahab Date: Sun, 15 Feb 2015 01:32:59 +0800 Subject: [PATCH 1/8] First bit done, TODO, binary tree alg to connect the cells --- README.md | 7 +++--- cell.go | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ grid.go | 49 +++++++++++++++++++++++++++++++++++++ main.go | 36 +++++++++++++++++++++++++++ 4 files changed, 162 insertions(+), 3 deletions(-) create mode 100644 cell.go create mode 100644 grid.go create mode 100644 main.go diff --git a/README.md b/README.md index b360f98..5752dfd 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ -# 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. + +The following code is just a port of the ruby code in the book -All code are in the chapter branches diff --git a/cell.go b/cell.go new file mode 100644 index 0000000..cffd065 --- /dev/null +++ b/cell.go @@ -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 { + c.Link(c, false) + } + return c +} + +func (c *Cell) Unlink(cell *Cell, bidi bool) *Cell { + delete(c.links, cell) + if bidi { + c.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 +} diff --git a/grid.go b/grid.go new file mode 100644 index 0000000..42c794d --- /dev/null +++ b/grid.go @@ -0,0 +1,49 @@ +package main + +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] +} diff --git a/main.go b/main.go new file mode 100644 index 0000000..e39b2b7 --- /dev/null +++ b/main.go @@ -0,0 +1,36 @@ +// Not done yet, currently, what's below is just test code to see what's going on +package main + +import "fmt" + +func main() { + c := NewCell(0, 0) + d := NewCell(0, 1) + c.Link(d, true) + c.North = d + d.South = c + d.Link(c, false) + + fmt.Println(c) + fmt.Println(d) + fmt.Println(c.Links()) + fmt.Println(c.Neighbors()) + fmt.Println(d.Neighbors()) + fmt.Println(c.IsLinked(d)) + c.Unlink(d, true) + fmt.Println(c) + fmt.Println(d) + fmt.Println(c.Links()) + fmt.Println(c.Neighbors()) + fmt.Println(d.Neighbors()) + fmt.Println(c.IsLinked(d)) + + g := NewGrid(10, 10) + fmt.Println(g.grid) + + fmt.Println(g.grid[4][5]) + fmt.Println(g.grid[4][5].North) + fmt.Println(g.grid[4][5].South) + fmt.Println(g.grid[4][5].East) + fmt.Println(g.grid[4][5].West) +} From 79d1ccaeb75f3284b80bf3c142b685a4d80d72cd Mon Sep 17 00:00:00 2001 From: Wari Wahab Date: Mon, 16 Feb 2015 00:18:21 +0800 Subject: [PATCH 2/8] Iterators for rows/cells --- grid.go | 40 ++++++++++++++++++++++++++++++++++++++++ main.go | 6 ++++-- 2 files changed, 44 insertions(+), 2 deletions(-) diff --git a/grid.go b/grid.go index 42c794d..0dcdf5d 100644 --- a/grid.go +++ b/grid.go @@ -1,5 +1,10 @@ package main +import ( + "math/rand" + "time" +) + type Grid struct { Rows, Cols int grid [][]*Cell @@ -47,3 +52,38 @@ func (g *Grid) getCell(row, col int) *Cell { } 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 +} diff --git a/main.go b/main.go index e39b2b7..317f2ca 100644 --- a/main.go +++ b/main.go @@ -15,14 +15,12 @@ func main() { fmt.Println(d) fmt.Println(c.Links()) fmt.Println(c.Neighbors()) - fmt.Println(d.Neighbors()) fmt.Println(c.IsLinked(d)) c.Unlink(d, true) fmt.Println(c) fmt.Println(d) fmt.Println(c.Links()) fmt.Println(c.Neighbors()) - fmt.Println(d.Neighbors()) fmt.Println(c.IsLinked(d)) g := NewGrid(10, 10) @@ -33,4 +31,8 @@ func main() { fmt.Println(g.grid[4][5].South) fmt.Println(g.grid[4][5].East) fmt.Println(g.grid[4][5].West) + + for y := range g.EachRow() { + fmt.Println(y) + } } From 0ea9962bb006a27ac59898be308473a4b0cb7414 Mon Sep 17 00:00:00 2001 From: Wari Wahab Date: Mon, 16 Feb 2015 01:29:11 +0800 Subject: [PATCH 3/8] Updated with the btree algorithm One thing to note, in line 6 of the book, we check for north and east, and chose either one to link. Somehow, it does not work on this code, I have to use South and East. Will have to check why I can't follow the code as is given in the book --- README.md | 49 ++++++++++++++++++++++++++++++++++++++++++++++++- btree.go | 29 +++++++++++++++++++++++++++++ grid.go | 39 +++++++++++++++++++++++++++++++++++++++ main.go | 35 ++++------------------------------- 4 files changed, 120 insertions(+), 32 deletions(-) create mode 100644 btree.go diff --git a/README.md b/README.md index 5752dfd..8f0835a 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,53 @@ # Mazes Chapter 2 -Chapter 2 is all about building a grid class that contains cells. +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 + +``` ++---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ +| | | | | | | | | | ++---+ +---+ +---+ +---+ + +---+---+---+ + +---+---+---+ +---+ + +| | | | | | | | | ++---+ + + + +---+---+---+---+---+---+ + + +---+---+---+---+---+ + +| | | | | | | | | | ++ +---+---+---+---+ +---+ +---+---+---+---+---+ + + + + +---+ + +| | | | | | | | | | | | | | | ++---+ + +---+---+---+ + + + + +---+ + + + + +---+ + + +| | | | | | | | | | | | | | | | | | ++ +---+---+ + + + + + + + + + + + + + +---+ + + +| | | | | | | | | | | | | | ++---+ +---+ + + + +---+ + +---+ + + + +---+---+ +---+ + +| | | | | | | | | | | | | ++ +---+ +---+ +---+ +---+---+ + +---+ + +---+ + + +---+ + +| | | | | | | | | ++ + +---+---+ +---+ +---+---+---+---+ +---+---+ + +---+---+---+ + +| | | | | | | | | | | | | ++ +---+---+ + +---+ + +---+ + +---+ + +---+---+ + +---+ + +| | | | | | | | | | ++ + + + +---+---+ +---+---+---+---+ + +---+---+---+---+ +---+ + +| | | | | | | | | ++ +---+---+---+---+---+ + +---+---+---+---+ +---+---+ +---+ + + + +| | | | | | | | ++---+ +---+---+---+---+ + +---+---+ +---+---+---+---+ +---+---+ + + +| | | | | | | | | | | ++ +---+---+---+ +---+ + +---+---+ + + +---+---+ +---+ +---+ + +| | | | | | | | | | | | ++---+ + + + +---+ + + +---+---+---+---+---+---+ + +---+ + + +| | | | | | | | | | ++---+---+---+ + +---+---+---+---+ + +---+---+ +---+---+ + + + + +| | | | | | | | | | | | | | | ++ + +---+ +---+ +---+ +---+ + + + + + +---+ +---+ + + +| | | | | | | | | | | | ++ + +---+ +---+---+---+ + +---+ +---+---+ + + +---+ +---+ + +| | | | | | | ++---+ +---+---+ + +---+---+---+---+---+---+---+---+---+ + +---+---+ + +| | | | | | | | | | ++---+ +---+---+ + +---+---+---+ + +---+ +---+---+---+ +---+ + + +| | ++---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ +``` The following code is just a port of the ruby code in the book diff --git a/btree.go b/btree.go new file mode 100644 index 0000000..2181ded --- /dev/null +++ b/btree.go @@ -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.South != nil { + neighbors = append(neighbors, c.South) + } + if c.East != nil { + neighbors = append(neighbors, c.East) + } + l := len(neighbors) + if l != 0 { + i := rand.Intn(len(neighbors)) + neighbor := neighbors[i] + if neighbor != nil { + c.Link(neighbor, true) + } + } + } +} diff --git a/grid.go b/grid.go index 0dcdf5d..6641d14 100644 --- a/grid.go +++ b/grid.go @@ -87,3 +87,42 @@ func (g *Grid) EachCell() chan *Cell { }() 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 +} diff --git a/main.go b/main.go index 317f2ca..e70bb57 100644 --- a/main.go +++ b/main.go @@ -4,35 +4,8 @@ package main import "fmt" func main() { - c := NewCell(0, 0) - d := NewCell(0, 1) - c.Link(d, true) - c.North = d - d.South = c - d.Link(c, false) - - fmt.Println(c) - fmt.Println(d) - fmt.Println(c.Links()) - fmt.Println(c.Neighbors()) - fmt.Println(c.IsLinked(d)) - c.Unlink(d, true) - fmt.Println(c) - fmt.Println(d) - fmt.Println(c.Links()) - fmt.Println(c.Neighbors()) - fmt.Println(c.IsLinked(d)) - - g := NewGrid(10, 10) - fmt.Println(g.grid) - - fmt.Println(g.grid[4][5]) - fmt.Println(g.grid[4][5].North) - fmt.Println(g.grid[4][5].South) - fmt.Println(g.grid[4][5].East) - fmt.Println(g.grid[4][5].West) - - for y := range g.EachRow() { - fmt.Println(y) - } + g := NewGrid(20, 20) + b := new(BinaryTree) + b.On(g) + fmt.Println(g) } From ba2d155c32875a6db604c02e76e9c95eadd1c0c2 Mon Sep 17 00:00:00 2001 From: Wari Wahab Date: Tue, 17 Feb 2015 09:25:24 +0800 Subject: [PATCH 4/8] Fixed a bug that cause mazes to not be linked north wise. * Re-reading the source code from the book got me to spot my own mistake that makes bidirectional links to not join at all * The code now follows the book exactly --- btree.go | 6 +++--- cell.go | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/btree.go b/btree.go index 2181ded..3ce6f94 100644 --- a/btree.go +++ b/btree.go @@ -11,15 +11,15 @@ func (b *BinaryTree) On(g *Grid) { rand.Seed(time.Now().UnixNano()) for c := range g.EachCell() { neighbors := make([]*Cell, 0) - if c.South != nil { - neighbors = append(neighbors, c.South) + 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(len(neighbors)) + i := rand.Intn(l) neighbor := neighbors[i] if neighbor != nil { c.Link(neighbor, true) diff --git a/cell.go b/cell.go index cffd065..99f963e 100644 --- a/cell.go +++ b/cell.go @@ -25,7 +25,7 @@ func (c *Cell) Link(cell *Cell, bidi bool) *Cell { c.links[cell] = true if bidi { - c.Link(c, false) + cell.Link(c, false) } return c } @@ -33,7 +33,7 @@ func (c *Cell) Link(cell *Cell, bidi bool) *Cell { func (c *Cell) Unlink(cell *Cell, bidi bool) *Cell { delete(c.links, cell) if bidi { - c.Unlink(c, false) + cell.Unlink(c, false) } return c } From 0acd9138c12ca6496ff4d72ba1346cc8d07b442c Mon Sep 17 00:00:00 2001 From: Wari Wahab Date: Tue, 17 Feb 2015 10:57:53 +0800 Subject: [PATCH 5/8] Added the sidewinder algorithm from the book --- README.md | 86 +++++++++++++++++++++++++++------------------------ main.go | 8 ++++- sidewinder.go | 44 ++++++++++++++++++++++++++ 3 files changed, 96 insertions(+), 42 deletions(-) create mode 100644 sidewinder.go diff --git a/README.md b/README.md index 8f0835a..e660acd 100644 --- a/README.md +++ b/README.md @@ -6,47 +6,51 @@ populate our maze and print it out. Running this produces a random maze with the btree algorithm ``` -+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ -| | | | | | | | | | -+---+ +---+ +---+ +---+ + +---+---+---+ + +---+---+---+ +---+ + -| | | | | | | | | -+---+ + + + +---+---+---+---+---+---+ + + +---+---+---+---+---+ + -| | | | | | | | | | -+ +---+---+---+---+ +---+ +---+---+---+---+---+ + + + + +---+ + -| | | | | | | | | | | | | | | -+---+ + +---+---+---+ + + + + +---+ + + + + +---+ + + -| | | | | | | | | | | | | | | | | | -+ +---+---+ + + + + + + + + + + + + + +---+ + + -| | | | | | | | | | | | | | -+---+ +---+ + + + +---+ + +---+ + + + +---+---+ +---+ + -| | | | | | | | | | | | | -+ +---+ +---+ +---+ +---+---+ + +---+ + +---+ + + +---+ + -| | | | | | | | | -+ + +---+---+ +---+ +---+---+---+---+ +---+---+ + +---+---+---+ + -| | | | | | | | | | | | | -+ +---+---+ + +---+ + +---+ + +---+ + +---+---+ + +---+ + -| | | | | | | | | | -+ + + + +---+---+ +---+---+---+---+ + +---+---+---+---+ +---+ + -| | | | | | | | | -+ +---+---+---+---+---+ + +---+---+---+---+ +---+---+ +---+ + + + -| | | | | | | | -+---+ +---+---+---+---+ + +---+---+ +---+---+---+---+ +---+---+ + + -| | | | | | | | | | | -+ +---+---+---+ +---+ + +---+---+ + + +---+---+ +---+ +---+ + -| | | | | | | | | | | | -+---+ + + + +---+ + + +---+---+---+---+---+---+ + +---+ + + -| | | | | | | | | | -+---+---+---+ + +---+---+---+---+ + +---+---+ +---+---+ + + + + -| | | | | | | | | | | | | | | -+ + +---+ +---+ +---+ +---+ + + + + + +---+ +---+ + + -| | | | | | | | | | | | -+ + +---+ +---+---+---+ + +---+ +---+---+ + + +---+ +---+ + -| | | | | | | -+---+ +---+---+ + +---+---+---+---+---+---+---+---+---+ + +---+---+ + -| | | | | | | | | | -+---+ +---+---+ + +---+---+---+ + +---+ +---+---+---+ +---+ + + -| | -+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ +Binary Tree ++---+---+---+---+---+---+---+---+---+---+ +| | ++ + + + + +---+---+---+---+ + +| | | | | | | ++---+ +---+---+ +---+---+ +---+ + +| | | | | ++---+ +---+---+---+---+---+ +---+ + +| | | | ++ + + +---+ +---+---+---+ + + +| | | | | | | ++---+ + +---+ +---+ +---+---+ + +| | | | | | ++---+---+---+---+---+---+---+---+---+ + +| | ++ +---+---+---+ + +---+ +---+ + +| | | | | | ++---+---+---+ + + +---+ + + + +| | | | | | | ++ +---+ +---+---+ + +---+ + + +| | | | | | | ++---+---+---+---+---+---+---+---+---+---+ + +Sidewinder ++---+---+---+---+---+---+---+---+---+---+ +| | ++ + +---+---+ +---+---+ + + + +| | | | | | | ++ + +---+ +---+---+ +---+ + + +| | | | | | | ++ + + +---+ +---+---+---+ + + +| | | | | | | ++ + + + + +---+ +---+---+ + +| | | | | | | | ++ + +---+---+ + +---+ + +---+ +| | | | | | | ++---+ + +---+ + + +---+ + + +| | | | | | | | ++---+ +---+ +---+ + +---+ + + +| | | | | | | ++---+ +---+ +---+ + + + +---+ +| | | | | | | ++ + +---+ + +---+---+ +---+---+ +| | | | | | ++---+---+---+---+---+---+---+---+---+---+ ``` The following code is just a port of the ruby code in the book diff --git a/main.go b/main.go index e70bb57..14beca2 100644 --- a/main.go +++ b/main.go @@ -4,8 +4,14 @@ package main import "fmt" func main() { - g := NewGrid(20, 20) + 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) } diff --git a/sidewinder.go b/sidewinder.go new file mode 100644 index 0000000..d83c541 --- /dev/null +++ b/sidewinder.go @@ -0,0 +1,44 @@ +package main + +import ( + "math/rand" + "time" +) + +type Sidewinder struct{} + +type cells []*Cell + +func (r cells) sample() *Cell { + l := len(r) + if l == 0 { + return nil + } else { + return r[rand.Intn(l)] + } +} + +func (s *Sidewinder) On(g *Grid) *Grid { + rand.Seed(time.Now().UnixNano()) + for r := range g.EachRow() { + run := make(cells, 0) + for _, c := range r { + run = append(run, c) + + atEasternBoundary := c.East == nil + atNorthernBoundary := c.North == nil + shouldCloseOut := atEasternBoundary || (!atNorthernBoundary && rand.Intn(2) == 0) + + if shouldCloseOut { + member := run.sample() + if member.North != nil { + member.Link(member.North, true) + } + run = nil // Clear out the cells + } else { + c.Link(c.East, true) + } + } + } + return g +} From 3d5c70f31a13df74c36756c3a8a1225a098d998d Mon Sep 17 00:00:00 2001 From: Wari Wahab Date: Tue, 17 Feb 2015 13:18:01 +0800 Subject: [PATCH 6/8] And finally, the imaging routine (phew) --- README.md | 2 ++ imager.go | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ main.go | 4 +++ test.png | Bin 0 -> 1694 bytes 4 files changed, 86 insertions(+) create mode 100644 imager.go create mode 100644 test.png diff --git a/README.md b/README.md index e660acd..91a1b7d 100644 --- a/README.md +++ b/README.md @@ -53,5 +53,7 @@ Sidewinder +---+---+---+---+---+---+---+---+---+---+ ``` +![Image output](test.png) + The following code is just a port of the ruby code in the book diff --git a/imager.go b/imager.go new file mode 100644 index 0000000..cc3b69d --- /dev/null +++ b/imager.go @@ -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) + } +} diff --git a/main.go b/main.go index 14beca2..d78595e 100644 --- a/main.go +++ b/main.go @@ -14,4 +14,8 @@ func main() { 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") } diff --git a/test.png b/test.png new file mode 100644 index 0000000000000000000000000000000000000000..5da2bd253d10dbf219a1deede0478cbcf116a72e GIT binary patch literal 1694 zcmeAS@N?(olHy`uVBq!ia0y~yV4MiT985qFZD&a!$(HKr;uumf=gsv%zE@@f4uLVL z|D($?cQ@4S?a?dlJMul@_|6CW?HFXwe=mMN_n#EQ|Mznq*NX)#igf5qV^p2RIwgay zoRh|;Kjsv_m!0|h--Y!PkJdfAW}R9vKYZ@<^LN7fO|vgtiSxg??Ov$ZKe1iXO!Rji zG)!zR$0u|bpW9oW_2suSySTM!)sbyq>rAqnbJJ(tf0oBV=RiZm)TbKz=X1WZ-><$e z|7(8kYgxlhCpRxTPfeBEUwwYRbC%WldyC6$f}5A0`(hUSUg-UeZw33G-@Gd@Fb)KU$`c>n zec$`e*go&+`FF0i{zZDpeD`O5kvq-@zrSc~TD>sz_nx=rnWqkg4QL_^Za#1M{ocx# z%KNRx2x{*Hqto}B2xamgEybgIr!2$=k}B8_b2YW zxAX6nGu&}+V;b+gwG($Xhwb(LV^i)t0Qm&s#7XH{A1u?ezL;(MwLQ0bU-H>qz;t={ zTf_2im9tkCZ~b6fG;ndt@PL2E_kXes4FCTZyxyX7FVdQ&MBb@0GX Date: Sun, 8 Mar 2015 02:54:51 +0800 Subject: [PATCH 7/8] My interpretation of distances @ page 40 * Dynamic type languages like Ruby and Python tend to leave out details and make things seem like magic. I used to like that about Ruby and Python :P * Now that I'm reading someone else's code, I have to do the interpretation myself, and I hope this is what the short listing on page 40 does. * Based on this however, there may be more Ruby fu to translate in the later pages 8| --- distances.go | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 distances.go diff --git a/distances.go b/distances.go new file mode 100644 index 0000000..16f83e3 --- /dev/null +++ b/distances.go @@ -0,0 +1,29 @@ +package main + +type Distances struct { + root *Cell + cells map[*Cell]int +} + +func NewDistances(root *Cell) *Distances { + d := new(Distances) + d.root = root + d.cells[root] = 0 + return d +} + +func (d *Distances) Cells() []*Cell { + cells := make([]*Cell, len(d.cells)) + for k, v := range d.cells { + cells[v] = k + } + return cells +} + +func (d *Distances) Distance(cell *Cell) int { + return d.cells[cell] +} + +func (d *Distances) SetDistance(cell *Cell, distance int) { + d.cells[cell] = distance +} From 1895b7eed84f23e9f2415ad4a53800ffc5f98c6b Mon Sep 17 00:00:00 2001 From: Wari Wahab Date: Mon, 9 Mar 2015 09:05:44 +0800 Subject: [PATCH 8/8] Up to page 44 of the book * We can now draw the grid with added distances * "Inheritance" in go in not really inheritance in the sense like Ruby, we have to override `String()`, as once promoted to Grid's String() method, we are not able to get to DistanceGrid's `ContentsOf(cell)` method. * Another thing to note, since there is only one `main()`, and the next few pages adds different scripts, which means I might have to split things up or provide command line options. --- .gitignore | 1 + README.md | 89 ++++++++++++++++++++++------------------------- btree.go | 2 +- cell.go | 19 ++++++++++ distancegrid.go | 64 ++++++++++++++++++++++++++++++++++ distances.go | 1 + grid.go | 16 +++++---- gridInterface.go | 6 ++++ main.go | 13 ++++--- sidewinder.go | 2 +- test.png | Bin 1694 -> 0 bytes 11 files changed, 153 insertions(+), 60 deletions(-) create mode 100644 .gitignore create mode 100644 distancegrid.go create mode 100644 gridInterface.go delete mode 100644 test.png diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..dbbbe4a --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +mazes diff --git a/README.md b/README.md index 91a1b7d..40d979c 100644 --- a/README.md +++ b/README.md @@ -1,59 +1,54 @@ -# Mazes Chapter 2 +# Mazes Chapter 3 -Chapter 2 is all about building a grid class that contains cells. We can -populate our maze and print it out. +Finding Solutions. We’ve learned how to populate our mazes. We can now use +Dijkstra’s Algorithm to find the shortest path. -Running this produces a random maze with the btree algorithm +Done up to page 44, for now. ``` Binary Tree +---+---+---+---+---+---+---+---+---+---+ -| | -+ + + + + +---+---+---+---+ + -| | | | | | | -+---+ +---+---+ +---+---+ +---+ + -| | | | | -+---+ +---+---+---+---+---+ +---+ + -| | | | -+ + + +---+ +---+---+---+ + + -| | | | | | | -+---+ + +---+ +---+ +---+---+ + -| | | | | | -+---+---+---+---+---+---+---+---+---+ + -| | -+ +---+---+---+ + +---+ +---+ + -| | | | | | -+---+---+---+ + + +---+ + + + -| | | | | | | -+ +---+ +---+---+ + +---+ + + -| | | | | | | +| 0 1 2 3 4 5 6 7 8 9 | ++---+ +---+ +---+ + + +---+ + +| 3 2 | 5 4 | 7 6 | 7 | 8 | b a | ++ + +---+---+---+ +---+---+---+ + +| 4 | 3 | a 9 8 7 | e d c b | ++---+ +---+ +---+---+ + +---+ + +| 5 4 | b a | h g f | e | d c | ++---+---+---+ + + +---+---+ + + +| e d c b | i | h | g f e | d | ++---+---+ +---+ + + +---+ + + +| f e d | k j | i | h | g f | e | ++---+---+---+ +---+ +---+---+---+ + +| o n m l | k j | i h g f | ++ +---+ +---+ +---+ +---+ + + +| p | o n | m l | k j | i h | g | ++---+ +---+---+---+ +---+---+---+ + +| q p | o n m l | k j i h | ++ + +---+---+---+---+ +---+---+ + +| r | q | p o n m l | k j i | +---+---+---+---+---+---+---+---+---+---+ Sidewinder +---+---+---+---+---+---+---+---+---+---+ -| | -+ + +---+---+ +---+---+ + + + -| | | | | | | -+ + +---+ +---+---+ +---+ + + -| | | | | | | -+ + + +---+ +---+---+---+ + + -| | | | | | | -+ + + + + +---+ +---+---+ + -| | | | | | | | -+ + +---+---+ + +---+ + +---+ -| | | | | | | -+---+ + +---+ + + +---+ + + -| | | | | | | | -+---+ +---+ +---+ + +---+ + + -| | | | | | | -+---+ +---+ +---+ + + + +---+ -| | | | | | | -+ + +---+ + +---+---+ +---+---+ -| | | | | | +| 0 1 2 3 4 5 6 7 8 9 | ++---+ + +---+---+---+---+ +---+---+ +| 3 2 | 3 4 5 6 7 | 8 9 a | ++ +---+---+ +---+ + + + +---+ +| 4 | 7 6 5 | 8 7 | 8 | 9 | a b | ++ + +---+ +---+ +---+---+---+ + +| 5 | 8 | 7 6 7 | 8 9 a b | c | ++---+ + +---+---+ +---+ + +---+ +| a 9 | 8 9 a | 9 a | b | c d | ++ +---+ + +---+ +---+---+ +---+ +| b c | 9 | a | b a | f e d e | ++---+---+ +---+---+ + + +---+ + +| c b a b c | b | g | f | g f | ++ + + + + + +---+ +---+ + +| d | c | b | c | d | c | h g h | g | ++ + + + +---+---+---+---+---+ + +| e | d | c | d e | l k j i h | ++ + +---+ +---+ +---+ + + + +| f | e f | e f | m n | k | j | i | +---+---+---+---+---+---+---+---+---+---+ ``` - -![Image output](test.png) - -The following code is just a port of the ruby code in the book - diff --git a/btree.go b/btree.go index 3ce6f94..13db15c 100644 --- a/btree.go +++ b/btree.go @@ -7,7 +7,7 @@ import ( type BinaryTree struct{} -func (b *BinaryTree) On(g *Grid) { +func (b *BinaryTree) On(g Grider) { rand.Seed(time.Now().UnixNano()) for c := range g.EachCell() { neighbors := make([]*Cell, 0) diff --git a/cell.go b/cell.go index 99f963e..3751884 100644 --- a/cell.go +++ b/cell.go @@ -71,3 +71,22 @@ func (c Cell) Neighbors() []*Cell { } return list } + +func (c *Cell) Distances() *Distances { + d := NewDistances(c) + frontier := []*Cell{c} + for len(frontier) != 0 { // frontier.any? + newFrontier := make([]*Cell, 0) + for _, cell := range frontier { + for _, link := range cell.Links() { + if link == c || d.Distance(link) > 0 { + continue + } + d.SetDistance(link, d.Distance(cell)+1) + newFrontier = append(newFrontier, link) + } + } + frontier = newFrontier + } + return d +} diff --git a/distancegrid.go b/distancegrid.go new file mode 100644 index 0000000..3709b40 --- /dev/null +++ b/distancegrid.go @@ -0,0 +1,64 @@ +package main + +import "strconv" + +type DistanceGrid struct { + Grid + distances *Distances +} + +func NewDistanceGrid(rows, cols int) *DistanceGrid { + g := new(DistanceGrid) + g.distances = new(Distances) + g.Rows, g.Cols = rows, cols + g.prepareGrid() + g.configureCells() + return g +} + +func (d *DistanceGrid) SetDistances(distances *Distances) { + d.distances = distances +} + +func (g *DistanceGrid) ContentsOf(cell *Cell) string { + return strconv.FormatInt(int64(g.distances.Distance(cell)), 36) +} + +func (g *DistanceGrid) 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 := " " + g.ContentsOf(c) + " " + 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 +} diff --git a/distances.go b/distances.go index 16f83e3..0156833 100644 --- a/distances.go +++ b/distances.go @@ -8,6 +8,7 @@ type Distances struct { func NewDistances(root *Cell) *Distances { d := new(Distances) d.root = root + d.cells = make(map[*Cell]int) d.cells[root] = 0 return d } diff --git a/grid.go b/grid.go index 6641d14..e9e83ab 100644 --- a/grid.go +++ b/grid.go @@ -35,15 +35,15 @@ func (g *Grid) prepareGrid() { 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) + 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 { +func (g *Grid) GetCell(row, col int) *Cell { if row < 0 || row >= g.Rows { return nil } @@ -88,6 +88,10 @@ func (g *Grid) EachCell() chan *Cell { return c } +func (g *Grid) ContentsOf(cell *Cell) string { + return " " +} + func (g *Grid) String() string { output := "+" for i := 0; i < g.Cols; i++ { @@ -99,7 +103,7 @@ func (g *Grid) String() string { top := "|" bottom := "+" for _, c := range r { - body := " " + body := " " + g.ContentsOf(c) + " " eastBoundary := "" if c.IsLinked(c.East) { eastBoundary = " " diff --git a/gridInterface.go b/gridInterface.go new file mode 100644 index 0000000..438620c --- /dev/null +++ b/gridInterface.go @@ -0,0 +1,6 @@ +package main + +type Grider interface { + EachRow() chan []*Cell + EachCell() chan *Cell +} diff --git a/main.go b/main.go index d78595e..c6a08fe 100644 --- a/main.go +++ b/main.go @@ -5,17 +5,20 @@ import "fmt" func main() { fmt.Println("Binary Tree") - g := NewGrid(10, 10) + g := NewDistanceGrid(10, 10) b := new(BinaryTree) b.On(g) + start := g.GetCell(0, 0) + distances := start.Distances() + g.SetDistances(distances) fmt.Println(g) fmt.Println("Sidewinder") - g = NewGrid(10, 10) + g = NewDistanceGrid(10, 10) s := new(Sidewinder) s.On(g) + start = g.GetCell(0, 0) + distances = start.Distances() + g.SetDistances(distances) fmt.Println(g) fmt.Println("Showing image") - i := NewImage(40) - i.Save("test.png", i.DrawGrid(g)) - Show("test.png") } diff --git a/sidewinder.go b/sidewinder.go index d83c541..01c0651 100644 --- a/sidewinder.go +++ b/sidewinder.go @@ -18,7 +18,7 @@ func (r cells) sample() *Cell { } } -func (s *Sidewinder) On(g *Grid) *Grid { +func (s *Sidewinder) On(g Grider) Grider { rand.Seed(time.Now().UnixNano()) for r := range g.EachRow() { run := make(cells, 0) diff --git a/test.png b/test.png deleted file mode 100644 index 5da2bd253d10dbf219a1deede0478cbcf116a72e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1694 zcmeAS@N?(olHy`uVBq!ia0y~yV4MiT985qFZD&a!$(HKr;uumf=gsv%zE@@f4uLVL z|D($?cQ@4S?a?dlJMul@_|6CW?HFXwe=mMN_n#EQ|Mznq*NX)#igf5qV^p2RIwgay zoRh|;Kjsv_m!0|h--Y!PkJdfAW}R9vKYZ@<^LN7fO|vgtiSxg??Ov$ZKe1iXO!Rji zG)!zR$0u|bpW9oW_2suSySTM!)sbyq>rAqnbJJ(tf0oBV=RiZm)TbKz=X1WZ-><$e z|7(8kYgxlhCpRxTPfeBEUwwYRbC%WldyC6$f}5A0`(hUSUg-UeZw33G-@Gd@Fb)KU$`c>n zec$`e*go&+`FF0i{zZDpeD`O5kvq-@zrSc~TD>sz_nx=rnWqkg4QL_^Za#1M{ocx# z%KNRx2x{*Hqto}B2xamgEybgIr!2$=k}B8_b2YW zxAX6nGu&}+V;b+gwG($Xhwb(LV^i)t0Qm&s#7XH{A1u?ezL;(MwLQ0bU-H>qz;t={ zTf_2im9tkCZ~b6fG;ndt@PL2E_kXes4FCTZyxyX7FVdQ&MBb@0GX