Advent-of-Code-2023/day23/field.go

146 lines
2.9 KiB
Go

package day23
import (
"fmt"
"os"
"strings"
)
type Coord struct {
Row, Col int
}
type CellType rune
const (
Path CellType = '.'
Tree CellType = '#'
SlideDown CellType = 'v'
SlideUp CellType = '^'
SlideLeft CellType = '<'
SlideRight CellType = '>'
)
type Field struct {
MaxRow, MaxCol int
Cells map[Coord]CellType
StartCol, EndCol int
}
func (f *Field) EndCoord() Coord {
return Coord{Row: f.MaxRow, Col: f.EndCol}
}
func (f *Field) NeighborsPart2(c Coord) (neighbors []Coord) {
symb, exists := f.Cells[c]
if !exists {
panic(fmt.Sprintf("coord %+v not found in field", c))
}
var coords []Coord
switch symb {
case Tree:
panic(fmt.Sprintf("attempting to get neighbors of a tree at %+v", c))
default:
coords = []Coord{
{Row: c.Row + 1, Col: c.Col},
{Row: c.Row - 1, Col: c.Col},
{Row: c.Row, Col: c.Col + 1},
{Row: c.Row, Col: c.Col - 1},
}
}
for _, coord := range coords {
neighborSymb, found := f.Cells[coord]
if !found || neighborSymb == Tree {
continue
}
neighbors = append(neighbors, coord)
}
return
}
func (f *Field) Neighbors(c Coord) (neighbors []Coord) {
symb, exists := f.Cells[c]
if !exists {
panic(fmt.Sprintf("coord %+v not found in field", c))
}
var coords []Coord
switch symb {
case Path:
coords = []Coord{
{Row: c.Row + 1, Col: c.Col},
{Row: c.Row - 1, Col: c.Col},
{Row: c.Row, Col: c.Col + 1},
{Row: c.Row, Col: c.Col - 1},
}
case Tree:
panic(fmt.Sprintf("attempting to get neighbors of a tree at %+v", c))
case SlideDown:
coords = []Coord{{Row: c.Row + 1, Col: c.Col}}
case SlideUp:
coords = []Coord{{Row: c.Row - 1, Col: c.Col}}
case SlideLeft:
coords = []Coord{{Row: c.Row, Col: c.Col - 1}}
case SlideRight:
coords = []Coord{{Row: c.Row, Col: c.Col + 1}}
}
for _, coord := range coords {
neighborSymb, found := f.Cells[coord]
if !found || neighborSymb == Tree {
continue
}
neighbors = append(neighbors, coord)
}
return
}
func (f *Field) String() (result string) {
result += "\n"
for row := 0; row <= f.MaxRow; row++ {
for col := 0; col <= f.MaxCol; col++ {
if row == 0 && col == f.StartCol {
result += "S"
continue
}
if row == f.MaxRow && col == f.EndCol {
result += "E"
continue
}
symb := f.Cells[Coord{Row: row, Col: col}]
result += string(symb)
}
result += "\n"
}
return
}
func ReadField(filename string) (result Field) {
bytes, err := os.ReadFile(filename)
if err != nil {
panic(err)
}
lines := strings.Split(strings.TrimSpace(string(bytes)), "\n")
result.MaxRow = len(lines) - 1
result.MaxCol = len(lines[0]) - 1
rows := make(map[Coord]CellType)
for rowNum, row := range lines {
for colNum, symb := range row {
rows[Coord{Row: rowNum, Col: colNum}] = CellType(symb)
if rowNum == 0 && symb == rune(Path) {
result.StartCol = colNum
}
if rowNum == result.MaxRow && symb == rune(Path) {
result.EndCol = colNum
}
}
}
result.Cells = rows
return
}