Compare commits
22 Commits
day-5-map-
...
44c8a7659d
| Author | SHA1 | Date | |
|---|---|---|---|
| 44c8a7659d | |||
| 0f07ffcc00 | |||
| e165726833 | |||
| 3f7f533592 | |||
| 0ce04d208b | |||
| daf897cea2 | |||
| 6b1552d65e | |||
| 6b2abb3ebc | |||
| c09e706d42 | |||
| 137cfd379b | |||
| c2a087abf7 | |||
| 6fe9d251bd | |||
| 349e2a8f19 | |||
| 0a19c487cc | |||
| 5f9c19bf47 | |||
| 214c505d8c | |||
| 8e68234caa | |||
| 55383aeedf | |||
| fb73d56bd5 | |||
| 056ac16cf1 | |||
| d2699dfd24 | |||
| 019b87c43c |
22
05/main.go
22
05/main.go
@@ -41,13 +41,11 @@ type point struct {
|
||||
y int
|
||||
}
|
||||
|
||||
type grid struct {
|
||||
m map[point]int
|
||||
}
|
||||
type grid []int
|
||||
|
||||
func (g *grid) AddLine(start, end point, includeHorizontal bool) {
|
||||
for _, p := range LineFromPoints(start, end, includeHorizontal) {
|
||||
g.m[p]++
|
||||
(*g)[p.x+p.y*1000]++
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,17 +106,15 @@ func parsePoints(line string) (point, point) {
|
||||
func partOne() {
|
||||
scanner := makeScanner(false)
|
||||
|
||||
grid := &grid{
|
||||
m: map[point]int{},
|
||||
}
|
||||
grid := make(grid, 1_000_000)
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
start, end := parsePoints(line)
|
||||
grid.AddLine(start, end, false)
|
||||
}
|
||||
var danger int
|
||||
for i := range grid.m {
|
||||
if grid.m[i] > 1 {
|
||||
for i := range grid {
|
||||
if grid[i] > 1 {
|
||||
danger++
|
||||
}
|
||||
}
|
||||
@@ -128,17 +124,15 @@ func partOne() {
|
||||
func partTwo() {
|
||||
scanner := makeScanner(false)
|
||||
|
||||
grid := &grid{
|
||||
m: map[point]int{},
|
||||
}
|
||||
grid := make(grid, 1_000_000)
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
start, end := parsePoints(line)
|
||||
grid.AddLine(start, end, true)
|
||||
}
|
||||
var danger int
|
||||
for i := range grid.m {
|
||||
if grid.m[i] > 1 {
|
||||
for i := range grid {
|
||||
if grid[i] > 1 {
|
||||
danger++
|
||||
}
|
||||
}
|
||||
|
||||
117
06/main.go
Normal file
117
06/main.go
Normal file
@@ -0,0 +1,117 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
start := time.Now()
|
||||
partOne()
|
||||
duration := time.Since(start)
|
||||
partTwo()
|
||||
duration2 := time.Since(start)
|
||||
fmt.Printf("p1: %s, p2: %s\n", duration, duration2-duration)
|
||||
}
|
||||
|
||||
func makeScanner(test bool) *bufio.Scanner {
|
||||
var f *os.File
|
||||
if test {
|
||||
f, _ = os.Open("inputs/testinput")
|
||||
} else {
|
||||
f, _ = os.Open("inputs/input")
|
||||
}
|
||||
reader := bufio.NewReader(f)
|
||||
return bufio.NewScanner(reader)
|
||||
}
|
||||
|
||||
func mustAtoi(line string) int {
|
||||
i, _ := strconv.Atoi(line)
|
||||
return i
|
||||
}
|
||||
|
||||
type school struct {
|
||||
zero int
|
||||
one int
|
||||
two int
|
||||
three int
|
||||
four int
|
||||
five int
|
||||
six int
|
||||
seven int
|
||||
eight int
|
||||
}
|
||||
|
||||
func (s *school) AddOneDay() {
|
||||
s.zero, s.one, s.two, s.three, s.four, s.five, s.six, s.seven, s.eight = s.one, s.two, s.three, s.four, s.five, s.six, s.seven+s.zero, s.eight, s.zero
|
||||
}
|
||||
|
||||
func (s *school) Sum() int {
|
||||
return s.zero + s.one + s.two + s.three + s.four + s.five + s.six + s.seven + s.eight
|
||||
}
|
||||
|
||||
func partOne() {
|
||||
scanner := makeScanner(false)
|
||||
|
||||
// just a single line today
|
||||
scanner.Scan()
|
||||
input := strings.Split(scanner.Text(), ",")
|
||||
school := school{}
|
||||
for _, i := range input {
|
||||
switch i {
|
||||
case "0":
|
||||
school.zero++
|
||||
case "1":
|
||||
school.one++
|
||||
case "2":
|
||||
school.two++
|
||||
case "3":
|
||||
school.three++
|
||||
case "4":
|
||||
school.four++
|
||||
case "5":
|
||||
school.five++
|
||||
case "6":
|
||||
school.six++
|
||||
}
|
||||
}
|
||||
for i := 0; i < 80; i++ {
|
||||
school.AddOneDay()
|
||||
}
|
||||
fmt.Println(school.Sum())
|
||||
}
|
||||
|
||||
func partTwo() {
|
||||
scanner := makeScanner(false)
|
||||
|
||||
// just a single line today
|
||||
scanner.Scan()
|
||||
input := strings.Split(scanner.Text(), ",")
|
||||
school := school{}
|
||||
for _, i := range input {
|
||||
switch i {
|
||||
case "0":
|
||||
school.zero++
|
||||
case "1":
|
||||
school.one++
|
||||
case "2":
|
||||
school.two++
|
||||
case "3":
|
||||
school.three++
|
||||
case "4":
|
||||
school.four++
|
||||
case "5":
|
||||
school.five++
|
||||
case "6":
|
||||
school.six++
|
||||
}
|
||||
}
|
||||
for i := 0; i < 256; i++ {
|
||||
school.AddOneDay()
|
||||
}
|
||||
fmt.Println(school.Sum())
|
||||
}
|
||||
111
07/main.go
Normal file
111
07/main.go
Normal file
@@ -0,0 +1,111 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
start := time.Now()
|
||||
partOne()
|
||||
duration := time.Since(start)
|
||||
partTwo()
|
||||
duration2 := time.Since(start)
|
||||
fmt.Printf("p1: %s, p2: %s\n", duration, duration2-duration)
|
||||
}
|
||||
|
||||
func makeScanner(test bool) *bufio.Scanner {
|
||||
var f *os.File
|
||||
if test {
|
||||
f, _ = os.Open("inputs/testinput")
|
||||
} else {
|
||||
f, _ = os.Open("inputs/input")
|
||||
}
|
||||
reader := bufio.NewReader(f)
|
||||
return bufio.NewScanner(reader)
|
||||
}
|
||||
|
||||
func mustAtoi(line string) int {
|
||||
i, _ := strconv.Atoi(line)
|
||||
return i
|
||||
}
|
||||
|
||||
func fuelCostPartOne(crabs []int, column int) int {
|
||||
var totalFuel int
|
||||
for _, v := range crabs {
|
||||
if column < v {
|
||||
totalFuel += v - column
|
||||
}
|
||||
if column > v {
|
||||
totalFuel += column - v
|
||||
}
|
||||
}
|
||||
return totalFuel
|
||||
}
|
||||
|
||||
func fuelCostPartTwo(crabs []int, column int) int {
|
||||
var totalFuel int
|
||||
for _, v := range crabs {
|
||||
if column < v {
|
||||
totalFuel += ((v - column) * ((v - column) + 1)) / 2
|
||||
}
|
||||
if column > v {
|
||||
totalFuel += ((column - v) * ((column - v) + 1)) / 2
|
||||
}
|
||||
}
|
||||
return totalFuel
|
||||
}
|
||||
|
||||
func partOne() {
|
||||
scanner := makeScanner(false)
|
||||
|
||||
// just a single line today
|
||||
scanner.Scan()
|
||||
input := strings.Split(scanner.Text(), ",")
|
||||
crabs := []int{}
|
||||
var max int
|
||||
for _, v := range input {
|
||||
crab := mustAtoi(v)
|
||||
crabs = append(crabs, crab)
|
||||
if max < crab {
|
||||
max = crab
|
||||
}
|
||||
}
|
||||
lowestFuel := 1000000000 // some initial awful max fuel cost
|
||||
for i := 0; i <= max; i++ {
|
||||
cost := fuelCostPartOne(crabs, i)
|
||||
if cost < lowestFuel {
|
||||
lowestFuel = cost
|
||||
}
|
||||
}
|
||||
fmt.Println(lowestFuel)
|
||||
}
|
||||
|
||||
func partTwo() {
|
||||
scanner := makeScanner(false)
|
||||
|
||||
// just a single line today
|
||||
scanner.Scan()
|
||||
input := strings.Split(scanner.Text(), ",")
|
||||
crabs := []int{}
|
||||
var max int
|
||||
for _, v := range input {
|
||||
crab := mustAtoi(v)
|
||||
crabs = append(crabs, crab)
|
||||
if max < crab {
|
||||
max = crab
|
||||
}
|
||||
}
|
||||
lowestFuel := 1000000000 // some initial awful max fuel cost
|
||||
for i := 0; i <= max; i++ {
|
||||
cost := fuelCostPartTwo(crabs, i)
|
||||
if cost < lowestFuel {
|
||||
lowestFuel = cost
|
||||
}
|
||||
}
|
||||
fmt.Println(lowestFuel)
|
||||
}
|
||||
207
08/main.go
Normal file
207
08/main.go
Normal file
@@ -0,0 +1,207 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
start := time.Now()
|
||||
partOne()
|
||||
duration := time.Since(start)
|
||||
partTwo()
|
||||
duration2 := time.Since(start)
|
||||
fmt.Printf("p1: %s, p2: %s\n", duration, duration2-duration)
|
||||
}
|
||||
|
||||
func makeScanner(test bool) *bufio.Scanner {
|
||||
var f *os.File
|
||||
if test {
|
||||
f, _ = os.Open("inputs/testinput")
|
||||
} else {
|
||||
f, _ = os.Open("inputs/input")
|
||||
}
|
||||
reader := bufio.NewReader(f)
|
||||
return bufio.NewScanner(reader)
|
||||
}
|
||||
|
||||
type display struct {
|
||||
inputs []string
|
||||
outputs []string
|
||||
// mappings from input wires to display pieces
|
||||
top string
|
||||
topleft string
|
||||
topright string
|
||||
center string
|
||||
bottomleft string
|
||||
bottomright string
|
||||
bottom string
|
||||
}
|
||||
|
||||
func parseLine(line string) display {
|
||||
display := display{
|
||||
inputs: make([]string, 0),
|
||||
outputs: make([]string, 0),
|
||||
}
|
||||
acc := []byte{}
|
||||
outputs := false
|
||||
for i := 0; i < len(line); i++ {
|
||||
switch line[i] {
|
||||
case 'a', 'b', 'c', 'd', 'e', 'f', 'g':
|
||||
acc = append(acc, line[i])
|
||||
case ' ':
|
||||
if !outputs {
|
||||
display.inputs = append(display.inputs, string(acc))
|
||||
acc = []byte{}
|
||||
} else {
|
||||
display.outputs = append(display.outputs, string(acc))
|
||||
acc = []byte{}
|
||||
}
|
||||
case '|':
|
||||
i++
|
||||
acc = []byte{}
|
||||
outputs = true
|
||||
}
|
||||
}
|
||||
// and catch the last one
|
||||
display.outputs = append(display.outputs, string(acc))
|
||||
return display
|
||||
}
|
||||
|
||||
func removeAll(s, remove string) string {
|
||||
for _, v := range remove {
|
||||
s = strings.ReplaceAll(s, string(v), "")
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func timesAppears(s string, list []string) (r int) {
|
||||
for _, v := range list {
|
||||
if strings.Contains(v, s) {
|
||||
r++
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func partOne() {
|
||||
scanner := makeScanner(false)
|
||||
|
||||
displays := []display{}
|
||||
for scanner.Scan() {
|
||||
displays = append(displays, parseLine(scanner.Text()))
|
||||
}
|
||||
hit := 0
|
||||
for _, display := range displays {
|
||||
for _, v := range display.outputs {
|
||||
if len(v) == 7 || len(v) == 4 || len(v) == 3 || len(v) == 2 { // 8, 4, 7, 1
|
||||
hit++
|
||||
}
|
||||
}
|
||||
}
|
||||
fmt.Println(hit)
|
||||
}
|
||||
|
||||
func solve(display *display) {
|
||||
mapping := map[int]string{}
|
||||
for _, v := range display.inputs {
|
||||
if len(v) == 2 {
|
||||
mapping[1] = v
|
||||
}
|
||||
if len(v) == 3 {
|
||||
mapping[7] = v
|
||||
}
|
||||
if len(v) == 4 {
|
||||
mapping[4] = v
|
||||
}
|
||||
if len(v) == 7 {
|
||||
mapping[8] = v
|
||||
}
|
||||
}
|
||||
for _, v := range []string{"a", "b", "c", "d", "e", "f", "g"} {
|
||||
if timesAppears(v, display.inputs) == 9 {
|
||||
display.bottomright = v
|
||||
}
|
||||
if timesAppears(v, display.inputs) == 4 {
|
||||
display.bottomleft = v
|
||||
}
|
||||
}
|
||||
|
||||
display.top = removeAll(mapping[7], mapping[1])
|
||||
display.bottom = removeAll(mapping[8], mapping[4]+mapping[7]+display.bottomleft)
|
||||
|
||||
// find 0
|
||||
for _, v := range display.inputs {
|
||||
if len(v) == 6 {
|
||||
remainder := removeAll(v, display.top+display.bottomleft+display.bottom+mapping[1])
|
||||
if len(remainder) == 1 { // this is "0", so we found top-left and center
|
||||
display.topleft = remainder
|
||||
display.center = removeAll(mapping[8], v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
display.topright = removeAll(mapping[8], display.top+display.topleft+display.center+display.bottomleft+display.bottomright+display.bottom)
|
||||
}
|
||||
|
||||
func valueFromSolved(d display, unknown string) string {
|
||||
if len(unknown) == 2 {
|
||||
return "1"
|
||||
}
|
||||
if len(unknown) == 3 {
|
||||
return "7"
|
||||
}
|
||||
if len(unknown) == 4 {
|
||||
return "4"
|
||||
}
|
||||
if len(unknown) == 5 {
|
||||
if strings.Contains(unknown, d.topright) && strings.Contains(unknown, d.bottomright) {
|
||||
return "3"
|
||||
}
|
||||
if strings.Contains(unknown, d.topright) && strings.Contains(unknown, d.bottomleft) {
|
||||
return "2"
|
||||
}
|
||||
if strings.Contains(unknown, d.topleft) && strings.Contains(unknown, d.bottomright) {
|
||||
return "5"
|
||||
}
|
||||
}
|
||||
if len(unknown) == 6 {
|
||||
if !strings.Contains(unknown, d.center) {
|
||||
return "0"
|
||||
}
|
||||
if !strings.Contains(unknown, d.bottomleft) {
|
||||
return "9"
|
||||
}
|
||||
if !strings.Contains(unknown, d.topright) {
|
||||
return "6"
|
||||
}
|
||||
}
|
||||
if len(unknown) == 7 {
|
||||
return "8"
|
||||
}
|
||||
panic("uhoh")
|
||||
}
|
||||
|
||||
func partTwo() {
|
||||
scanner := makeScanner(false)
|
||||
|
||||
displays := []display{}
|
||||
for scanner.Scan() {
|
||||
displays = append(displays, parseLine(scanner.Text()))
|
||||
}
|
||||
total := 0
|
||||
for _, v := range displays {
|
||||
solve(&v)
|
||||
sub := ""
|
||||
for _, integer := range v.outputs {
|
||||
sub += valueFromSolved(v, integer)
|
||||
}
|
||||
i, _ := strconv.Atoi(sub)
|
||||
total += i
|
||||
}
|
||||
fmt.Println(total)
|
||||
}
|
||||
140
09/main.go
Normal file
140
09/main.go
Normal file
@@ -0,0 +1,140 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func mustAtoi(line string) int {
|
||||
i, _ := strconv.Atoi(line)
|
||||
return i
|
||||
}
|
||||
|
||||
func main() {
|
||||
start := time.Now()
|
||||
partOne()
|
||||
duration := time.Since(start)
|
||||
partTwo()
|
||||
duration2 := time.Since(start)
|
||||
fmt.Printf("p1: %s, p2: %s\n", duration, duration2-duration)
|
||||
}
|
||||
|
||||
func makeScanner(test bool) *bufio.Scanner {
|
||||
var f *os.File
|
||||
if test {
|
||||
f, _ = os.Open("inputs/testinput")
|
||||
} else {
|
||||
f, _ = os.Open("inputs/input")
|
||||
}
|
||||
reader := bufio.NewReader(f)
|
||||
return bufio.NewScanner(reader)
|
||||
}
|
||||
|
||||
type floor []int
|
||||
|
||||
func partOne() {
|
||||
scanner := makeScanner(false)
|
||||
width := 100
|
||||
height := 100
|
||||
|
||||
caveFloor := make([]int, width*height)
|
||||
i := 0
|
||||
for scanner.Scan() {
|
||||
row := strings.Split(scanner.Text(), "")
|
||||
for j, v := range row {
|
||||
caveFloor[j+(width*i)] = mustAtoi(v)
|
||||
}
|
||||
i++
|
||||
}
|
||||
// find low points
|
||||
points := 0
|
||||
for row := 0; row < i; row++ {
|
||||
for col := 0; col < width; col++ {
|
||||
islow := 0
|
||||
curr := caveFloor[col+(width*row)]
|
||||
if col == 0 || curr < caveFloor[(col-1)+(width*row)] { // check left edge
|
||||
islow++
|
||||
}
|
||||
if col+1 == width || curr < caveFloor[(col+1)+(width*row)] { // check right edge
|
||||
islow++
|
||||
}
|
||||
if row == 0 || curr < caveFloor[col+(width*(row-1))] { // top
|
||||
islow++
|
||||
}
|
||||
if row+1 == i || curr < caveFloor[col+(width*(row+1))] { // bottom
|
||||
islow++
|
||||
}
|
||||
if islow == 4 {
|
||||
points += curr + 1
|
||||
}
|
||||
}
|
||||
}
|
||||
fmt.Println(points)
|
||||
}
|
||||
|
||||
func downhill(caveFloor []int, width int, col, row int) (int, int) {
|
||||
curr := caveFloor[col+(width*row)]
|
||||
nextcol := col
|
||||
nextrow := row
|
||||
if col > 0 && curr > caveFloor[(col-1)+(width*row)] { // check left edge
|
||||
nextcol = (col - 1)
|
||||
nextrow = row
|
||||
}
|
||||
if col < width-1 && curr > caveFloor[(col+1)+(width*row)] { // check right edge
|
||||
nextcol = (col + 1)
|
||||
nextrow = row
|
||||
}
|
||||
if row > 0 && curr > caveFloor[col+(width*(row-1))] { // top
|
||||
nextcol = col
|
||||
nextrow = row - 1
|
||||
}
|
||||
if col+(width*(row+1)) < len(caveFloor) && curr > caveFloor[col+(width*(row+1))] { // bottom
|
||||
nextcol = col
|
||||
nextrow = row + 1
|
||||
}
|
||||
if nextcol == col && nextrow == row { // found our low point
|
||||
return col, row
|
||||
}
|
||||
return downhill(caveFloor, width, nextcol, nextrow)
|
||||
}
|
||||
|
||||
func partTwo() {
|
||||
scanner := makeScanner(false)
|
||||
width := 100
|
||||
height := 100
|
||||
|
||||
caveFloor := make([]int, width*height)
|
||||
i := 0
|
||||
for scanner.Scan() {
|
||||
row := strings.Split(scanner.Text(), "")
|
||||
for j, v := range row {
|
||||
caveFloor[j+(width*i)] = mustAtoi(v)
|
||||
}
|
||||
i++
|
||||
}
|
||||
|
||||
basins := map[int]int{} // map from low-point location to size of basin
|
||||
for row := 0; row < height; row++ {
|
||||
for col := 0; col < width; col++ {
|
||||
if caveFloor[col+row*width] < 9 {
|
||||
lowcol, lowrow := downhill(caveFloor, width, col, row)
|
||||
basins[lowcol+lowrow*width]++
|
||||
}
|
||||
}
|
||||
}
|
||||
one, two, three := 0, 0, 0
|
||||
for _, v := range basins {
|
||||
if v >= one {
|
||||
one, two, three = v, one, two
|
||||
} else if v >= two {
|
||||
two, three = v, two
|
||||
} else if v >= three {
|
||||
three = v
|
||||
}
|
||||
}
|
||||
fmt.Println(one * two * three)
|
||||
}
|
||||
128
10/main.go
Normal file
128
10/main.go
Normal file
@@ -0,0 +1,128 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
"sort"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
func mustAtoi(line string) int {
|
||||
i, _ := strconv.Atoi(line)
|
||||
return i
|
||||
}
|
||||
|
||||
func main() {
|
||||
start := time.Now()
|
||||
partOne()
|
||||
duration := time.Since(start)
|
||||
partTwo()
|
||||
duration2 := time.Since(start)
|
||||
fmt.Printf("p1: %s, p2: %s\n", duration, duration2-duration)
|
||||
}
|
||||
|
||||
func makeScanner(test bool) *bufio.Scanner {
|
||||
var f *os.File
|
||||
if test {
|
||||
f, _ = os.Open("inputs/testinput")
|
||||
} else {
|
||||
f, _ = os.Open("inputs/input")
|
||||
}
|
||||
reader := bufio.NewReader(f)
|
||||
return bufio.NewScanner(reader)
|
||||
}
|
||||
|
||||
type parsed struct {
|
||||
errorChar rune
|
||||
missingkeys []rune
|
||||
autocompleteTotal int
|
||||
}
|
||||
|
||||
func pop(stack []rune) (rune, []rune) {
|
||||
pop := stack[len(stack)-1]
|
||||
return pop, stack[:len(stack)-1]
|
||||
}
|
||||
|
||||
func parseLine(line string) parsed {
|
||||
stack := []rune{}
|
||||
for _, v := range line {
|
||||
var p rune
|
||||
switch v {
|
||||
case '[', '{', '<', '(':
|
||||
stack = append(stack, v)
|
||||
case '>':
|
||||
p, stack = pop(stack)
|
||||
if p != '<' {
|
||||
return parsed{errorChar: v}
|
||||
}
|
||||
case ')':
|
||||
p, stack = pop(stack)
|
||||
if p != '(' {
|
||||
return parsed{errorChar: v}
|
||||
}
|
||||
case ']':
|
||||
p, stack = pop(stack)
|
||||
if p != '[' {
|
||||
return parsed{errorChar: v}
|
||||
}
|
||||
case '}':
|
||||
p, stack = pop(stack)
|
||||
if p != '{' {
|
||||
return parsed{errorChar: v}
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(stack) != 0 {
|
||||
return parsed{missingkeys: stack}
|
||||
}
|
||||
return parsed{}
|
||||
}
|
||||
|
||||
func partOne() {
|
||||
scanner := makeScanner(false)
|
||||
|
||||
sum := 0
|
||||
for scanner.Scan() {
|
||||
result := parseLine(scanner.Text())
|
||||
switch result.errorChar {
|
||||
case ')':
|
||||
sum += 3
|
||||
case ']':
|
||||
sum += 57
|
||||
case '}':
|
||||
sum += 1197
|
||||
case '>':
|
||||
sum += 25137
|
||||
}
|
||||
}
|
||||
fmt.Println(sum)
|
||||
}
|
||||
|
||||
func partTwo() {
|
||||
scanner := makeScanner(false)
|
||||
|
||||
scores := []int{}
|
||||
for scanner.Scan() {
|
||||
result := parseLine(scanner.Text())
|
||||
if result.errorChar == 0 {
|
||||
for i := len(result.missingkeys) - 1; i >= 0; i-- {
|
||||
result.autocompleteTotal *= 5
|
||||
switch result.missingkeys[i] {
|
||||
case '(':
|
||||
result.autocompleteTotal += 1
|
||||
case '[':
|
||||
result.autocompleteTotal += 2
|
||||
case '{':
|
||||
result.autocompleteTotal += 3
|
||||
case '<':
|
||||
result.autocompleteTotal += 4
|
||||
}
|
||||
}
|
||||
scores = append(scores, result.autocompleteTotal)
|
||||
}
|
||||
}
|
||||
sort.Ints(scores)
|
||||
fmt.Println(scores[(len(scores) / 2)])
|
||||
}
|
||||
147
11/main.go
Normal file
147
11/main.go
Normal file
@@ -0,0 +1,147 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
func mustAtoi(line byte) int {
|
||||
i, _ := strconv.Atoi(string(line))
|
||||
return i
|
||||
}
|
||||
|
||||
func main() {
|
||||
start := time.Now()
|
||||
partOne()
|
||||
duration := time.Since(start)
|
||||
partTwo()
|
||||
duration2 := time.Since(start)
|
||||
fmt.Printf("p1: %s, p2: %s\n", duration, duration2-duration)
|
||||
}
|
||||
|
||||
func makeScanner(test bool) *bufio.Scanner {
|
||||
var f *os.File
|
||||
if test {
|
||||
f, _ = os.Open("inputs/testinput")
|
||||
} else {
|
||||
f, _ = os.Open("inputs/input")
|
||||
}
|
||||
reader := bufio.NewReader(f)
|
||||
return bufio.NewScanner(reader)
|
||||
}
|
||||
|
||||
type octopus struct {
|
||||
energy int
|
||||
flashed bool
|
||||
}
|
||||
|
||||
type octopi []octopus // index is col + (row*10)
|
||||
|
||||
func (o *octopi) incrementEnergyLevels() {
|
||||
for i := range *o {
|
||||
(*o)[i].energy++
|
||||
}
|
||||
}
|
||||
|
||||
func (o *octopi) flash() bool {
|
||||
flash := false
|
||||
toIncrement := make([]int, 100)
|
||||
for i := range *o {
|
||||
if (*o)[i].energy > 9 && !(*o)[i].flashed {
|
||||
(*o)[i].flashed = true
|
||||
flash = true
|
||||
if i > 9 {
|
||||
toIncrement[i-10]++ // above
|
||||
}
|
||||
if i < 90 {
|
||||
toIncrement[i+10]++ // below
|
||||
}
|
||||
if i%10 != 9 {
|
||||
toIncrement[i+1]++ // right
|
||||
}
|
||||
if i%10 != 0 {
|
||||
toIncrement[i-1]++ // left
|
||||
}
|
||||
if i%10 != 0 && i > 9 {
|
||||
toIncrement[i-11]++ // above-left
|
||||
}
|
||||
if i%10 != 9 && i > 9 {
|
||||
toIncrement[i-9]++ // above-right
|
||||
}
|
||||
if i%10 != 0 && i < 90 {
|
||||
toIncrement[i+9]++ // below-left
|
||||
}
|
||||
if i%10 != 9 && i < 90 {
|
||||
toIncrement[i+11]++ // below-right
|
||||
}
|
||||
}
|
||||
}
|
||||
for i := range toIncrement {
|
||||
(*o)[i].energy += toIncrement[i]
|
||||
}
|
||||
return flash
|
||||
}
|
||||
|
||||
func (o *octopi) reset() int {
|
||||
count := 0
|
||||
for i := range *o {
|
||||
if (*o)[i].energy > 9 {
|
||||
count++
|
||||
(*o)[i].energy = 0
|
||||
(*o)[i].flashed = false
|
||||
}
|
||||
}
|
||||
return count
|
||||
}
|
||||
|
||||
func partOne() {
|
||||
scanner := makeScanner(false)
|
||||
|
||||
cave := octopi{}
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
for i := range line {
|
||||
cave = append(cave, octopus{energy: mustAtoi(line[i])})
|
||||
}
|
||||
}
|
||||
total := 0
|
||||
for step := 0; step < 100; step++ {
|
||||
cave.incrementEnergyLevels()
|
||||
for {
|
||||
if !cave.flash() {
|
||||
break
|
||||
}
|
||||
}
|
||||
total += cave.reset()
|
||||
}
|
||||
fmt.Println(total)
|
||||
}
|
||||
|
||||
func partTwo() {
|
||||
scanner := makeScanner(false)
|
||||
|
||||
cave := octopi{}
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
for i := range line {
|
||||
cave = append(cave, octopus{energy: mustAtoi(line[i])})
|
||||
}
|
||||
}
|
||||
step := 0
|
||||
for {
|
||||
step++
|
||||
cave.incrementEnergyLevels()
|
||||
for {
|
||||
if !cave.flash() {
|
||||
break
|
||||
}
|
||||
}
|
||||
if cave.reset() == 100 {
|
||||
break
|
||||
}
|
||||
}
|
||||
fmt.Println(step)
|
||||
}
|
||||
140
12/main.go
Normal file
140
12/main.go
Normal file
@@ -0,0 +1,140 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
start := time.Now()
|
||||
partOne()
|
||||
duration := time.Since(start)
|
||||
partTwo()
|
||||
duration2 := time.Since(start)
|
||||
fmt.Printf("p1: %s, p2: %s\n", duration, duration2-duration)
|
||||
}
|
||||
|
||||
func makeScanner(test bool) *bufio.Scanner {
|
||||
var f *os.File
|
||||
if test {
|
||||
f, _ = os.Open("inputs/testinput")
|
||||
} else {
|
||||
f, _ = os.Open("inputs/input")
|
||||
}
|
||||
reader := bufio.NewReader(f)
|
||||
return bufio.NewScanner(reader)
|
||||
}
|
||||
|
||||
type room struct {
|
||||
name string
|
||||
links []string
|
||||
}
|
||||
|
||||
func isBigRoom(name string) bool {
|
||||
return strings.ToUpper(name) == name
|
||||
}
|
||||
|
||||
func canVisit(targetRoom room, visitedRooms []string) bool {
|
||||
if isBigRoom(targetRoom.name) {
|
||||
return true
|
||||
}
|
||||
for _, v := range visitedRooms {
|
||||
if targetRoom.name == v {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func doubleSmallAlready(visitedRooms []string) bool {
|
||||
counts := map[string]int{}
|
||||
for _, v := range visitedRooms {
|
||||
counts[v]++
|
||||
}
|
||||
for room, v := range counts {
|
||||
if v == 2 && !isBigRoom(room) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func descend(rooms map[string]room, currentRoom string, path []string, success chan struct{}, canVisitSmallRoomTwice bool) {
|
||||
var wg sync.WaitGroup
|
||||
if currentRoom == "end" {
|
||||
success <- struct{}{}
|
||||
return
|
||||
}
|
||||
for _, link := range rooms[currentRoom].links {
|
||||
newPath := []string{currentRoom}
|
||||
newPath = append(newPath, path...)
|
||||
if canVisit(rooms[link], path) || // part one
|
||||
(canVisitSmallRoomTwice && !doubleSmallAlready(newPath) && link != "start") { // part two
|
||||
wg.Add(1)
|
||||
go func(link string, path []string) {
|
||||
defer wg.Done()
|
||||
// in day 2, skip checks once we know we've visited a small room twice
|
||||
descend(rooms, link, path, success, canVisitSmallRoomTwice && !doubleSmallAlready(newPath))
|
||||
}(link, newPath)
|
||||
}
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func partOne() {
|
||||
scanner := makeScanner(false)
|
||||
|
||||
rooms := map[string]room{}
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
p := strings.Split(line, "-")
|
||||
// create rooms if we haven't seen them before
|
||||
if _, ok := rooms[p[0]]; !ok {
|
||||
rooms[p[0]] = room{name: p[0]}
|
||||
}
|
||||
if _, ok := rooms[p[1]]; !ok {
|
||||
rooms[p[1]] = room{name: p[1]}
|
||||
}
|
||||
// set up links
|
||||
a := rooms[p[0]]
|
||||
b := rooms[p[1]]
|
||||
a.links = append(a.links, rooms[p[1]].name)
|
||||
b.links = append(b.links, rooms[p[0]].name)
|
||||
rooms[p[0]] = a
|
||||
rooms[p[1]] = b
|
||||
}
|
||||
successes := make(chan struct{}, 10000)
|
||||
descend(rooms, "start", []string{}, successes, false)
|
||||
fmt.Printf("%+v\n", len(successes))
|
||||
}
|
||||
|
||||
func partTwo() {
|
||||
scanner := makeScanner(false)
|
||||
|
||||
rooms := map[string]room{}
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
p := strings.Split(line, "-")
|
||||
// create rooms if we haven't seen them before
|
||||
if _, ok := rooms[p[0]]; !ok {
|
||||
rooms[p[0]] = room{name: p[0]}
|
||||
}
|
||||
if _, ok := rooms[p[1]]; !ok {
|
||||
rooms[p[1]] = room{name: p[1]}
|
||||
}
|
||||
// set up links
|
||||
a := rooms[p[0]]
|
||||
b := rooms[p[1]]
|
||||
a.links = append(a.links, rooms[p[1]].name)
|
||||
b.links = append(b.links, rooms[p[0]].name)
|
||||
rooms[p[0]] = a
|
||||
rooms[p[1]] = b
|
||||
}
|
||||
successes := make(chan struct{}, 200000)
|
||||
descend(rooms, "start", []string{}, successes, true)
|
||||
fmt.Printf("%+v\n", len(successes))
|
||||
}
|
||||
133
13/main.go
Normal file
133
13/main.go
Normal file
@@ -0,0 +1,133 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func mustAtoi(line string) int {
|
||||
i, _ := strconv.Atoi(line)
|
||||
return i
|
||||
}
|
||||
|
||||
func main() {
|
||||
start := time.Now()
|
||||
partOne()
|
||||
duration := time.Since(start)
|
||||
partTwo()
|
||||
duration2 := time.Since(start)
|
||||
fmt.Printf("p1: %s, p2: %s\n", duration, duration2-duration)
|
||||
}
|
||||
|
||||
func makeScanner(test bool) *bufio.Scanner {
|
||||
var f *os.File
|
||||
if test {
|
||||
f, _ = os.Open("inputs/testinput")
|
||||
} else {
|
||||
f, _ = os.Open("inputs/input")
|
||||
}
|
||||
reader := bufio.NewReader(f)
|
||||
return bufio.NewScanner(reader)
|
||||
}
|
||||
|
||||
type point struct {
|
||||
x int
|
||||
y int
|
||||
}
|
||||
|
||||
func partOne() {
|
||||
scanner := makeScanner(false)
|
||||
|
||||
// parse points
|
||||
points := make(map[point]struct{}, 0)
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
if line == "" {
|
||||
break
|
||||
}
|
||||
p := strings.Split(line, ",")
|
||||
points[point{
|
||||
x: mustAtoi(p[0]),
|
||||
y: mustAtoi(p[1]),
|
||||
}] = struct{}{}
|
||||
}
|
||||
|
||||
// make first fold
|
||||
scanner.Scan()
|
||||
f := strings.Split(scanner.Text(), "=")
|
||||
orientation := strings.Split(f[0], " ")[2]
|
||||
crease := mustAtoi(f[1])
|
||||
if orientation == "y" {
|
||||
for p := range points {
|
||||
if p.y > crease {
|
||||
delete(points, p)
|
||||
points[point{x: p.x, y: p.y - ((p.y - crease) * 2)}] = struct{}{}
|
||||
}
|
||||
}
|
||||
}
|
||||
if orientation == "x" {
|
||||
for p := range points {
|
||||
if p.x > crease {
|
||||
delete(points, p)
|
||||
points[point{x: p.x - ((p.x - crease) * 2), y: p.y}] = struct{}{}
|
||||
}
|
||||
}
|
||||
}
|
||||
fmt.Println(len(points))
|
||||
}
|
||||
|
||||
func partTwo() {
|
||||
scanner := makeScanner(false)
|
||||
|
||||
// parse points
|
||||
points := make(map[point]struct{}, 0)
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
if line == "" {
|
||||
break
|
||||
}
|
||||
p := strings.Split(line, ",")
|
||||
points[point{
|
||||
x: mustAtoi(p[0]),
|
||||
y: mustAtoi(p[1]),
|
||||
}] = struct{}{}
|
||||
}
|
||||
// do folds
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
f := strings.Split(line, "=")
|
||||
orientation := strings.Split(f[0], " ")[2]
|
||||
crease := mustAtoi(f[1])
|
||||
if orientation == "y" {
|
||||
for p := range points {
|
||||
if p.y > crease {
|
||||
delete(points, p)
|
||||
points[point{x: p.x, y: p.y - ((p.y - crease) * 2)}] = struct{}{}
|
||||
}
|
||||
}
|
||||
}
|
||||
if orientation == "x" {
|
||||
for p := range points {
|
||||
if p.x > crease {
|
||||
delete(points, p)
|
||||
points[point{x: p.x - ((p.x - crease) * 2), y: p.y}] = struct{}{}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// print letters
|
||||
for y := 0; y < 6; y++ { // six units tall
|
||||
for x := 0; x < 5*8; x++ { // 5 units wide, 8 letters
|
||||
if _, ok := points[point{x: x, y: y}]; ok {
|
||||
fmt.Printf("#")
|
||||
} else {
|
||||
fmt.Printf(" ")
|
||||
}
|
||||
}
|
||||
fmt.Printf("\n")
|
||||
}
|
||||
}
|
||||
153
14/main.go
Normal file
153
14/main.go
Normal file
@@ -0,0 +1,153 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
start := time.Now()
|
||||
partOne()
|
||||
duration := time.Since(start)
|
||||
partTwo()
|
||||
duration2 := time.Since(start)
|
||||
fmt.Printf("p1: %s, p2: %s\n", duration, duration2-duration)
|
||||
}
|
||||
|
||||
func makeScanner(test bool) *bufio.Scanner {
|
||||
var f *os.File
|
||||
if test {
|
||||
f, _ = os.Open("inputs/testinput")
|
||||
} else {
|
||||
f, _ = os.Open("inputs/input")
|
||||
}
|
||||
reader := bufio.NewReader(f)
|
||||
return bufio.NewScanner(reader)
|
||||
}
|
||||
|
||||
func partOne() {
|
||||
scanner := makeScanner(false)
|
||||
|
||||
polymer := map[string]int{}
|
||||
|
||||
// initial state
|
||||
scanner.Scan()
|
||||
initial := scanner.Text()
|
||||
for i := 0; i < len(initial)-1; i++ {
|
||||
pair := string(initial[i]) + string(initial[i+1])
|
||||
polymer[pair]++
|
||||
}
|
||||
|
||||
// eat empty line
|
||||
scanner.Scan()
|
||||
|
||||
// parse rules
|
||||
rulemap := map[string][]string{}
|
||||
for scanner.Scan() {
|
||||
rule := strings.Split(scanner.Text(), " -> ")
|
||||
rulemap[rule[0]] = []string{
|
||||
string(rule[0][0]) + rule[1],
|
||||
rule[1] + string(rule[0][1]),
|
||||
}
|
||||
}
|
||||
|
||||
// apply rules
|
||||
for i := 0; i < 10; i++ {
|
||||
newPolymer := map[string]int{}
|
||||
for p, c := range polymer {
|
||||
newPolymer[rulemap[p][0]] += c
|
||||
newPolymer[rulemap[p][1]] += c
|
||||
}
|
||||
polymer = newPolymer
|
||||
}
|
||||
|
||||
// count elements
|
||||
count := map[string]int{}
|
||||
for p, c := range polymer {
|
||||
count[string(p[0])] += c
|
||||
count[string(p[1])] += c
|
||||
}
|
||||
|
||||
// find max and min
|
||||
max, min := 0, 0
|
||||
for _, c := range count {
|
||||
if c > max {
|
||||
max = c
|
||||
}
|
||||
if c < min || min == 0 {
|
||||
min = c
|
||||
}
|
||||
}
|
||||
|
||||
// handle rounding
|
||||
if (max-min)%2 == 1 {
|
||||
fmt.Println((max-min)/2 + 1)
|
||||
} else {
|
||||
fmt.Println((max - min) / 2)
|
||||
}
|
||||
}
|
||||
|
||||
func partTwo() {
|
||||
scanner := makeScanner(false)
|
||||
|
||||
polymer := map[string]int{}
|
||||
|
||||
// initial state
|
||||
scanner.Scan()
|
||||
initial := scanner.Text()
|
||||
for i := 0; i < len(initial)-1; i++ {
|
||||
pair := string(initial[i]) + string(initial[i+1])
|
||||
polymer[pair]++
|
||||
}
|
||||
|
||||
// eat empty line
|
||||
scanner.Scan()
|
||||
|
||||
// parse rules
|
||||
rulemap := map[string][]string{}
|
||||
for scanner.Scan() {
|
||||
rule := strings.Split(scanner.Text(), " -> ")
|
||||
rulemap[rule[0]] = []string{
|
||||
string(rule[0][0]) + rule[1],
|
||||
rule[1] + string(rule[0][1]),
|
||||
}
|
||||
}
|
||||
|
||||
// apply rules
|
||||
for i := 0; i < 40; i++ {
|
||||
newPolymer := map[string]int{}
|
||||
for p, c := range polymer {
|
||||
newPolymer[rulemap[p][0]] += c
|
||||
newPolymer[rulemap[p][1]] += c
|
||||
}
|
||||
polymer = newPolymer
|
||||
}
|
||||
|
||||
// count elements
|
||||
count := map[string]int{}
|
||||
for p, c := range polymer {
|
||||
count[string(p[0])] += c
|
||||
count[string(p[1])] += c
|
||||
}
|
||||
|
||||
// find max and min
|
||||
max, min := 0, 0
|
||||
for _, c := range count {
|
||||
if c > max {
|
||||
max = c
|
||||
}
|
||||
if c < min || min == 0 {
|
||||
min = c
|
||||
}
|
||||
}
|
||||
|
||||
// handle rounding
|
||||
if (max-min)%2 == 1 {
|
||||
fmt.Println((max-min)/2 + 1)
|
||||
} else {
|
||||
fmt.Println((max - min) / 2)
|
||||
}
|
||||
}
|
||||
128
15/main.go
Normal file
128
15/main.go
Normal file
@@ -0,0 +1,128 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
func mustAtoi(line string) int {
|
||||
i, _ := strconv.Atoi(line)
|
||||
return i
|
||||
}
|
||||
|
||||
func main() {
|
||||
start := time.Now()
|
||||
partOne()
|
||||
duration := time.Since(start)
|
||||
partTwo()
|
||||
duration2 := time.Since(start)
|
||||
fmt.Printf("p1: %s, p2: %s\n", duration, duration2-duration)
|
||||
}
|
||||
|
||||
func makeScanner(test bool) *bufio.Scanner {
|
||||
var f *os.File
|
||||
if test {
|
||||
f, _ = os.Open("inputs/testinput")
|
||||
} else {
|
||||
f, _ = os.Open("inputs/input")
|
||||
}
|
||||
reader := bufio.NewReader(f)
|
||||
return bufio.NewScanner(reader)
|
||||
}
|
||||
|
||||
type room struct {
|
||||
row int
|
||||
col int
|
||||
distance int
|
||||
cost int
|
||||
}
|
||||
|
||||
func partOne() {
|
||||
scanner := makeScanner(false)
|
||||
|
||||
grid := [100][100]room{}
|
||||
col := 0
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
for row, v := range line {
|
||||
r := room{
|
||||
distance: 1000,
|
||||
cost: mustAtoi(string(v)),
|
||||
}
|
||||
grid[row][col] = r
|
||||
}
|
||||
col++
|
||||
}
|
||||
grid[0][0].distance = 0
|
||||
|
||||
for row := 0; row < 100; row++ {
|
||||
for col := 0; col < 100; col++ {
|
||||
if col+1 < 100 {
|
||||
d := grid[row][col+1].distance
|
||||
// if the cost of the space is less than the current known distance, this is the best route there
|
||||
if d > grid[row][col+1].cost+grid[row][col].distance {
|
||||
grid[row][col+1].distance = grid[row][col].distance + grid[row][col+1].cost
|
||||
}
|
||||
}
|
||||
if row+1 < 100 {
|
||||
d := grid[row+1][col].distance
|
||||
// if the cost of the space is less than the current known distance, this is the best route there
|
||||
if d > grid[row+1][col].cost+grid[row][col].distance {
|
||||
grid[row+1][col].distance = grid[row][col].distance + grid[row+1][col].cost
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fmt.Println(grid[99][99].distance)
|
||||
}
|
||||
|
||||
func partTwo() {
|
||||
scanner := makeScanner(false)
|
||||
width := 100
|
||||
scale := 5
|
||||
len := width * scale
|
||||
|
||||
grid := [500][500]room{}
|
||||
col := 0
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
for row, v := range line {
|
||||
for i := 0; i < scale; i++ {
|
||||
for j := 0; j < scale; j++ {
|
||||
cost := mustAtoi(string(v)) + i + j
|
||||
if cost > 9 {
|
||||
cost = ((mustAtoi(string(v)) + i + j) % 10) + 1
|
||||
}
|
||||
grid[row+i*width][col+j*width] = room{
|
||||
row: row + i*width,
|
||||
col: col + j*width,
|
||||
distance: 100000,
|
||||
cost: cost,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
col++
|
||||
}
|
||||
grid[0][0].distance = 0
|
||||
|
||||
for row := 0; row < len; row++ {
|
||||
for col := 0; col < len; col++ {
|
||||
// if the cost of the space is less than the current known distance, this is the best route there
|
||||
if col+1 < len {
|
||||
if grid[row][col+1].distance > grid[row][col+1].cost+grid[row][col].distance {
|
||||
grid[row][col+1].distance = grid[row][col].distance + grid[row][col+1].cost
|
||||
}
|
||||
}
|
||||
if row+1 < len {
|
||||
if grid[row+1][col].distance > grid[row+1][col].cost+grid[row][col].distance {
|
||||
grid[row+1][col].distance = grid[row][col].distance + grid[row+1][col].cost
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fmt.Println(grid[width*scale-1][width*scale-1])
|
||||
}
|
||||
154
16/main.go
Normal file
154
16/main.go
Normal file
@@ -0,0 +1,154 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
start := time.Now()
|
||||
partOne()
|
||||
duration := time.Since(start)
|
||||
partTwo()
|
||||
duration2 := time.Since(start)
|
||||
fmt.Printf("p1: %s, p2: %s\n", duration, duration2-duration)
|
||||
}
|
||||
|
||||
var hexMap = map[rune][]uint8{
|
||||
'0': {0, 0, 0, 0},
|
||||
'1': {0, 0, 0, 1},
|
||||
'2': {0, 0, 1, 0},
|
||||
'3': {0, 0, 1, 1},
|
||||
'4': {0, 1, 0, 0},
|
||||
'5': {0, 1, 0, 1},
|
||||
'6': {0, 1, 1, 0},
|
||||
'7': {0, 1, 1, 1},
|
||||
'8': {1, 0, 0, 0},
|
||||
'9': {1, 0, 0, 1},
|
||||
'A': {1, 0, 1, 0},
|
||||
'B': {1, 0, 1, 1},
|
||||
'C': {1, 1, 0, 0},
|
||||
'D': {1, 1, 0, 1},
|
||||
'E': {1, 1, 1, 0},
|
||||
'F': {1, 1, 1, 1},
|
||||
}
|
||||
|
||||
func makeScanner(test bool) *bufio.Scanner {
|
||||
var f *os.File
|
||||
if test {
|
||||
f, _ = os.Open("inputs/testinput")
|
||||
} else {
|
||||
f, _ = os.Open("inputs/input")
|
||||
}
|
||||
reader := bufio.NewReader(f)
|
||||
return bufio.NewScanner(reader)
|
||||
}
|
||||
|
||||
func parseNumber(stream []uint8, length int) int64 {
|
||||
result := int64(0)
|
||||
for i := 0; i < length; i++ {
|
||||
result += int64(stream[i]) << (length - 1 - i)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
type packet struct {
|
||||
version int64
|
||||
typeID int64
|
||||
subPackets []packet
|
||||
encodedNumber int64
|
||||
}
|
||||
|
||||
func getPacketVersion(stream []uint8) int64 {
|
||||
return parseNumber(stream, 3)
|
||||
}
|
||||
|
||||
func getPacketType(stream []uint8) int64 {
|
||||
return parseNumber(stream, 3)
|
||||
}
|
||||
|
||||
func getSubpacketLength(t uint8, stream []uint8) (int, int64) {
|
||||
if t == 0 {
|
||||
return 15, parseNumber(stream, 15)
|
||||
}
|
||||
if t == 1 {
|
||||
return 11, parseNumber(stream, 11)
|
||||
}
|
||||
return 0, 0
|
||||
}
|
||||
|
||||
func parsePayload(stream []uint8) (int64, int) {
|
||||
num := []uint8{}
|
||||
pos := 0
|
||||
chars := 0
|
||||
for {
|
||||
currentsegment := stream[pos : pos+5]
|
||||
chars += 4
|
||||
num = append(num, currentsegment[1:5]...)
|
||||
pos += 5
|
||||
if currentsegment[0] == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
return parseNumber(num, chars), pos
|
||||
}
|
||||
|
||||
func parsePackets(stream []uint8) (int, []packet) {
|
||||
if len(stream) <= 7 {
|
||||
return 0, []packet{}
|
||||
}
|
||||
parsedPacket := packet{}
|
||||
parsedPacket.version = getPacketVersion(stream[0:3])
|
||||
parsedPacket.typeID = getPacketType(stream[3:6])
|
||||
if parsedPacket.typeID == 4 {
|
||||
encoded, consumed := parsePayload(stream[6:])
|
||||
parsedPacket.encodedNumber = encoded
|
||||
return consumed + 6, []packet{parsedPacket} // 6 is packet header length
|
||||
} else {
|
||||
parsed := 0
|
||||
size, subpacketlength := getSubpacketLength(stream[6], stream[7:])
|
||||
for {
|
||||
consumed, subs := parsePackets(stream[7+size+parsed:])
|
||||
parsedPacket.subPackets = append(parsedPacket.subPackets, subs...)
|
||||
parsed += consumed
|
||||
if size == 11 && int64(len(parsedPacket.subPackets)) == subpacketlength {
|
||||
return parsed + 7 + size, []packet{parsedPacket}
|
||||
|
||||
} else if size == 15 && int64(parsed) > subpacketlength || consumed == 0 {
|
||||
return parsed + 7 + size, []packet{parsedPacket}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func countVersions(packets []packet) int {
|
||||
i := 0
|
||||
for _, p := range packets {
|
||||
i += int(p.version)
|
||||
i += countVersions(p.subPackets)
|
||||
}
|
||||
return i
|
||||
}
|
||||
|
||||
func partOne() {
|
||||
scanner := makeScanner(false)
|
||||
|
||||
scanner.Scan()
|
||||
line := scanner.Text()
|
||||
stream := []uint8{}
|
||||
for _, hex := range line {
|
||||
stream = append(stream, hexMap[hex]...)
|
||||
}
|
||||
_, parsedPacket := parsePackets(stream)
|
||||
fmt.Println(countVersions(parsedPacket))
|
||||
}
|
||||
|
||||
func partTwo() {
|
||||
scanner := makeScanner(false)
|
||||
|
||||
for scanner.Scan() {
|
||||
// line := scanner.Text()
|
||||
}
|
||||
}
|
||||
61
16/main_test.go
Normal file
61
16/main_test.go
Normal file
@@ -0,0 +1,61 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestVersionParse(t *testing.T) {
|
||||
tests := map[int64][]uint8{
|
||||
0: {0, 0, 0},
|
||||
1: {0, 0, 1},
|
||||
2: {0, 1, 0},
|
||||
3: {0, 1, 1},
|
||||
4: {1, 0, 0},
|
||||
5: {1, 0, 1},
|
||||
6: {1, 1, 0},
|
||||
7: {1, 1, 1},
|
||||
}
|
||||
for result, input := range tests {
|
||||
if result != getPacketVersion(input) {
|
||||
t.Fail()
|
||||
}
|
||||
if result != getPacketType(input) {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestParsePayload(t *testing.T) {
|
||||
if n, q := parsePayload([]uint8{0, 1, 0, 1, 0}); n != 10 || q != 5 {
|
||||
t.Log(n, q)
|
||||
t.Fail()
|
||||
}
|
||||
if n, q := parsePayload([]uint8{1, 0, 0, 0, 1, 0, 0, 1, 0, 0}); n != 20 || q != 10 {
|
||||
t.Log(n, q)
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestCases(t *testing.T) {
|
||||
inputs := map[string]int{
|
||||
"D2FE28": 6,
|
||||
"38006F45291200": 9,
|
||||
"EE00D40C823060": 14,
|
||||
"8A004A801A8002F478": 16,
|
||||
"620080001611562C8802118E34": 12,
|
||||
"C0015000016115A2E0802F182340": 23,
|
||||
"A0016C880162017C3686B18A3D4780": 31,
|
||||
}
|
||||
|
||||
for c, r := range inputs {
|
||||
stream := []uint8{}
|
||||
for _, hex := range c {
|
||||
stream = append(stream, hexMap[hex]...)
|
||||
}
|
||||
_, parsedPacket := parsePackets(stream)
|
||||
if r != countVersions(parsedPacket) {
|
||||
t.Log(c, countVersions(parsedPacket))
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,9 +4,15 @@ import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
func mustAtoi(line string) int {
|
||||
i, _ := strconv.Atoi(line)
|
||||
return i
|
||||
}
|
||||
|
||||
func main() {
|
||||
start := time.Now()
|
||||
partOne()
|
||||
|
||||
2
new.sh
2
new.sh
@@ -5,7 +5,7 @@ __year=2021
|
||||
if [ "${1}" != "" ]; then
|
||||
padded=$(printf "%02g" ${1})
|
||||
mkdir -p ${padded}/inputs
|
||||
touch ${padded}/inputs/{input,testinput}
|
||||
touch ${padded}/inputs/testinput
|
||||
if [ ! -f "${padded}/inputs/input" ]; then
|
||||
curl -s -H "Cookie: session=`cat .cookie`" https://adventofcode.com/${__year}/day/${1##0}/input > "${padded}/inputs/input"
|
||||
fi
|
||||
|
||||
Reference in New Issue
Block a user