From 4170803ffe4aef77faf432ac425a34a331c77e7e Mon Sep 17 00:00:00 2001 From: alexchao26 Date: Mon, 5 Aug 2024 12:47:41 -0400 Subject: [PATCH] 2024-day14, using new go range over ints --- 2023/day14/main.go | 185 ++++++++++++++++++++++++++++++++++++++++ 2023/day14/main_test.go | 68 +++++++++++++++ 2 files changed, 253 insertions(+) create mode 100644 2023/day14/main.go create mode 100644 2023/day14/main_test.go diff --git a/2023/day14/main.go b/2023/day14/main.go new file mode 100644 index 0000000..f07e2a7 --- /dev/null +++ b/2023/day14/main.go @@ -0,0 +1,185 @@ +package main + +import ( + _ "embed" + "flag" + "fmt" + "strings" + + "github.com/alexchao26/advent-of-code-go/util" +) + +//go:embed input.txt +var input string + +func init() { + // do this in init (not main) so test file has same input + input = strings.TrimRight(input, "\n") + if len(input) == 0 { + panic("empty input.txt file") + } +} + +func main() { + var part int + flag.IntVar(&part, "part", 1, "part 1 or 2") + flag.Parse() + fmt.Println("Running part", part) + + if part == 1 { + ans := part1(input) + util.CopyToClipboard(fmt.Sprintf("%v", ans)) + fmt.Println("Output:", ans) + } else { + ans := part2(input) + util.CopyToClipboard(fmt.Sprintf("%v", ans)) + fmt.Println("Output:", ans) + } +} + +func part1(input string) int { + grid := parseInput(input) + + // tilt north, all O's roll to the top or to the next # + tiltNorth(grid) + + // then calculate total load (total rows) - (row index) per rock + ans := 0 + for r, row := range grid { + for _, val := range row { + if val == "O" { + ans += len(grid) - r + } + } + } + + return ans +} + +func part2(input string) int { + grid := parseInput(input) + + seenStates := map[string]int{} + + cycles := 1000000000 + for c := 0; c < cycles; c++ { + key := stringifyStringGrid(grid) + if lastIndex, ok := seenStates[key]; ok { + cyclePeriod := c - lastIndex + for c+cyclePeriod < cycles { + c += cyclePeriod + } + } + seenStates[key] = c + + // 1 cycle = tilt N, W, S, E + tiltNorth(grid) + tiltWest(grid) + tiltSouth(grid) + tiltEast(grid) + } + + ans := 0 + for r, row := range grid { + for _, val := range row { + if val == "O" { + ans += len(grid) - r + } + } + } + + // 99841 too low + return ans +} + +func tiltNorth(grid [][]string) { + for r, row := range grid { + for c, val := range row { + if val == "O" { + for nextRow := r - 1; nextRow >= 0; nextRow-- { + // can only fall north if nextRow is an empty space + if grid[nextRow][c] == "." { + grid[nextRow][c] = "O" + grid[nextRow+1][c] = "." + } else { + break + } + } + } + } + } +} + +func tiltSouth(grid [][]string) { + for r := len(grid) - 1; r >= 0; r-- { + for c := range len(grid[0]) { + val := grid[r][c] + if val == "O" { + for nextRow := r + 1; nextRow < len(grid); nextRow++ { + // can only fall north if nextRow is an empty space + if grid[nextRow][c] == "." { + grid[nextRow][c] = "O" + grid[nextRow-1][c] = "." + } else { + break + } + } + } + } + } +} + +func tiltEast(grid [][]string) { + for c := len(grid[0]) - 1; c >= 0; c-- { + for r := range grid { + val := grid[r][c] + + if val == "O" { + for nextCol := c + 1; nextCol < len(grid[0]); nextCol++ { + // can only fall north if nextCol is an empty space + if grid[r][nextCol] == "." { + grid[r][nextCol] = "O" + grid[r][nextCol-1] = "." + } else { + break + } + } + } + } + } +} + +func tiltWest(grid [][]string) { + for c := range len(grid[0]) { + for r := range grid { + val := grid[r][c] + + if val == "O" { + for nextCol := c - 1; nextCol >= 0; nextCol-- { + // can only fall north if nextCol is an empty space + if grid[r][nextCol] == "." { + grid[r][nextCol] = "O" + grid[r][nextCol+1] = "." + } else { + break + } + } + } + } + } +} + +func stringifyStringGrid(grid [][]string) string { + ans := "" + for _, row := range grid { + ans += strings.Join(row, "") + } + return ans +} + +func parseInput(input string) (ans [][]string) { + for _, line := range strings.Split(input, "\n") { + ans = append(ans, strings.Split(line, "")) + } + return ans +} diff --git a/2023/day14/main_test.go b/2023/day14/main_test.go new file mode 100644 index 0000000..5c4bb73 --- /dev/null +++ b/2023/day14/main_test.go @@ -0,0 +1,68 @@ +package main + +import ( + "testing" +) + +var example = `O....#.... +O.OO#....# +.....##... +OO.#O....O +.O.....O#. +O.#..O.#.# +..O..#O..O +.......O.. +#....###.. +#OO..#....` + +func Test_part1(t *testing.T) { + tests := []struct { + name string + input string + want int + }{ + { + name: "example", + input: example, + want: 136, + }, + { + name: "actual", + input: input, + want: 108840, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := part1(tt.input); got != tt.want { + t.Errorf("part1() = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_part2(t *testing.T) { + tests := []struct { + name string + input string + want int + }{ + { + name: "example", + input: example, + want: 64, + }, + { + name: "actual", + input: input, + want: 103445, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := part2(tt.input); got != tt.want { + t.Errorf("part2() = %v, want %v", got, tt.want) + } + }) + } +}