maze-solver-go/maze/parser/parser.go
Karma Riuk fcb2bc0d51 Reader -> Reader+Parser refacfotring: create the
parser package, moved the parsing aspect of reader
to parser (still have some naughty stuff like
WallChar and PathChar in parser but it'll be fixed
in next commit)
2023-08-05 10:38:46 +02:00

139 lines
3.5 KiB
Go

package parser
import (
"fmt"
"maze-solver/io/reader"
"maze-solver/maze"
)
const (
WallChar = '#'
PathChar = ' '
)
func Parse(reader reader.Reader) (*maze.Maze, error) {
nodesByCoord := make(map[maze.Coordinates]*maze.Node)
ret := &maze.Maze{}
raw_maze, err := reader.Read()
if err != nil {
return nil, err
}
for y, line := range raw_maze.Data {
fmt.Println(line)
for x := 1; x < len(line)-1; x++ {
char := line[x]
var left_char, right_char, above_char byte
if y > 0 {
left_char = line[x-1]
right_char = line[x+1]
above_char = raw_maze.Data[y-1][x]
}
// Parse first line to get entrance
if y == 0 && char == PathChar {
coords := maze.Coordinates{X: x, Y: y}
node := maze.NewNode(coords)
ret.Nodes = append(ret.Nodes, node)
nodesByCoord[coords] = node
continue
}
// Parse middle of the maze
if y > 0 && char == PathChar &&
(left_char == WallChar && right_char == PathChar ||
left_char == PathChar && right_char == WallChar ||
above_char == PathChar && (left_char == PathChar || right_char == PathChar)) {
coords := maze.Coordinates{X: x, Y: y}
node := maze.NewNode(coords)
lookupNeighbourAbove(&raw_maze.Data, node, &nodesByCoord, ret)
ret.Nodes = append(ret.Nodes, node)
nodesByCoord[coords] = node
if left_char == PathChar && right_char == WallChar ||
above_char == PathChar && (left_char == PathChar || right_char == PathChar) {
lookupNeighbourLeft(&line, node, &nodesByCoord)
}
}
}
}
// Parse last line to get exit
for x, rune := range raw_maze.Data[len(raw_maze.Data)-1] {
char := byte(rune)
if char == PathChar {
coords := maze.Coordinates{X: x, Y: len(raw_maze.Data) - 1}
node := maze.NewNode(coords)
lookupNeighbourAbove(&raw_maze.Data, node, &nodesByCoord, ret)
ret.Nodes = append(ret.Nodes, node)
break
}
}
return ret, nil
}
func lookupNeighbourAbove(Data *[]string, node *maze.Node, nodesByCoord *map[maze.Coordinates]*maze.Node, m *maze.Maze) {
for y := node.Coords.Y - 1; y >= 0; y-- {
neighbour, ok := (*nodesByCoord)[maze.Coordinates{X: node.Coords.X, Y: y}]
if ok {
node.Up = neighbour
neighbour.Down = node
break
}
if y > 0 && (*Data)[y][node.Coords.X] == WallChar {
y++
if y == node.Coords.Y {
break
}
coords := maze.Coordinates{X: node.Coords.X, Y: y}
new_node := maze.NewNode(coords)
lookupNeighbourLeft(&(*Data)[y], new_node, nodesByCoord)
lookupNeighbourRight(&(*Data)[y], new_node, nodesByCoord)
(*nodesByCoord)[coords] = new_node
m.Nodes = append(m.Nodes, new_node)
node.Up = new_node
new_node.Down = node
break
}
}
}
func lookupNeighbourLeft(line *string, node *maze.Node, nodesByCoord *map[maze.Coordinates]*maze.Node) {
for x := node.Coords.X - 1; x > 0; x-- {
if (*line)[x] == WallChar && x < node.Coords.X-1 {
panic(fmt.Sprintf("Found no node before wall while looking to the left at neighbours of node %v", node))
}
neighbour, ok := (*nodesByCoord)[maze.Coordinates{X: x, Y: node.Coords.Y}]
if ok {
node.Left = neighbour
neighbour.Right = node
break
}
}
}
func lookupNeighbourRight(line *string, node *maze.Node, nodesByCoord *map[maze.Coordinates]*maze.Node) {
for x := node.Coords.X + 1; x < len(*line); x++ {
if (*line)[x] == WallChar {
panic(fmt.Sprintf("Found no node before wall while looking to the right at neighbours of node %v", node))
}
neighbour, ok := (*nodesByCoord)[maze.Coordinates{X: x, Y: node.Coords.Y}]
if ok {
node.Right = neighbour
neighbour.Left = node
break
}
}
}