package common import ( "bufio" "math" ) type Tile struct { height int steps int } func NewTile(height int) *Tile { return &Tile{height, math.MaxInt32} } func (tile Tile) GetSteps() int { return tile.steps } type Map struct { tiles [][]Tile start *Tile end *Tile } func (heightmap Map) GetEndTile() Tile { return *heightmap.end } func (heightmap Map) GetStartTile() Tile { return *heightmap.start } func (heightmap Map) FindBestStart() Tile { min := math.MaxInt32 var bestStart Tile for i := 0; i < len(heightmap.tiles); i++ { for j := 0; j < len(heightmap.tiles[i]); j++ { if heightmap.tiles[i][j].height == 1 && heightmap.tiles[i][j].steps < min { bestStart = heightmap.tiles[i][j] min = bestStart.steps } } } return bestStart } func (heightmap *Map) ComputeStepsFromStart() { heightmap.start.steps = 0 for i := 0; i < len(heightmap.tiles); i++ { for j := 0; j < len(heightmap.tiles[i]); j++ { if &heightmap.tiles[i][j] == heightmap.start { heightmap.ComputeSteps(i, j, 1) } } } } func (heightmap *Map) ComputeStepsFromEnd() { heightmap.end.steps = 0 for i := 0; i < len(heightmap.tiles); i++ { for j := 0; j < len(heightmap.tiles[i]); j++ { if &heightmap.tiles[i][j] == heightmap.end { heightmap.ComputeStepsInReverse(i, j, 1) } } } } func (heightmap *Map) ComputeSteps(row int, column int, steps int) { if row > 0 && heightmap.tiles[row-1][column].steps > steps && heightmap.tiles[row-1][column].height <= heightmap.tiles[row][column].height + 1 { heightmap.tiles[row-1][column].steps = steps heightmap.ComputeSteps(row-1, column, steps+1) } if row < len(heightmap.tiles)-1 && heightmap.tiles[row+1][column].steps > steps && heightmap.tiles[row+1][column].height <= heightmap.tiles[row][column].height + 1 { heightmap.tiles[row+1][column].steps = steps heightmap.ComputeSteps(row+1, column, steps+1) } if column > 0 && heightmap.tiles[row][column-1].steps > steps && heightmap.tiles[row][column-1].height <= heightmap.tiles[row][column].height + 1 { heightmap.tiles[row][column-1].steps = steps heightmap.ComputeSteps(row, column-1, steps+1) } if column < len(heightmap.tiles[0])-1 && heightmap.tiles[row][column+1].steps > steps && heightmap.tiles[row][column+1].height <= heightmap.tiles[row][column].height + 1 { heightmap.tiles[row][column+1].steps = steps heightmap.ComputeSteps(row, column+1, steps+1) } } func (heightmap *Map) ComputeStepsInReverse(row int, column int, steps int) { if row > 0 && heightmap.tiles[row-1][column].steps > steps && heightmap.tiles[row-1][column].height + 1 >= heightmap.tiles[row][column].height { heightmap.tiles[row-1][column].steps = steps heightmap.ComputeStepsInReverse(row-1, column, steps+1) } if row < len(heightmap.tiles)-1 && heightmap.tiles[row+1][column].steps > steps && heightmap.tiles[row+1][column].height + 1 >= heightmap.tiles[row][column].height { heightmap.tiles[row+1][column].steps = steps heightmap.ComputeStepsInReverse(row+1, column, steps+1) } if column > 0 && heightmap.tiles[row][column-1].steps > steps && heightmap.tiles[row][column-1].height + 1 >= heightmap.tiles[row][column].height { heightmap.tiles[row][column-1].steps = steps heightmap.ComputeStepsInReverse(row, column-1, steps+1) } if column < len(heightmap.tiles[0])-1 && heightmap.tiles[row][column+1].steps > steps && heightmap.tiles[row][column+1].height + 1 >= heightmap.tiles[row][column].height { heightmap.tiles[row][column+1].steps = steps heightmap.ComputeStepsInReverse(row, column+1, steps+1) } } func Parse(scanner bufio.Scanner) Map { heightmap := Map{} for scanner.Scan() { line := scanner.Text() heightmapRow := make([]Tile, len(line)) for i := 0; i < len(line); i++ { if line[i] == 'S' { heightmapRow[i] = *NewTile(1) heightmap.start = &heightmapRow[i] } else if line[i] == 'E' { heightmapRow[i] = *NewTile(26) heightmap.end = &heightmapRow[i] } else { heightmapRow[i] = *NewTile(int(line[i] - 'a' + 1)) } } heightmap.tiles = append(heightmap.tiles, heightmapRow) } return heightmap }