Compare commits
1 Commits
master
...
day-5-map-
Author | SHA1 | Date | |
---|---|---|---|
b4db9ef306 |
22
05/main.go
22
05/main.go
@ -41,11 +41,13 @@ type point struct {
|
|||||||
y int
|
y int
|
||||||
}
|
}
|
||||||
|
|
||||||
type grid []int
|
type grid struct {
|
||||||
|
m map[int]int
|
||||||
|
}
|
||||||
|
|
||||||
func (g *grid) AddLine(start, end point, includeHorizontal bool) {
|
func (g *grid) AddLine(start, end point, includeHorizontal bool) {
|
||||||
for _, p := range LineFromPoints(start, end, includeHorizontal) {
|
for _, p := range LineFromPoints(start, end, includeHorizontal) {
|
||||||
(*g)[p.x+p.y*1000]++
|
g.m[p.x+p.y*1000]++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,15 +108,17 @@ func parsePoints(line string) (point, point) {
|
|||||||
func partOne() {
|
func partOne() {
|
||||||
scanner := makeScanner(false)
|
scanner := makeScanner(false)
|
||||||
|
|
||||||
grid := make(grid, 1_000_000)
|
grid := &grid{
|
||||||
|
m: make(map[int]int, 1000),
|
||||||
|
}
|
||||||
for scanner.Scan() {
|
for scanner.Scan() {
|
||||||
line := scanner.Text()
|
line := scanner.Text()
|
||||||
start, end := parsePoints(line)
|
start, end := parsePoints(line)
|
||||||
grid.AddLine(start, end, false)
|
grid.AddLine(start, end, false)
|
||||||
}
|
}
|
||||||
var danger int
|
var danger int
|
||||||
for i := range grid {
|
for i := range grid.m {
|
||||||
if grid[i] > 1 {
|
if grid.m[i] > 1 {
|
||||||
danger++
|
danger++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -124,15 +128,17 @@ func partOne() {
|
|||||||
func partTwo() {
|
func partTwo() {
|
||||||
scanner := makeScanner(false)
|
scanner := makeScanner(false)
|
||||||
|
|
||||||
grid := make(grid, 1_000_000)
|
grid := &grid{
|
||||||
|
m: make(map[int]int, 1000),
|
||||||
|
}
|
||||||
for scanner.Scan() {
|
for scanner.Scan() {
|
||||||
line := scanner.Text()
|
line := scanner.Text()
|
||||||
start, end := parsePoints(line)
|
start, end := parsePoints(line)
|
||||||
grid.AddLine(start, end, true)
|
grid.AddLine(start, end, true)
|
||||||
}
|
}
|
||||||
var danger int
|
var danger int
|
||||||
for i := range grid {
|
for i := range grid.m {
|
||||||
if grid[i] > 1 {
|
if grid.m[i] > 1 {
|
||||||
danger++
|
danger++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
117
06/main.go
117
06/main.go
@ -1,117 +0,0 @@
|
|||||||
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
111
07/main.go
@ -1,111 +0,0 @@
|
|||||||
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
207
08/main.go
@ -1,207 +0,0 @@
|
|||||||
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
140
09/main.go
@ -1,140 +0,0 @@
|
|||||||
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
128
10/main.go
@ -1,128 +0,0 @@
|
|||||||
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
147
11/main.go
@ -1,147 +0,0 @@
|
|||||||
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
140
12/main.go
@ -1,140 +0,0 @@
|
|||||||
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
133
13/main.go
@ -1,133 +0,0 @@
|
|||||||
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
153
14/main.go
@ -1,153 +0,0 @@
|
|||||||
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
128
15/main.go
@ -1,128 +0,0 @@
|
|||||||
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])
|
|
||||||
}
|
|
243
16/main.go
243
16/main.go
@ -1,243 +0,0 @@
|
|||||||
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) int {
|
|
||||||
result := int(0)
|
|
||||||
for i := 0; i < length; i++ {
|
|
||||||
result += int(stream[i]) << (length - 1 - i)
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
type packet struct {
|
|
||||||
version int
|
|
||||||
typeID int
|
|
||||||
subPackets []packet
|
|
||||||
encodedNumber int
|
|
||||||
}
|
|
||||||
|
|
||||||
func getPacketVersion(stream []uint8) int {
|
|
||||||
return parseNumber(stream, 3)
|
|
||||||
}
|
|
||||||
|
|
||||||
func getPacketType(stream []uint8) int {
|
|
||||||
return parseNumber(stream, 3)
|
|
||||||
}
|
|
||||||
|
|
||||||
func getSubpacketLength(t uint8, stream []uint8) (int, int) {
|
|
||||||
if t == 0 {
|
|
||||||
return 15, parseNumber(stream, 15)
|
|
||||||
}
|
|
||||||
if t == 1 {
|
|
||||||
return 11, parseNumber(stream, 11)
|
|
||||||
}
|
|
||||||
return 0, 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func parsePayload(stream []uint8) (int, 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, parsedPacket // 6 is packet header length
|
|
||||||
} else {
|
|
||||||
parsed := 0
|
|
||||||
size, subpacketlength := getSubpacketLength(stream[6], stream[7:])
|
|
||||||
for {
|
|
||||||
consumed, subs := parsePackets(stream[7+size+parsed:])
|
|
||||||
if consumed == 0 {
|
|
||||||
return parsed + 7 + size, parsedPacket
|
|
||||||
}
|
|
||||||
parsedPacket.subPackets = append(parsedPacket.subPackets, subs)
|
|
||||||
parsed += consumed
|
|
||||||
if size == 11 && len(parsedPacket.subPackets) == subpacketlength {
|
|
||||||
return parsed + 7 + size, parsedPacket
|
|
||||||
|
|
||||||
} else if size == 15 && parsed > subpacketlength {
|
|
||||||
return parsed + 7 + size, parsedPacket
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func countVersions(pac packet) int {
|
|
||||||
i := int(pac.version)
|
|
||||||
for _, p := range pac.subPackets {
|
|
||||||
i += countVersions(p)
|
|
||||||
}
|
|
||||||
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 solve(p packet) int {
|
|
||||||
switch p.typeID {
|
|
||||||
case 0: // sum
|
|
||||||
if len(p.subPackets) == 1 {
|
|
||||||
return solve(p.subPackets[0])
|
|
||||||
} else {
|
|
||||||
acc := 0
|
|
||||||
for _, v := range p.subPackets {
|
|
||||||
acc += solve(v)
|
|
||||||
}
|
|
||||||
return acc
|
|
||||||
}
|
|
||||||
case 1: // product
|
|
||||||
if len(p.subPackets) == 1 {
|
|
||||||
return solve(p.subPackets[0])
|
|
||||||
} else {
|
|
||||||
acc := solve(p.subPackets[0])
|
|
||||||
for _, v := range p.subPackets[1:] {
|
|
||||||
acc *= solve(v)
|
|
||||||
}
|
|
||||||
return acc
|
|
||||||
}
|
|
||||||
case 2: // min
|
|
||||||
if len(p.subPackets) == 1 {
|
|
||||||
return solve(p.subPackets[0])
|
|
||||||
} else {
|
|
||||||
acc := solve(p.subPackets[0])
|
|
||||||
for _, v := range p.subPackets[1:] {
|
|
||||||
t := solve(v)
|
|
||||||
if t < acc {
|
|
||||||
acc = t
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return acc
|
|
||||||
}
|
|
||||||
case 3: // max
|
|
||||||
if len(p.subPackets) == 1 {
|
|
||||||
return solve(p.subPackets[0])
|
|
||||||
} else {
|
|
||||||
acc := solve(p.subPackets[0])
|
|
||||||
for _, v := range p.subPackets[1:] {
|
|
||||||
t := solve(v)
|
|
||||||
if t > acc {
|
|
||||||
acc = t
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return acc
|
|
||||||
}
|
|
||||||
case 4: // number
|
|
||||||
return p.encodedNumber
|
|
||||||
case 5: // >
|
|
||||||
if len(p.subPackets) != 2 {
|
|
||||||
panic(fmt.Sprintf("recevied type 5 packet with %d subpackets", len(p.subPackets)))
|
|
||||||
}
|
|
||||||
if solve(p.subPackets[0]) > solve(p.subPackets[1]) {
|
|
||||||
return 1
|
|
||||||
} else {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
case 6: // <
|
|
||||||
if len(p.subPackets) != 2 {
|
|
||||||
panic(fmt.Sprintf("recevied type 6 packet with %d subpackets", len(p.subPackets)))
|
|
||||||
}
|
|
||||||
if solve(p.subPackets[0]) < solve(p.subPackets[1]) {
|
|
||||||
return 1
|
|
||||||
} else {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
case 7: // ==
|
|
||||||
if len(p.subPackets) != 2 {
|
|
||||||
panic(fmt.Sprintf("recevied type 7 packet with %d subpackets", len(p.subPackets)))
|
|
||||||
}
|
|
||||||
if solve(p.subPackets[0]) == solve(p.subPackets[1]) {
|
|
||||||
return 1
|
|
||||||
} else {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
panic("unknown packet type")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func partTwo() {
|
|
||||||
scanner := makeScanner(false)
|
|
||||||
|
|
||||||
scanner.Scan()
|
|
||||||
line := scanner.Text()
|
|
||||||
stream := []uint8{}
|
|
||||||
for _, hex := range line {
|
|
||||||
stream = append(stream, hexMap[hex]...)
|
|
||||||
}
|
|
||||||
_, parsedPacket := parsePackets(stream)
|
|
||||||
fmt.Println(solve(parsedPacket))
|
|
||||||
}
|
|
@ -1,86 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestVersionParse(t *testing.T) {
|
|
||||||
tests := map[int][]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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSolving(t *testing.T) {
|
|
||||||
inputs := map[string]int{
|
|
||||||
"C200B40A82": 3,
|
|
||||||
"04005AC33890": 54,
|
|
||||||
"880086C3E88112": 7,
|
|
||||||
"CE00C43D881120": 9,
|
|
||||||
"D8005AC2A8F0": 1,
|
|
||||||
"F600BC2D8F": 0,
|
|
||||||
"9C005AC2F8F0": 0,
|
|
||||||
"9C0141080250320F1802104A08": 1,
|
|
||||||
}
|
|
||||||
|
|
||||||
for c, r := range inputs {
|
|
||||||
stream := []uint8{}
|
|
||||||
for _, hex := range c {
|
|
||||||
stream = append(stream, hexMap[hex]...)
|
|
||||||
}
|
|
||||||
_, parsedPacket := parsePackets(stream)
|
|
||||||
if r != solve(parsedPacket) {
|
|
||||||
t.Log(c, solve(parsedPacket))
|
|
||||||
t.Fail()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
159
17/main.go
159
17/main.go
@ -1,159 +0,0 @@
|
|||||||
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 targetArea struct {
|
|
||||||
startx int
|
|
||||||
endx int
|
|
||||||
starty int
|
|
||||||
endy int
|
|
||||||
}
|
|
||||||
|
|
||||||
func ParseInput(line string) targetArea {
|
|
||||||
target := targetArea{}
|
|
||||||
acc := ""
|
|
||||||
for i := 0; i < len(line); i++ {
|
|
||||||
switch line[i] {
|
|
||||||
case '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-':
|
|
||||||
acc += string(line[i])
|
|
||||||
case '.':
|
|
||||||
i++ // skip the second .
|
|
||||||
if target.startx == 0 {
|
|
||||||
target.startx = mustAtoi(acc)
|
|
||||||
} else {
|
|
||||||
target.starty = mustAtoi(acc)
|
|
||||||
}
|
|
||||||
acc = ""
|
|
||||||
case ',':
|
|
||||||
target.endx = mustAtoi(acc)
|
|
||||||
acc = ""
|
|
||||||
default: // all other characters do nothing
|
|
||||||
}
|
|
||||||
target.endy = mustAtoi(acc)
|
|
||||||
}
|
|
||||||
return target
|
|
||||||
}
|
|
||||||
|
|
||||||
func InTarget(x, y int, target targetArea) bool {
|
|
||||||
return x >= target.startx && x <= target.endx && y <= target.endy && y >= target.starty
|
|
||||||
}
|
|
||||||
|
|
||||||
func BeyondTarget(x, y int, target targetArea) bool {
|
|
||||||
return x > target.endx || y < target.starty
|
|
||||||
}
|
|
||||||
|
|
||||||
type probe struct {
|
|
||||||
xvelocity int
|
|
||||||
yvelocity int
|
|
||||||
x int
|
|
||||||
y int
|
|
||||||
maxy int
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *probe) Step() {
|
|
||||||
p.x += p.xvelocity
|
|
||||||
p.y += p.yvelocity
|
|
||||||
if p.xvelocity > 0 {
|
|
||||||
p.xvelocity--
|
|
||||||
} else if p.xvelocity < 0 {
|
|
||||||
p.xvelocity++
|
|
||||||
}
|
|
||||||
p.yvelocity--
|
|
||||||
if p.y > p.maxy {
|
|
||||||
p.maxy = p.y
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func partOne() {
|
|
||||||
scanner := makeScanner(false)
|
|
||||||
|
|
||||||
// read line
|
|
||||||
scanner.Scan()
|
|
||||||
line := scanner.Text()
|
|
||||||
target := ParseInput(line)
|
|
||||||
highestArc := 0
|
|
||||||
for j := 1; j < 50; j++ {
|
|
||||||
for k := 1; k < 100; k++ {
|
|
||||||
initx := j
|
|
||||||
inity := k
|
|
||||||
p := &probe{
|
|
||||||
xvelocity: initx,
|
|
||||||
yvelocity: inity,
|
|
||||||
}
|
|
||||||
for {
|
|
||||||
p.Step()
|
|
||||||
if InTarget(p.x, p.y, target) {
|
|
||||||
if p.maxy > highestArc {
|
|
||||||
highestArc = p.maxy
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if BeyondTarget(p.x, p.y, target) {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fmt.Println(highestArc)
|
|
||||||
}
|
|
||||||
|
|
||||||
func partTwo() {
|
|
||||||
scanner := makeScanner(false)
|
|
||||||
|
|
||||||
// read line
|
|
||||||
scanner.Scan()
|
|
||||||
line := scanner.Text()
|
|
||||||
target := ParseInput(line)
|
|
||||||
hits := 0
|
|
||||||
for j := 0; j < 1000; j++ {
|
|
||||||
for k := -200; k < 1000; k++ {
|
|
||||||
initx := j
|
|
||||||
inity := k
|
|
||||||
p := &probe{
|
|
||||||
xvelocity: initx,
|
|
||||||
yvelocity: inity,
|
|
||||||
}
|
|
||||||
for {
|
|
||||||
p.Step()
|
|
||||||
if InTarget(p.x, p.y, target) {
|
|
||||||
hits++
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if BeyondTarget(p.x, p.y, target) {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fmt.Println(hits)
|
|
||||||
}
|
|
@ -1,15 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import "testing"
|
|
||||||
|
|
||||||
func TestInTarget(t *testing.T) {
|
|
||||||
target := targetArea{
|
|
||||||
startx: 20,
|
|
||||||
endx: 30,
|
|
||||||
starty: -10,
|
|
||||||
endy: -5,
|
|
||||||
}
|
|
||||||
if !InTarget(28, -7, target) {
|
|
||||||
t.Fail()
|
|
||||||
}
|
|
||||||
}
|
|
225
18/main.go
225
18/main.go
@ -1,225 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bufio"
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"strconv"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
func mustAtoi(line rune) 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 pair struct {
|
|
||||||
parent *pair
|
|
||||||
leftp *pair
|
|
||||||
left int
|
|
||||||
rightp *pair
|
|
||||||
right int
|
|
||||||
}
|
|
||||||
|
|
||||||
func Parse(raw string) *pair {
|
|
||||||
root := &pair{}
|
|
||||||
var current *pair
|
|
||||||
left := true
|
|
||||||
for _, v := range raw {
|
|
||||||
switch v {
|
|
||||||
case '[':
|
|
||||||
if current == nil {
|
|
||||||
current = root
|
|
||||||
} else {
|
|
||||||
p := &pair{parent: current}
|
|
||||||
if left {
|
|
||||||
current.leftp = p
|
|
||||||
} else {
|
|
||||||
current.rightp = p
|
|
||||||
}
|
|
||||||
current = p
|
|
||||||
}
|
|
||||||
left = true
|
|
||||||
case ']':
|
|
||||||
current = current.parent
|
|
||||||
case ',':
|
|
||||||
left = false
|
|
||||||
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
|
|
||||||
if left {
|
|
||||||
current.left = mustAtoi(v)
|
|
||||||
} else {
|
|
||||||
current.right = mustAtoi(v)
|
|
||||||
}
|
|
||||||
case ' ':
|
|
||||||
continue
|
|
||||||
default:
|
|
||||||
panic("what the: " + string(v))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return root
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *pair) String() string {
|
|
||||||
var left, right string
|
|
||||||
if p.leftp == nil {
|
|
||||||
left = fmt.Sprintf("%d", p.left)
|
|
||||||
} else {
|
|
||||||
left = p.leftp.String()
|
|
||||||
}
|
|
||||||
if p.rightp == nil {
|
|
||||||
right = fmt.Sprintf("%d", p.right)
|
|
||||||
} else {
|
|
||||||
right = p.rightp.String()
|
|
||||||
}
|
|
||||||
return fmt.Sprintf("[%s,%s]", left, right)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *pair) Magnitude() int {
|
|
||||||
left := 0
|
|
||||||
right := 0
|
|
||||||
if p.leftp == nil {
|
|
||||||
left = p.left
|
|
||||||
} else {
|
|
||||||
left = p.leftp.Magnitude()
|
|
||||||
}
|
|
||||||
if p.rightp == nil {
|
|
||||||
right = p.right
|
|
||||||
} else {
|
|
||||||
right = p.rightp.Magnitude()
|
|
||||||
}
|
|
||||||
return left*3 + right*2
|
|
||||||
}
|
|
||||||
|
|
||||||
func Add(left, right *pair) *pair {
|
|
||||||
return &pair{
|
|
||||||
leftp: left,
|
|
||||||
rightp: right,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Reduce(p *pair) {
|
|
||||||
for {
|
|
||||||
if MustExplode(0, p) {
|
|
||||||
Explode(p)
|
|
||||||
} else if MustSplit(p) {
|
|
||||||
Split(p)
|
|
||||||
} else {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Split(p *pair) bool {
|
|
||||||
if p.left > 9 {
|
|
||||||
p.leftp = &pair{
|
|
||||||
left: p.left / 2,
|
|
||||||
right: (p.left / 2) + (p.left % 2),
|
|
||||||
}
|
|
||||||
p.left = 0
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if p.leftp != nil {
|
|
||||||
m := Split(p.leftp)
|
|
||||||
if m {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if p.right > 9 {
|
|
||||||
p.rightp = &pair{
|
|
||||||
left: p.right / 2,
|
|
||||||
right: (p.right / 2) + (p.right % 2),
|
|
||||||
}
|
|
||||||
p.right = 0
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if p.rightp != nil {
|
|
||||||
m := Split(p.rightp)
|
|
||||||
if m {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func MustSplit(p *pair) bool {
|
|
||||||
if p.left > 9 || p.right > 9 {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if p.leftp != nil {
|
|
||||||
m := MustSplit(p.leftp)
|
|
||||||
if m {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if p.rightp != nil {
|
|
||||||
m := MustSplit(p.rightp)
|
|
||||||
if m {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func MustExplode(depth int, p *pair) bool {
|
|
||||||
if depth >= 4 {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if p.leftp != nil {
|
|
||||||
m := MustExplode(depth+1, p.leftp)
|
|
||||||
if m {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if p.rightp != nil {
|
|
||||||
m := MustExplode(depth+1, p.rightp)
|
|
||||||
if m {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func Explode(p *pair) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func partOne() {
|
|
||||||
scanner := makeScanner(false)
|
|
||||||
|
|
||||||
scanner.Scan()
|
|
||||||
line := scanner.Text()
|
|
||||||
total := Parse(line)
|
|
||||||
for scanner.Scan() {
|
|
||||||
line := scanner.Text()
|
|
||||||
total = Add(total, Parse(line))
|
|
||||||
}
|
|
||||||
fmt.Println(total)
|
|
||||||
}
|
|
||||||
|
|
||||||
func partTwo() {
|
|
||||||
scanner := makeScanner(false)
|
|
||||||
|
|
||||||
for scanner.Scan() {
|
|
||||||
// line := scanner.Text()
|
|
||||||
}
|
|
||||||
}
|
|
160
18/main_test.go
160
18/main_test.go
@ -1,160 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestParse(t *testing.T) {
|
|
||||||
cases := []string{
|
|
||||||
"[1,2]",
|
|
||||||
"[[3,2],1]",
|
|
||||||
"[[3,2],[4,5]]",
|
|
||||||
"[[3,2],[[7,8],5]]",
|
|
||||||
"[[1,2],3]",
|
|
||||||
"[9,[8,7]]",
|
|
||||||
"[[1,9],[8,5]]",
|
|
||||||
"[[[[1,2],[3,4]],[[5,6],[7,8]]],9]",
|
|
||||||
"[[[9,[3,8]],[[0,9],6]],[[[3,7],[4,9]],3]]",
|
|
||||||
"[[[[1,3],[5,3]],[[1,3],[8,7]]],[[[4,9],[6,9]],[[8,2],[7,3]]]]",
|
|
||||||
}
|
|
||||||
for _, input := range cases {
|
|
||||||
p := Parse(input)
|
|
||||||
if input != p.String() {
|
|
||||||
t.Log(p.String())
|
|
||||||
t.Fail()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMustExplode(t *testing.T) {
|
|
||||||
cases := map[string]bool{
|
|
||||||
"[1,2]": false,
|
|
||||||
"[[[[2,4],4],[2,3]],1]": false,
|
|
||||||
"[[[[[4,3],4],4],1],3]": true,
|
|
||||||
"[2,[1,[4,[3,[4,3]]]]]": true,
|
|
||||||
"[[[[0,7],4],[7,[[8,4],9]]],[1,1]]": true,
|
|
||||||
}
|
|
||||||
for input, output := range cases {
|
|
||||||
if MustExplode(0, Parse(input)) != output {
|
|
||||||
t.Log(input)
|
|
||||||
t.Fail()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSplit(t *testing.T) {
|
|
||||||
cases := map[*pair]string{
|
|
||||||
{left: 1, right: 1}: "[1,1]",
|
|
||||||
{left: 10, right: 1}: "[[5,5],1]",
|
|
||||||
{left: 11, right: 1}: "[[5,6],1]",
|
|
||||||
{left: 12, right: 1}: "[[6,6],1]",
|
|
||||||
{left: 12, right: 12}: "[[6,6],12]",
|
|
||||||
{left: 2, right: 12}: "[2,[6,6]]",
|
|
||||||
{
|
|
||||||
leftp: &pair{left: 15, right: 9},
|
|
||||||
rightp: &pair{left: 8, right: 1},
|
|
||||||
}: "[[[7,8],9],[8,1]]",
|
|
||||||
{
|
|
||||||
leftp: &pair{left: 1, right: 9},
|
|
||||||
rightp: &pair{left: 8, right: 15},
|
|
||||||
}: "[[1,9],[8,[7,8]]]",
|
|
||||||
}
|
|
||||||
for input, expected := range cases {
|
|
||||||
Split(input)
|
|
||||||
if input.String() != expected {
|
|
||||||
t.Log(input.String(), expected)
|
|
||||||
t.Fail()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMustSplit(t *testing.T) {
|
|
||||||
cases := map[*pair]bool{
|
|
||||||
{left: 1, right: 1}: false,
|
|
||||||
{left: 10, right: 1}: true,
|
|
||||||
{left: 11, right: 1}: true,
|
|
||||||
{left: 12, right: 1}: true,
|
|
||||||
{left: 12, right: 12}: true,
|
|
||||||
{left: 2, right: 12}: true,
|
|
||||||
{
|
|
||||||
leftp: &pair{left: 1, right: 9},
|
|
||||||
rightp: &pair{left: 8, right: 5},
|
|
||||||
}: false,
|
|
||||||
{
|
|
||||||
leftp: &pair{left: 1, right: 9},
|
|
||||||
rightp: &pair{left: 8, right: 15},
|
|
||||||
}: true,
|
|
||||||
}
|
|
||||||
for input, output := range cases {
|
|
||||||
result := MustSplit(input)
|
|
||||||
if result != output {
|
|
||||||
t.Log(input.String())
|
|
||||||
t.Fail()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestAdd(t *testing.T) {
|
|
||||||
cases := map[string][]*pair{
|
|
||||||
"[[1,2],[[3,4],5]]": {
|
|
||||||
&pair{left: 1, right: 2},
|
|
||||||
&pair{leftp: &pair{left: 3, right: 4}, right: 5},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for answer, pairs := range cases {
|
|
||||||
r := Add(pairs[0], pairs[1])
|
|
||||||
if r.String() != answer {
|
|
||||||
fmt.Printf("%s %s", r, answer)
|
|
||||||
t.Fail()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestReduce(t *testing.T) {
|
|
||||||
cases := map[*pair]string{
|
|
||||||
{left: 1, right: 1}: "[1,1]",
|
|
||||||
{left: 10, right: 1}: "[[5,5],1]",
|
|
||||||
{left: 11, right: 1}: "[[5,6],1]",
|
|
||||||
{left: 12, right: 1}: "[[6,6],1]",
|
|
||||||
{left: 12, right: 13}: "[[6,6],[6,7]]",
|
|
||||||
{left: 2, right: 12}: "[2,[6,6]]",
|
|
||||||
{
|
|
||||||
leftp: &pair{left: 15, right: 9},
|
|
||||||
rightp: &pair{left: 8, right: 1},
|
|
||||||
}: "[[[7,8],9],[8,1]]",
|
|
||||||
{
|
|
||||||
leftp: &pair{left: 1, right: 9},
|
|
||||||
rightp: &pair{left: 8, right: 15},
|
|
||||||
}: "[[1,9],[8,[7,8]]]",
|
|
||||||
}
|
|
||||||
for input, expected := range cases {
|
|
||||||
Reduce(input)
|
|
||||||
if input.String() != expected {
|
|
||||||
t.Log(input.String(), expected)
|
|
||||||
t.Fail()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMagnitude(t *testing.T) {
|
|
||||||
cases := map[int]*pair{
|
|
||||||
29: {left: 9, right: 1},
|
|
||||||
21: {left: 1, right: 9},
|
|
||||||
129: {
|
|
||||||
leftp: &pair{left: 9, right: 1},
|
|
||||||
rightp: &pair{left: 1, right: 9},
|
|
||||||
},
|
|
||||||
143: {
|
|
||||||
leftp: &pair{left: 1, right: 2},
|
|
||||||
rightp: &pair{leftp: &pair{left: 3, right: 4}, right: 5},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for answer, pair := range cases {
|
|
||||||
r := pair.Magnitude()
|
|
||||||
if r != answer {
|
|
||||||
fmt.Printf("%d %d", r, answer)
|
|
||||||
t.Fail()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
180
20/main.go
180
20/main.go
@ -1,180 +0,0 @@
|
|||||||
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)
|
|
||||||
}
|
|
||||||
|
|
||||||
type coord struct {
|
|
||||||
x int
|
|
||||||
y int
|
|
||||||
}
|
|
||||||
|
|
||||||
// grid SHOULD be like this:
|
|
||||||
// x ->
|
|
||||||
// y
|
|
||||||
// |
|
|
||||||
// V
|
|
||||||
|
|
||||||
type image struct {
|
|
||||||
background rune // what all uninitialized cells are set to; defaults to '.'
|
|
||||||
grid map[coord]rune
|
|
||||||
topleft coord
|
|
||||||
size int
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetNeighbors(c coord) []coord {
|
|
||||||
return []coord{
|
|
||||||
{x: c.x - 1, y: c.y - 1},
|
|
||||||
{x: c.x, y: c.y - 1},
|
|
||||||
{x: c.x + 1, y: c.y - 1},
|
|
||||||
|
|
||||||
{x: c.x - 1, y: c.y},
|
|
||||||
{x: c.x, y: c.y},
|
|
||||||
{x: c.x + 1, y: c.y},
|
|
||||||
|
|
||||||
{x: c.x - 1, y: c.y + 1},
|
|
||||||
{x: c.x, y: c.y + 1},
|
|
||||||
{x: c.x + 1, y: c.y + 1},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (img *image) GetNewRune(coord coord, enhancementMap string) rune {
|
|
||||||
index := 0
|
|
||||||
coords := GetNeighbors(coord)
|
|
||||||
for i := 0; i < len(coords); i++ {
|
|
||||||
value := img.grid[coords[i]]
|
|
||||||
if value == 0 {
|
|
||||||
value = img.background
|
|
||||||
}
|
|
||||||
if value == '#' {
|
|
||||||
index += (1 << (8 - i))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return rune(enhancementMap[index])
|
|
||||||
}
|
|
||||||
|
|
||||||
func (img *image) CountBrightPixels() int {
|
|
||||||
count := 0
|
|
||||||
for _, v := range img.grid {
|
|
||||||
if v == '#' {
|
|
||||||
count++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return count
|
|
||||||
}
|
|
||||||
|
|
||||||
func (img *image) Print() {
|
|
||||||
fmt.Println(strings.Repeat(string(img.background), img.size+2))
|
|
||||||
for y := img.topleft.y; y < img.size+img.topleft.y; y++ {
|
|
||||||
fmt.Print(string(img.background))
|
|
||||||
for x := img.topleft.x; x < img.size+img.topleft.x; x++ {
|
|
||||||
fmt.Printf("%s", string(img.grid[coord{x, y}]))
|
|
||||||
}
|
|
||||||
fmt.Printf("%s\n", string(img.background))
|
|
||||||
}
|
|
||||||
fmt.Println(strings.Repeat(string(img.background), img.size+2))
|
|
||||||
}
|
|
||||||
|
|
||||||
func Enhance(img *image, m string) *image {
|
|
||||||
next := &image{
|
|
||||||
topleft: coord{
|
|
||||||
x: img.topleft.x - 1,
|
|
||||||
y: img.topleft.y - 1,
|
|
||||||
},
|
|
||||||
size: img.size + 2,
|
|
||||||
grid: map[coord]rune{},
|
|
||||||
}
|
|
||||||
if img.background == '.' { // permute new "background" value
|
|
||||||
next.background = rune(m[0])
|
|
||||||
} else if img.background == '#' {
|
|
||||||
next.background = rune(m[511])
|
|
||||||
}
|
|
||||||
for y := img.topleft.y - 1; y < img.size+1; y++ {
|
|
||||||
for x := img.topleft.x - 1; x < img.size+1; x++ {
|
|
||||||
next.grid[coord{x, y}] = img.GetNewRune(coord{x, y}, m)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return next
|
|
||||||
}
|
|
||||||
|
|
||||||
func partOne() {
|
|
||||||
scanner := makeScanner(false)
|
|
||||||
|
|
||||||
scanner.Scan()
|
|
||||||
enhancementString := scanner.Text()
|
|
||||||
scanner.Scan() // eat empty line
|
|
||||||
|
|
||||||
img := &image{
|
|
||||||
background: '.',
|
|
||||||
grid: map[coord]rune{},
|
|
||||||
topleft: coord{0, 0},
|
|
||||||
}
|
|
||||||
|
|
||||||
y := 0
|
|
||||||
for scanner.Scan() {
|
|
||||||
line := scanner.Text()
|
|
||||||
img.size = len(line)
|
|
||||||
for x, c := range line {
|
|
||||||
img.grid[coord{x, y}] = c
|
|
||||||
}
|
|
||||||
y++
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := 0; i < 2; i++ {
|
|
||||||
img = Enhance(img, enhancementString)
|
|
||||||
}
|
|
||||||
fmt.Println(img.CountBrightPixels())
|
|
||||||
}
|
|
||||||
|
|
||||||
func partTwo() {
|
|
||||||
scanner := makeScanner(false)
|
|
||||||
|
|
||||||
scanner.Scan()
|
|
||||||
enhancementString := scanner.Text()
|
|
||||||
scanner.Scan() // eat empty line
|
|
||||||
|
|
||||||
img := &image{
|
|
||||||
background: '.',
|
|
||||||
grid: map[coord]rune{},
|
|
||||||
topleft: coord{0, 0},
|
|
||||||
}
|
|
||||||
|
|
||||||
y := 0
|
|
||||||
for scanner.Scan() {
|
|
||||||
line := scanner.Text()
|
|
||||||
img.size = len(line)
|
|
||||||
for x, c := range line {
|
|
||||||
img.grid[coord{x, y}] = c
|
|
||||||
}
|
|
||||||
y++
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := 0; i < 50; i++ {
|
|
||||||
img = Enhance(img, enhancementString)
|
|
||||||
}
|
|
||||||
fmt.Println(img.CountBrightPixels())
|
|
||||||
}
|
|
@ -1,66 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestGetNewRune(t *testing.T) {
|
|
||||||
img := image{
|
|
||||||
grid: map[coord]rune{
|
|
||||||
{0, 0}: '.', {1, 0}: '.', {2, 0}: '.',
|
|
||||||
{0, 1}: '.', {1, 1}: '.', {2, 1}: '.',
|
|
||||||
{0, 2}: '.', {1, 2}: '.', {2, 2}: '.',
|
|
||||||
},
|
|
||||||
}
|
|
||||||
if img.GetNewRune(coord{1, 1}, ".") != '.' {
|
|
||||||
t.Fail()
|
|
||||||
}
|
|
||||||
|
|
||||||
img = image{
|
|
||||||
grid: map[coord]rune{
|
|
||||||
{0, 0}: '.', {1, 0}: '.', {2, 0}: '.',
|
|
||||||
{0, 1}: '.', {1, 1}: '.', {2, 1}: '.',
|
|
||||||
{0, 2}: '.', {1, 2}: '.', {2, 2}: '#',
|
|
||||||
},
|
|
||||||
}
|
|
||||||
if img.GetNewRune(coord{1, 1}, ".#") != '#' {
|
|
||||||
t.Fail()
|
|
||||||
}
|
|
||||||
|
|
||||||
img = image{
|
|
||||||
grid: map[coord]rune{
|
|
||||||
{0, 0}: '.', {1, 0}: '.', {2, 0}: '.',
|
|
||||||
{0, 1}: '.', {1, 1}: '.', {2, 1}: '.',
|
|
||||||
{0, 2}: '.', {1, 2}: '#', {2, 2}: '.',
|
|
||||||
},
|
|
||||||
}
|
|
||||||
if img.GetNewRune(coord{1, 1}, "..#.") != '#' {
|
|
||||||
t.Fail()
|
|
||||||
}
|
|
||||||
|
|
||||||
img = image{
|
|
||||||
grid: map[coord]rune{
|
|
||||||
{0, 0}: '.', {1, 0}: '.', {2, 0}: '.',
|
|
||||||
{0, 1}: '.', {1, 1}: '.', {2, 1}: '.',
|
|
||||||
{0, 2}: '.', {1, 2}: '#', {2, 2}: '#',
|
|
||||||
},
|
|
||||||
}
|
|
||||||
if img.GetNewRune(coord{1, 1}, "...#") != '#' {
|
|
||||||
t.Fail()
|
|
||||||
}
|
|
||||||
|
|
||||||
img = image{
|
|
||||||
background: '#',
|
|
||||||
grid: map[coord]rune{
|
|
||||||
{0, 0}: '.', {1, 0}: '.', {2, 0}: '.',
|
|
||||||
{0, 1}: '.', {1, 1}: '.', {2, 1}: '.',
|
|
||||||
{0, 2}: '.', {1, 2}: '#', {2, 2}: '#',
|
|
||||||
},
|
|
||||||
}
|
|
||||||
m := strings.Repeat(".", 484)
|
|
||||||
m += "#"
|
|
||||||
if img.GetNewRune(coord{0, 0}, m) != '#' { // 111100100, or 484
|
|
||||||
t.Fail()
|
|
||||||
}
|
|
||||||
}
|
|
95
21/main.go
95
21/main.go
@ -1,95 +0,0 @@
|
|||||||
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)
|
|
||||||
}
|
|
||||||
|
|
||||||
func MakeDeterministicDie(max int) func() int {
|
|
||||||
currentDieValue := 0
|
|
||||||
return func() int {
|
|
||||||
if currentDieValue >= max {
|
|
||||||
currentDieValue = 0
|
|
||||||
}
|
|
||||||
currentDieValue++
|
|
||||||
return currentDieValue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func RollThree(f func() int) int {
|
|
||||||
return f() + f() + f()
|
|
||||||
}
|
|
||||||
|
|
||||||
func partOne() {
|
|
||||||
scanner := makeScanner(false)
|
|
||||||
|
|
||||||
scanner.Scan()
|
|
||||||
player1 := mustAtoi(strings.Split(scanner.Text(), " ")[4])
|
|
||||||
scanner.Scan()
|
|
||||||
player2 := mustAtoi(strings.Split(scanner.Text(), " ")[4])
|
|
||||||
|
|
||||||
die := MakeDeterministicDie(100)
|
|
||||||
score1 := 0
|
|
||||||
score2 := 0
|
|
||||||
rolls := 0
|
|
||||||
|
|
||||||
for {
|
|
||||||
player1 = player1 + RollThree(die)
|
|
||||||
rolls += 3
|
|
||||||
for player1 > 10 {
|
|
||||||
player1 -= 10
|
|
||||||
}
|
|
||||||
score1 += player1
|
|
||||||
if score1 >= 1000 {
|
|
||||||
fmt.Println(score2 * rolls)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
player2 = player2 + RollThree(die)
|
|
||||||
rolls += 3
|
|
||||||
for player2 > 10 {
|
|
||||||
player2 -= 10
|
|
||||||
}
|
|
||||||
score2 += player2
|
|
||||||
if score2 >= 1000 {
|
|
||||||
fmt.Println(score1 * rolls)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func partTwo() {
|
|
||||||
scanner := makeScanner(false)
|
|
||||||
|
|
||||||
for scanner.Scan() {
|
|
||||||
// line := scanner.Text()
|
|
||||||
}
|
|
||||||
}
|
|
134
22/main.go
134
22/main.go
@ -1,134 +0,0 @@
|
|||||||
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 step struct {
|
|
||||||
on bool
|
|
||||||
x []int
|
|
||||||
y []int
|
|
||||||
z []int
|
|
||||||
}
|
|
||||||
|
|
||||||
func ParseInput(line string) step {
|
|
||||||
s := step{}
|
|
||||||
var state byte
|
|
||||||
acc := ""
|
|
||||||
for i := 0; i < len(line); i++ {
|
|
||||||
switch line[i] {
|
|
||||||
case '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-':
|
|
||||||
acc += string(line[i])
|
|
||||||
case 'f':
|
|
||||||
s.on = false
|
|
||||||
case 'n':
|
|
||||||
s.on = true
|
|
||||||
case 'x', 'y', 'z':
|
|
||||||
state = line[i]
|
|
||||||
case '.', ',':
|
|
||||||
if line[i] == '.' {
|
|
||||||
i++ // skip second .
|
|
||||||
}
|
|
||||||
switch state {
|
|
||||||
case 'x':
|
|
||||||
s.x = append(s.x, mustAtoi(acc))
|
|
||||||
case 'y':
|
|
||||||
s.y = append(s.y, mustAtoi(acc))
|
|
||||||
case 'z':
|
|
||||||
s.z = append(s.z, mustAtoi(acc))
|
|
||||||
}
|
|
||||||
acc = ""
|
|
||||||
default: // all other characters do nothing
|
|
||||||
}
|
|
||||||
}
|
|
||||||
s.z = append(s.z, mustAtoi(acc)) // catch last number
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
type coord struct {
|
|
||||||
x int
|
|
||||||
y int
|
|
||||||
z int
|
|
||||||
}
|
|
||||||
|
|
||||||
func GenerateCoords(s step) []coord {
|
|
||||||
c := []coord{}
|
|
||||||
for x := s.x[0]; x <= s.x[1]; x++ {
|
|
||||||
for y := s.y[0]; y <= s.y[1]; y++ {
|
|
||||||
for z := s.z[0]; z <= s.z[1]; z++ {
|
|
||||||
c = append(c, coord{x, y, z})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
|
|
||||||
func partOne() {
|
|
||||||
scanner := makeScanner(true)
|
|
||||||
|
|
||||||
grid := map[coord]struct{}{}
|
|
||||||
steps := []step{}
|
|
||||||
for scanner.Scan() {
|
|
||||||
steps = append(steps, ParseInput(scanner.Text()))
|
|
||||||
}
|
|
||||||
for _, step := range steps[0:20] {
|
|
||||||
for _, coord := range GenerateCoords(step) {
|
|
||||||
if step.on {
|
|
||||||
grid[coord] = struct{}{}
|
|
||||||
} else {
|
|
||||||
delete(grid, coord)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fmt.Println(len(grid))
|
|
||||||
}
|
|
||||||
|
|
||||||
func partTwo() {
|
|
||||||
scanner := makeScanner(true)
|
|
||||||
|
|
||||||
grid := map[coord]struct{}{}
|
|
||||||
steps := []step{}
|
|
||||||
for scanner.Scan() {
|
|
||||||
steps = append(steps, ParseInput(scanner.Text()))
|
|
||||||
}
|
|
||||||
// this ain't gonna work
|
|
||||||
for _, step := range steps {
|
|
||||||
for _, coord := range GenerateCoords(step) {
|
|
||||||
if step.on {
|
|
||||||
grid[coord] = struct{}{}
|
|
||||||
} else {
|
|
||||||
delete(grid, coord)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fmt.Println(len(grid))
|
|
||||||
}
|
|
110
25/main.go
110
25/main.go
@ -1,110 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bufio"
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
start := time.Now()
|
|
||||||
partOne()
|
|
||||||
duration := time.Since(start)
|
|
||||||
fmt.Printf("p1: %s\n", 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 coord struct {
|
|
||||||
x int
|
|
||||||
y int
|
|
||||||
}
|
|
||||||
|
|
||||||
type floor struct {
|
|
||||||
steps int
|
|
||||||
width int
|
|
||||||
height int
|
|
||||||
m map[coord]rune
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *floor) Print() {
|
|
||||||
for y := 0; y < f.height; y++ {
|
|
||||||
for x := 0; x < f.width; x++ {
|
|
||||||
fmt.Printf("%s", string(f.m[coord{x: x, y: y}]))
|
|
||||||
}
|
|
||||||
fmt.Printf("\n")
|
|
||||||
}
|
|
||||||
fmt.Printf("\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *floor) Step() bool {
|
|
||||||
f.steps++
|
|
||||||
moved := false
|
|
||||||
toMove := map[coord]coord{}
|
|
||||||
for y := 0; y < f.height; y++ {
|
|
||||||
for x := 0; x < f.width; x++ {
|
|
||||||
current := coord{x: x, y: y}
|
|
||||||
x += 1
|
|
||||||
if x >= f.width {
|
|
||||||
x = 0
|
|
||||||
}
|
|
||||||
if f.m[current] == '>' && f.m[coord{x: x, y: y}] == '.' {
|
|
||||||
toMove[current] = coord{x: x, y: y}
|
|
||||||
moved = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for current, next := range toMove {
|
|
||||||
f.m[next] = f.m[current]
|
|
||||||
f.m[current] = '.'
|
|
||||||
}
|
|
||||||
toMove = map[coord]coord{}
|
|
||||||
for y := 0; y < f.height; y++ {
|
|
||||||
for x := 0; x < f.width; x++ {
|
|
||||||
current := coord{x: x, y: y}
|
|
||||||
y += 1
|
|
||||||
if y >= f.height {
|
|
||||||
y = 0
|
|
||||||
}
|
|
||||||
if f.m[current] == 'v' && f.m[coord{x: x, y: y}] == '.' {
|
|
||||||
toMove[current] = coord{x: x, y: y}
|
|
||||||
moved = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for current, next := range toMove {
|
|
||||||
f.m[next] = f.m[current]
|
|
||||||
f.m[current] = '.'
|
|
||||||
}
|
|
||||||
return moved
|
|
||||||
}
|
|
||||||
|
|
||||||
func partOne() {
|
|
||||||
scanner := makeScanner(false)
|
|
||||||
f := &floor{
|
|
||||||
m: make(map[coord]rune),
|
|
||||||
}
|
|
||||||
y := 0
|
|
||||||
for scanner.Scan() {
|
|
||||||
line := scanner.Text()
|
|
||||||
f.width = len(line)
|
|
||||||
for x, v := range line {
|
|
||||||
f.m[coord{x: x, y: y}] = v
|
|
||||||
}
|
|
||||||
y++
|
|
||||||
}
|
|
||||||
f.height = y
|
|
||||||
for f.Step() {
|
|
||||||
}
|
|
||||||
fmt.Println(f.steps)
|
|
||||||
}
|
|
@ -4,15 +4,9 @@ import (
|
|||||||
"bufio"
|
"bufio"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func mustAtoi(line string) int {
|
|
||||||
i, _ := strconv.Atoi(line)
|
|
||||||
return i
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
partOne()
|
partOne()
|
||||||
|
2
new.sh
2
new.sh
@ -5,7 +5,7 @@ __year=2021
|
|||||||
if [ "${1}" != "" ]; then
|
if [ "${1}" != "" ]; then
|
||||||
padded=$(printf "%02g" ${1})
|
padded=$(printf "%02g" ${1})
|
||||||
mkdir -p ${padded}/inputs
|
mkdir -p ${padded}/inputs
|
||||||
touch ${padded}/inputs/testinput
|
touch ${padded}/inputs/{input,testinput}
|
||||||
if [ ! -f "${padded}/inputs/input" ]; then
|
if [ ! -f "${padded}/inputs/input" ]; then
|
||||||
curl -s -H "Cookie: session=`cat .cookie`" https://adventofcode.com/${__year}/day/${1##0}/input > "${padded}/inputs/input"
|
curl -s -H "Cookie: session=`cat .cookie`" https://adventofcode.com/${__year}/day/${1##0}/input > "${padded}/inputs/input"
|
||||||
fi
|
fi
|
||||||
|
Loading…
Reference in New Issue
Block a user