Add day 14 part 1 solution
This is a bit messy but I was expecting a twist in part 2master
parent
7ff46673da
commit
4723a2d384
|
@ -0,0 +1,133 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"slices"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Tile int
|
||||||
|
|
||||||
|
const (
|
||||||
|
TileEmpty Tile = iota
|
||||||
|
TileRoundRock
|
||||||
|
TileCubeRock
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
if len(os.Args) != 2 && len(os.Args) != 3 {
|
||||||
|
fmt.Fprintf(os.Stderr, "Usage: %s inputfile\n", os.Args[0])
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
inputFilename := os.Args[1]
|
||||||
|
inputFile, err := os.Open(inputFilename)
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Sprintf("could not open input file: %s", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
defer inputFile.Close()
|
||||||
|
|
||||||
|
inputBytes, err := io.ReadAll(inputFile)
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Sprintf("could not read input file: %s", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
input := strings.TrimSpace(string(inputBytes))
|
||||||
|
inputLines := strings.Split(input, "\n")
|
||||||
|
grid, err := parseTileGrid(inputLines)
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Sprintf("failed to parse input: %s", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("Part 1: %d\n", part1(Clone2D(grid)))
|
||||||
|
}
|
||||||
|
|
||||||
|
func part1(inputGrid [][]Tile) int {
|
||||||
|
rollNorth(inputGrid)
|
||||||
|
load := 0
|
||||||
|
for row, rowItems := range inputGrid {
|
||||||
|
for _, tile := range rowItems {
|
||||||
|
if tile == TileRoundRock {
|
||||||
|
load += len(inputGrid) - row
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return load
|
||||||
|
}
|
||||||
|
|
||||||
|
func rollNorth(inputGrid [][]Tile) {
|
||||||
|
for row, line := range inputGrid {
|
||||||
|
if row == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
for col, tile := range line {
|
||||||
|
if tile != TileRoundRock {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
lastEmptyRow := row
|
||||||
|
for candidateRow := row - 1; candidateRow >= 0; candidateRow-- {
|
||||||
|
if inputGrid[candidateRow][col] == TileEmpty {
|
||||||
|
lastEmptyRow = candidateRow
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inputGrid[row][col] = TileEmpty
|
||||||
|
inputGrid[lastEmptyRow][col] = TileRoundRock
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Clone2D[T any, S ~[][]T](grid S) S {
|
||||||
|
clone := make(S, len(grid))
|
||||||
|
for i, row := range grid {
|
||||||
|
clone[i] = slices.Clone(row)
|
||||||
|
}
|
||||||
|
|
||||||
|
return clone
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseTileGrid(inputLines []string) ([][]Tile, error) {
|
||||||
|
if len(inputLines) == 0 {
|
||||||
|
return [][]Tile{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
grid := make([][]Tile, len(inputLines))
|
||||||
|
for i, line := range inputLines {
|
||||||
|
if len(line) != len(inputLines[0]) {
|
||||||
|
return nil, errors.New("lines have uneven lengths")
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, char := range line {
|
||||||
|
tile, err := tileForRune(char)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
grid[i] = append(grid[i], tile)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return grid, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func tileForRune(r rune) (Tile, error) {
|
||||||
|
switch r {
|
||||||
|
case '.':
|
||||||
|
return TileEmpty, nil
|
||||||
|
case 'O':
|
||||||
|
return TileRoundRock, nil
|
||||||
|
case '#':
|
||||||
|
return TileCubeRock, nil
|
||||||
|
default:
|
||||||
|
return TileEmpty, fmt.Errorf("invalid tile char %c", r)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue