From 41e665c169def8d47fa808cf67756c35f4530e3e Mon Sep 17 00:00:00 2001 From: Karma Riuk Date: Wed, 9 Aug 2023 17:44:59 +0200 Subject: [PATCH] Written the ImageWriter --- go.mod | 12 +++++- go.sum | 6 +++ io/writer/image.go | 103 ++++++++++++++++++++++++++++++++++++++++++++- maze/maze.go | 23 ++++++++++ 4 files changed, 140 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index 5033a7e..b060f9c 100644 --- a/go.mod +++ b/go.mod @@ -1,5 +1,13 @@ module maze-solver -go 1.20 +go 1.21 -require golang.org/x/exp v0.0.0-20230801115018-d63ba01acd4b +require ( + github.com/mazznoer/colorgrad v0.9.1 + golang.org/x/exp v0.0.0-20230801115018-d63ba01acd4b +) + +require ( + github.com/lucasb-eyer/go-colorful v1.2.0 // indirect + github.com/mazznoer/csscolorparser v0.1.2 // indirect +) diff --git a/go.sum b/go.sum index 9cf7e1c..247b345 100644 --- a/go.sum +++ b/go.sum @@ -1,2 +1,8 @@ +github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= +github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= +github.com/mazznoer/colorgrad v0.9.1 h1:MB80JYVndKWSMEM1beNqnuOowWGhoQc3DXWXkFp6JlM= +github.com/mazznoer/colorgrad v0.9.1/go.mod h1:WX2R9wt9B47+txJZVVpM9LY+LAGIdi4lTI5wIyreDH4= +github.com/mazznoer/csscolorparser v0.1.2 h1:/UBHuQg792ePmGFzTQAC9u+XbFr7/HzP/Gj70Phyz2A= +github.com/mazznoer/csscolorparser v0.1.2/go.mod h1:Aj22+L/rYN/Y6bj3bYqO3N6g1dtdHtGfQ32xZ5PJQic= golang.org/x/exp v0.0.0-20230801115018-d63ba01acd4b h1:r+vk0EmXNmekl0S0BascoeeoHk/L7wmaW2QF90K+kYI= golang.org/x/exp v0.0.0-20230801115018-d63ba01acd4b/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= diff --git a/io/writer/image.go b/io/writer/image.go index e3727e2..5731a83 100644 --- a/io/writer/image.go +++ b/io/writer/image.go @@ -1,11 +1,110 @@ package writer import ( + "errors" + "image" + "image/color" + "image/draw" + "image/png" "maze-solver/maze" + "os" + + "github.com/mazznoer/colorgrad" ) -type ImageWriter struct{} +type ImageWriter struct { + Filename string + Maze *maze.SolvedMaze + CellWidth, CellHeight int + WallColor, PathColor color.Color + SolutionGradient colorgrad.Gradient + img *image.RGBA +} -func (w *ImageWriter) Write(filename string, maze *maze.SolvedMaze) error { +func (w *ImageWriter) Write() error { + if w.Filename[len(w.Filename)-4:] != ".png" { + return errors.New("Filename of ImageWriter doesn't have .png extension. The only suppported image type is png") + } + + w.img = image.NewRGBA(image.Rect(0, 0, w.Maze.Width*w.CellWidth, w.Maze.Height*w.CellHeight)) + + // Fill the image with walls + draw.Draw(w.img, w.img.Bounds(), &image.Uniform{w.WallColor}, image.Pt(0, 0), draw.Src) + + // Fill in the paths + var x0, y0, width, height int + for _, node := range w.Maze.Nodes { + x0 = node.Coords.X * w.CellWidth + y0 = node.Coords.Y * w.CellHeight + if node.Right != nil { + width = (node.Right.Coords.X - node.Coords.X + 1) * w.CellWidth + height = w.CellHeight + w.draw(x0, y0, width, height, w.PathColor) + } + + if node.Down != nil { + width = w.CellWidth + height = (node.Down.Coords.Y - node.Coords.Y + 1) * w.CellHeight + w.draw(x0, y0, width, height, w.PathColor) + } + } + + // Fill in the solution + total_len := w.getSolutionLength() + colors := w.SolutionGradient.Colors(uint(total_len + 1)) + c := 0 + width, height = w.CellWidth, w.CellHeight + for i, from := range w.Maze.Solution[:len(w.Maze.Solution)-1] { + to := w.Maze.Solution[i+1] + if from.Coords.X == to.Coords.X { + x0 = from.Coords.X * w.CellWidth + + for y := from.Coords.Y; y < to.Coords.Y; y++ { + y0 = y * w.CellHeight + w.draw(x0, y0, width, height, colors[c]) + c++ + } + y0 = to.Coords.Y * w.CellHeight + w.draw(x0, y0, width, height, colors[c]) + } else { + y0 = from.Coords.Y * w.CellHeight + + if from.Coords.X < to.Coords.X { + for x := from.Coords.X; x < to.Coords.X; x++ { + x0 = x * w.CellWidth + w.draw(x0, y0, width, height, colors[c]) + c++ + } + } else { + for x := from.Coords.X; x > to.Coords.X; x-- { + x0 = x * w.CellWidth + w.draw(x0, y0, width, height, colors[c]) + c++ + } + } + x0 = to.Coords.X * w.CellWidth + w.draw(x0, y0, width, height, colors[c]) + } + } + + f, err := os.Create(w.Filename) + if err != nil { + return err + } + png.Encode(f, w.img) + f.Close() return nil } + +func (w *ImageWriter) getSolutionLength() int { + ret := 0 + for i, node := range w.Maze.Solution[:len(w.Maze.Solution)-1] { + next := w.Maze.Solution[i+1] + ret += int(node.Coords.Distance(next.Coords)) + } + return ret +} + +func (w *ImageWriter) draw(x0, y0, width, height int, color color.Color) { + draw.Draw(w.img, image.Rect(x0, y0, x0+width, y0+height), &image.Uniform{color}, image.Pt(0, 0), draw.Src) +} diff --git a/maze/maze.go b/maze/maze.go index 997597c..a603628 100644 --- a/maze/maze.go +++ b/maze/maze.go @@ -1,8 +1,31 @@ package maze +import "math" + type Coordinates struct { X, Y int } + +func (c Coordinates) Distance(o Coordinates) float64 { + x, y := float64(o.X-c.X), float64(o.Y-c.Y) + + if y == 0 { + if x < 0 { + return -x + } + return x + } + + if x == 0 { + if y < 0 { + return -y + } + return y + } + + return math.Sqrt(x*x + y*y) +} + type Node struct { Coords Coordinates Up, Down *Node