diff --git a/cmd/maze/action.go b/cmd/maze/action.go index 3cd3785..bf498a4 100644 --- a/cmd/maze/action.go +++ b/cmd/maze/action.go @@ -38,10 +38,15 @@ func action(ctx *cli.Context) error { defer termbox.Close() interactive(maze, config.Format) } else { - if config.Image { - maze.PrintImage(config.Output, config.Format, config.Scale) - } else { + switch config.Image { + case "": maze.Print(config.Output, config.Format) + case "png": + maze.PrintPNG(config.Output, config.Format, config.Scale) + case "svg": + maze.PrintSVG(config.Output, config.Format, config.Scale) + default: + return fmt.Errorf("unsupported image format: %s", config.Image) } } return nil diff --git a/cmd/maze/config.go b/cmd/maze/config.go index f85fe41..9843d0b 100644 --- a/cmd/maze/config.go +++ b/cmd/maze/config.go @@ -22,7 +22,7 @@ type Config struct { Start *maze.Point Goal *maze.Point Interactive bool - Image bool + Image string Scale int Solution bool Format *maze.Format @@ -107,10 +107,10 @@ func makeConfig(ctx *cli.Context) (*Config, []error) { } } - image := ctx.GlobalBool("image") - if image { + image := ctx.GlobalString("image") + if image != "" { if file, ok := output.(*os.File); ok && isatty.IsTerminal(file.Fd()) { - errs = append(errs, errors.New("cannot write binary data into the terminal\nuse -output flag")) + errs = append(errs, errors.New("cannot write image data into the terminal\nuse -output flag")) } } diff --git a/cmd/maze/flag.go b/cmd/maze/flag.go index 53505e6..3bc4036 100644 --- a/cmd/maze/flag.go +++ b/cmd/maze/flag.go @@ -35,9 +35,9 @@ var flags = []cli.Flag{ Name: "output, o", Usage: "Output file name", }, - cli.BoolFlag{ + cli.StringFlag{ Name: "image", - Usage: "Generate image", + Usage: "Generate image, `png` or `svg`", }, cli.IntFlag{ Name: "scale", diff --git a/maze.go b/maze.go index 2400221..68e7aa6 100644 --- a/maze.go +++ b/maze.go @@ -322,8 +322,8 @@ func plot(img *image.RGBA, x, y, scale int, c color.Color) { } } -// PrintImage outputs the maze to the IO writer as PNG image -func (maze *Maze) PrintImage(writer io.Writer, format *Format, scale int) { +// PrintPNG outputs the maze to the IO writer as PNG image +func (maze *Maze) PrintPNG(writer io.Writer, format *Format, scale int) { var sb strings.Builder maze.Print(&sb, format) lines := strings.Split(strings.TrimSpace(sb.String()), "\n") @@ -361,6 +361,42 @@ func (maze *Maze) PrintImage(writer io.Writer, format *Format, scale int) { png.Encode(writer, img) } +// PrintSVG outputs the maze to the IO writer as SVG image +func (maze *Maze) PrintSVG(writer io.Writer, format *Format, scale int) { + var sb strings.Builder + maze.Print(&sb, format) + lines := strings.Split(strings.TrimSpace(sb.String()), "\n") + for i, line := range lines { + lines[i] = strings.TrimSpace(line) + } + width := len(lines[0]) / 2 + height := len(lines) + fmt.Fprintf(writer, "\n", width*scale, height*scale) + fmt.Fprintf(writer, "\n", width*scale, height*scale) + for y := 0; y < height; y++ { + if y >= len(lines) { + continue + } + for x := 0; x < width; x++ { + if x*2 >= len(lines[y]) { + continue + } + switch lines[y][x*2 : x*2+2] { + case "##": + fmt.Fprintf(writer, ``+"\n", x*scale, y*scale, scale, scale) + case "::": + fmt.Fprintf(writer, ``+"\n", x*scale, y*scale, scale, scale) + case "S ", " S", "S:", ":S": + fmt.Fprintf(writer, ``+"\n", x*scale, y*scale, scale, scale) + case "G ", " G", "G:", ":G": + fmt.Fprintf(writer, ``+"\n", x*scale, y*scale, scale, scale) + default: + } + } + } + fmt.Fprintln(writer, "") +} + // Print out the maze to the IO writer func (maze *Maze) Print(writer io.Writer, format *Format) { fmt.Fprint(writer, maze.String(format))