Compare commits
28 Commits
0b851158dc
...
master
Author | SHA1 | Date | |
---|---|---|---|
3e9fe4153c | |||
f1d6903fba | |||
16784775c9 | |||
df30e9abc0 | |||
17ab6d7144 | |||
42c77627d1 | |||
f744ac6745 | |||
44fb58ff14 | |||
010a843471 | |||
d2b4bc2921 | |||
9821836b6c | |||
0cd38cfd03 | |||
d8ed532442 | |||
e1d3ca5ea2 | |||
0883efd35e | |||
353d5e92c9 | |||
9d406c2d22 | |||
80142a25fb | |||
e2ac00420d | |||
18bccde2f5 | |||
559d91b9a6 | |||
6ed45d319b | |||
1124022f4f | |||
f5ec48772e | |||
55fa312abf | |||
24b59f71fa | |||
9244b2e178 | |||
56cd171588 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1 +1,2 @@
|
|||||||
input
|
input
|
||||||
|
testinput
|
@@ -5,11 +5,16 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
start := time.Now()
|
||||||
partOne()
|
partOne()
|
||||||
|
duration := time.Since(start)
|
||||||
partTwo()
|
partTwo()
|
||||||
|
duration2 := time.Since(start)
|
||||||
|
fmt.Printf("p1: %s, p2: %s\n", duration, duration2-duration)
|
||||||
}
|
}
|
||||||
|
|
||||||
// [...] they need you to find the two entries that sum to 2020 and then multiply those two numbers together.
|
// [...] they need you to find the two entries that sum to 2020 and then multiply those two numbers together.
|
||||||
|
@@ -6,12 +6,17 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
"unicode"
|
"unicode"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
start := time.Now()
|
||||||
partOne()
|
partOne()
|
||||||
|
duration := time.Since(start)
|
||||||
partTwo()
|
partTwo()
|
||||||
|
duration2 := time.Since(start)
|
||||||
|
fmt.Printf("p1: %s, p2: %s\n", duration, duration2-duration)
|
||||||
}
|
}
|
||||||
|
|
||||||
//To try to debug the problem, they have created a list (your puzzle input) of passwords (according to the corrupted database) and the corporate policy when that password was set.
|
//To try to debug the problem, they have created a list (your puzzle input) of passwords (according to the corrupted database) and the corporate policy when that password was set.
|
||||||
|
@@ -5,11 +5,16 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
start := time.Now()
|
||||||
partOne()
|
partOne()
|
||||||
|
duration := time.Since(start)
|
||||||
partTwo()
|
partTwo()
|
||||||
|
duration2 := time.Since(start)
|
||||||
|
fmt.Printf("p1: %s, p2: %s\n", duration, duration2-duration)
|
||||||
}
|
}
|
||||||
|
|
||||||
type slope struct {
|
type slope struct {
|
||||||
|
@@ -6,11 +6,16 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
start := time.Now()
|
||||||
partOne()
|
partOne()
|
||||||
|
duration := time.Since(start)
|
||||||
partTwo()
|
partTwo()
|
||||||
|
duration2 := time.Since(start)
|
||||||
|
fmt.Printf("p1: %s, p2: %s\n", duration, duration2-duration)
|
||||||
}
|
}
|
||||||
|
|
||||||
type passport struct {
|
type passport struct {
|
||||||
|
@@ -5,11 +5,16 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"sort"
|
"sort"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
start := time.Now()
|
||||||
partOne()
|
partOne()
|
||||||
|
duration := time.Since(start)
|
||||||
partTwo()
|
partTwo()
|
||||||
|
duration2 := time.Since(start)
|
||||||
|
fmt.Printf("p1: %s, p2: %s\n", duration, duration2-duration)
|
||||||
}
|
}
|
||||||
|
|
||||||
type boardingPass struct {
|
type boardingPass struct {
|
||||||
|
@@ -5,11 +5,16 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
start := time.Now()
|
||||||
partOne()
|
partOne()
|
||||||
|
duration := time.Since(start)
|
||||||
partTwo()
|
partTwo()
|
||||||
|
duration2 := time.Since(start)
|
||||||
|
fmt.Printf("p1: %s, p2: %s\n", duration, duration2-duration)
|
||||||
}
|
}
|
||||||
|
|
||||||
func union(s string) string {
|
func union(s string) string {
|
||||||
|
@@ -6,11 +6,16 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
start := time.Now()
|
||||||
partOne()
|
partOne()
|
||||||
|
duration := time.Since(start)
|
||||||
partTwo()
|
partTwo()
|
||||||
|
duration2 := time.Since(start)
|
||||||
|
fmt.Printf("p1: %s, p2: %s\n", duration, duration2-duration)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bag is a bag that contains other bags
|
// Bag is a bag that contains other bags
|
||||||
|
@@ -6,11 +6,16 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
start := time.Now()
|
||||||
partOne()
|
partOne()
|
||||||
|
duration := time.Since(start)
|
||||||
partTwo()
|
partTwo()
|
||||||
|
duration2 := time.Since(start)
|
||||||
|
fmt.Printf("p1: %s, p2: %s\n", duration, duration2-duration)
|
||||||
}
|
}
|
||||||
|
|
||||||
type opCode struct {
|
type opCode struct {
|
||||||
|
@@ -6,11 +6,16 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
start := time.Now()
|
||||||
partOne()
|
partOne()
|
||||||
|
duration := time.Since(start)
|
||||||
partTwo()
|
partTwo()
|
||||||
|
duration2 := time.Since(start)
|
||||||
|
fmt.Printf("p1: %s, p2: %s\n", duration, duration2-duration)
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkNotSum(t int, s []int) bool {
|
func checkNotSum(t int, s []int) bool {
|
||||||
|
122
10/main.go
Normal file
122
10/main.go
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"sort"
|
||||||
|
"strconv"
|
||||||
|
"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)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find a chain that uses all of your adapters to connect the charging outlet to your device's built-in adapter
|
||||||
|
// and count the joltage differences between the charging outlet, the adapters, and your device.
|
||||||
|
// What is the number of 1-jolt differences multiplied by the number of 3-jolt differences?
|
||||||
|
|
||||||
|
func partOne() {
|
||||||
|
f, _ := os.Open("input")
|
||||||
|
reader := bufio.NewReader(f)
|
||||||
|
scanner := bufio.NewScanner(reader)
|
||||||
|
|
||||||
|
// wall
|
||||||
|
adapters := []int{0}
|
||||||
|
|
||||||
|
// load
|
||||||
|
for scanner.Scan() {
|
||||||
|
line := scanner.Text()
|
||||||
|
i, _ := strconv.Atoi(line)
|
||||||
|
adapters = append(adapters, i)
|
||||||
|
}
|
||||||
|
|
||||||
|
// sort
|
||||||
|
sort.Slice(adapters, func(i, j int) bool {
|
||||||
|
return adapters[i] < adapters[j]
|
||||||
|
})
|
||||||
|
|
||||||
|
// device
|
||||||
|
adapters = append(adapters, adapters[len(adapters)-1]+3)
|
||||||
|
|
||||||
|
one := 0
|
||||||
|
three := 0
|
||||||
|
|
||||||
|
// count gaps
|
||||||
|
for i, j := range adapters {
|
||||||
|
if i < len(adapters)-1 {
|
||||||
|
if adapters[i+1]-j == 3 {
|
||||||
|
three = three + 1
|
||||||
|
} else if adapters[i+1]-j == 1 {
|
||||||
|
one = one + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(three * one)
|
||||||
|
}
|
||||||
|
|
||||||
|
// You glance back down at your bag and try to remember why you brought so many adapters; there must be more than a trillion valid ways to arrange them!
|
||||||
|
// Surely, there must be an efficient way to count the arrangements.
|
||||||
|
// What is the total number of distinct ways you can arrange the adapters to connect the charging outlet to your device?
|
||||||
|
|
||||||
|
func partTwo() {
|
||||||
|
f, _ := os.Open("input")
|
||||||
|
reader := bufio.NewReader(f)
|
||||||
|
scanner := bufio.NewScanner(reader)
|
||||||
|
|
||||||
|
// wall
|
||||||
|
adapters := []int{0}
|
||||||
|
|
||||||
|
for scanner.Scan() {
|
||||||
|
line := scanner.Text()
|
||||||
|
i, _ := strconv.Atoi(line)
|
||||||
|
adapters = append(adapters, i)
|
||||||
|
}
|
||||||
|
|
||||||
|
// sort
|
||||||
|
sort.Slice(adapters, func(i, j int) bool {
|
||||||
|
return adapters[i] < adapters[j]
|
||||||
|
})
|
||||||
|
|
||||||
|
// device
|
||||||
|
adapters = append(adapters, adapters[len(adapters)-1]+3)
|
||||||
|
|
||||||
|
combinations := 1
|
||||||
|
ones := 0
|
||||||
|
three := 0
|
||||||
|
|
||||||
|
// count gaps
|
||||||
|
for i, j := range adapters {
|
||||||
|
if i < len(adapters)-1 {
|
||||||
|
if adapters[i+1]-j == 1 {
|
||||||
|
// small steps...
|
||||||
|
ones = ones + 1
|
||||||
|
} else if adapters[i+1]-j == 3 {
|
||||||
|
combinations = combinations + 1
|
||||||
|
if ones == 2 {
|
||||||
|
combinations = combinations * 1
|
||||||
|
}
|
||||||
|
if ones == 3 {
|
||||||
|
combinations = combinations * 2
|
||||||
|
}
|
||||||
|
if ones == 4 {
|
||||||
|
combinations = combinations * 4
|
||||||
|
}
|
||||||
|
if ones == 5 {
|
||||||
|
combinations = combinations * 7
|
||||||
|
}
|
||||||
|
ones = 0
|
||||||
|
three = three + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(adapters, combinations)
|
||||||
|
}
|
303
11/main.go
Normal file
303
11/main.go
Normal file
@@ -0,0 +1,303 @@
|
|||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
type cell struct {
|
||||||
|
taken int // 1: someone there; 0: empty
|
||||||
|
seat bool // t: seat available; f: open floor
|
||||||
|
}
|
||||||
|
|
||||||
|
type waitingRoom struct {
|
||||||
|
seats [][]cell
|
||||||
|
maxCol int
|
||||||
|
maxRow int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *waitingRoom) parseRow(s string) {
|
||||||
|
row := []cell{}
|
||||||
|
|
||||||
|
for _, r := range s {
|
||||||
|
switch {
|
||||||
|
case r == 'L':
|
||||||
|
row = append(row, cell{taken: 0, seat: true})
|
||||||
|
case r == '.':
|
||||||
|
row = append(row, cell{taken: 0, seat: false})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
w.seats = append(w.seats, row)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *waitingRoom) countNeighborsPartOne(row, col int) int {
|
||||||
|
c := 0
|
||||||
|
if row-1 > -1 {
|
||||||
|
c = c + w.seats[row-1][col].taken // north
|
||||||
|
if col-1 > -1 {
|
||||||
|
c = c + w.seats[row-1][col-1].taken // northwest
|
||||||
|
}
|
||||||
|
if col+1 < w.maxCol {
|
||||||
|
c = c + w.seats[row-1][col+1].taken // northheast
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if row+1 < w.maxRow {
|
||||||
|
c = c + w.seats[row+1][col].taken // south
|
||||||
|
if col+1 < w.maxCol {
|
||||||
|
c = c + w.seats[row+1][col+1].taken // southeast
|
||||||
|
}
|
||||||
|
if col-1 > -1 {
|
||||||
|
c = c + w.seats[row+1][col-1].taken // southwest
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if col-1 > -1 {
|
||||||
|
c = c + w.seats[row][col-1].taken // west
|
||||||
|
}
|
||||||
|
if col+1 < w.maxCol {
|
||||||
|
c = c + w.seats[row][col+1].taken // east
|
||||||
|
}
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *waitingRoom) makeNextStepPartOne() *waitingRoom {
|
||||||
|
newRoom := &waitingRoom{
|
||||||
|
seats: make([][]cell, w.maxRow),
|
||||||
|
maxCol: w.maxCol,
|
||||||
|
maxRow: w.maxRow,
|
||||||
|
}
|
||||||
|
|
||||||
|
for r := range w.seats {
|
||||||
|
newRoom.seats[r] = make([]cell, newRoom.maxCol)
|
||||||
|
for c := range w.seats[r] {
|
||||||
|
if w.seats[r][c].seat && w.seats[r][c].taken == 0 && w.countNeighborsPartOne(r, c) == 0 {
|
||||||
|
newRoom.seats[r][c].seat = w.seats[r][c].seat
|
||||||
|
newRoom.seats[r][c].taken = 1
|
||||||
|
} else if w.seats[r][c].seat && w.seats[r][c].taken == 1 && w.countNeighborsPartOne(r, c) >= 4 {
|
||||||
|
newRoom.seats[r][c].seat = w.seats[r][c].seat
|
||||||
|
newRoom.seats[r][c].taken = 0
|
||||||
|
} else {
|
||||||
|
newRoom.seats[r][c].seat = w.seats[r][c].seat
|
||||||
|
newRoom.seats[r][c].taken = w.seats[r][c].taken
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return newRoom
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *waitingRoom) countNeighborsPartTwo(row, col int) int {
|
||||||
|
c := 0
|
||||||
|
trow := row
|
||||||
|
tcol := col
|
||||||
|
|
||||||
|
// south
|
||||||
|
for trow < w.maxRow-1 {
|
||||||
|
trow = trow + 1
|
||||||
|
if w.seats[trow][col].seat {
|
||||||
|
c = c + w.seats[trow][col].taken
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
trow = row
|
||||||
|
|
||||||
|
// north
|
||||||
|
for trow > 0 {
|
||||||
|
trow = trow - 1
|
||||||
|
if w.seats[trow][col].seat {
|
||||||
|
c = c + w.seats[trow][col].taken
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
trow = row
|
||||||
|
|
||||||
|
// west
|
||||||
|
for tcol > 0 {
|
||||||
|
tcol = tcol - 1
|
||||||
|
if w.seats[row][tcol].seat {
|
||||||
|
c = c + w.seats[row][tcol].taken
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tcol = col
|
||||||
|
|
||||||
|
// east
|
||||||
|
for tcol < w.maxCol-1 {
|
||||||
|
tcol = tcol + 1
|
||||||
|
if w.seats[row][tcol].seat {
|
||||||
|
c = c + w.seats[row][tcol].taken
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tcol = col
|
||||||
|
|
||||||
|
// southeast
|
||||||
|
for trow < w.maxRow-1 && tcol < w.maxCol-1 {
|
||||||
|
trow = trow + 1
|
||||||
|
tcol = tcol + 1
|
||||||
|
if w.seats[trow][tcol].seat {
|
||||||
|
c = c + w.seats[trow][tcol].taken
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
trow = row
|
||||||
|
tcol = col
|
||||||
|
|
||||||
|
// southwest
|
||||||
|
for trow < w.maxRow-1 && tcol > 0 {
|
||||||
|
trow = trow + 1
|
||||||
|
tcol = tcol - 1
|
||||||
|
if w.seats[trow][tcol].seat {
|
||||||
|
c = c + w.seats[trow][tcol].taken
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
trow = row
|
||||||
|
tcol = col
|
||||||
|
|
||||||
|
// northeast
|
||||||
|
for trow > 0 && tcol < w.maxCol-1 {
|
||||||
|
trow = trow - 1
|
||||||
|
tcol = tcol + 1
|
||||||
|
if w.seats[trow][tcol].seat {
|
||||||
|
c = c + w.seats[trow][tcol].taken
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
trow = row
|
||||||
|
tcol = col
|
||||||
|
|
||||||
|
// northwest
|
||||||
|
for trow > 0 && tcol > 0 {
|
||||||
|
trow = trow - 1
|
||||||
|
tcol = tcol - 1
|
||||||
|
if w.seats[trow][tcol].seat {
|
||||||
|
c = c + w.seats[trow][tcol].taken
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *waitingRoom) makeNextStepPartTwo() *waitingRoom {
|
||||||
|
newRoom := &waitingRoom{
|
||||||
|
seats: make([][]cell, w.maxRow),
|
||||||
|
maxCol: w.maxCol,
|
||||||
|
maxRow: w.maxRow,
|
||||||
|
}
|
||||||
|
|
||||||
|
for r := range w.seats {
|
||||||
|
newRoom.seats[r] = make([]cell, newRoom.maxCol)
|
||||||
|
for c := range w.seats[r] {
|
||||||
|
if w.seats[r][c].seat && w.seats[r][c].taken == 0 && w.countNeighborsPartTwo(r, c) == 0 {
|
||||||
|
newRoom.seats[r][c].seat = w.seats[r][c].seat
|
||||||
|
newRoom.seats[r][c].taken = 1
|
||||||
|
} else if w.seats[r][c].seat && w.seats[r][c].taken == 1 && w.countNeighborsPartTwo(r, c) >= 5 {
|
||||||
|
newRoom.seats[r][c].seat = w.seats[r][c].seat
|
||||||
|
newRoom.seats[r][c].taken = 0
|
||||||
|
} else {
|
||||||
|
newRoom.seats[r][c].seat = w.seats[r][c].seat
|
||||||
|
newRoom.seats[r][c].taken = w.seats[r][c].taken
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return newRoom
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *waitingRoom) countFilledSeats() int {
|
||||||
|
count := 0
|
||||||
|
for r := range w.seats {
|
||||||
|
for c := range w.seats[r] {
|
||||||
|
count = count + w.seats[r][c].taken
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *waitingRoom) print() {
|
||||||
|
for r := range w.seats {
|
||||||
|
s := ""
|
||||||
|
for c := range w.seats[r] {
|
||||||
|
if !w.seats[r][c].seat {
|
||||||
|
s = s + "."
|
||||||
|
} else if w.seats[r][c].taken == 0 {
|
||||||
|
s = s + "L"
|
||||||
|
} else if w.seats[r][c].taken == 1 {
|
||||||
|
s = s + "#"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt.Println(s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkStasis(old, new *waitingRoom) bool {
|
||||||
|
for r := range old.seats {
|
||||||
|
for c := range old.seats[r] {
|
||||||
|
if old.seats[r][c].seat && old.seats[r][c].taken != new.seats[r][c].taken {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func partOne() {
|
||||||
|
f, _ := os.Open("input")
|
||||||
|
reader := bufio.NewReader(f)
|
||||||
|
scanner := bufio.NewScanner(reader)
|
||||||
|
|
||||||
|
oldRoom := &waitingRoom{}
|
||||||
|
|
||||||
|
for scanner.Scan() {
|
||||||
|
line := scanner.Text()
|
||||||
|
oldRoom.parseRow(line)
|
||||||
|
}
|
||||||
|
|
||||||
|
oldRoom.maxCol = len(oldRoom.seats[0])
|
||||||
|
oldRoom.maxRow = len(oldRoom.seats)
|
||||||
|
|
||||||
|
for {
|
||||||
|
newRoom := oldRoom.makeNextStepPartOne()
|
||||||
|
if checkStasis(newRoom, oldRoom) {
|
||||||
|
fmt.Println(newRoom.countFilledSeats())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
oldRoom = newRoom
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func partTwo() {
|
||||||
|
f, _ := os.Open("input")
|
||||||
|
reader := bufio.NewReader(f)
|
||||||
|
scanner := bufio.NewScanner(reader)
|
||||||
|
oldRoom := &waitingRoom{}
|
||||||
|
|
||||||
|
for scanner.Scan() {
|
||||||
|
line := scanner.Text()
|
||||||
|
oldRoom.parseRow(line)
|
||||||
|
}
|
||||||
|
|
||||||
|
oldRoom.maxCol = len(oldRoom.seats[0])
|
||||||
|
oldRoom.maxRow = len(oldRoom.seats)
|
||||||
|
|
||||||
|
for {
|
||||||
|
newRoom := oldRoom.makeNextStepPartTwo()
|
||||||
|
if checkStasis(newRoom, oldRoom) {
|
||||||
|
fmt.Println(newRoom.countFilledSeats())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
oldRoom = newRoom
|
||||||
|
}
|
||||||
|
}
|
197
12/main.go
Normal file
197
12/main.go
Normal file
@@ -0,0 +1,197 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"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)
|
||||||
|
}
|
||||||
|
|
||||||
|
type ship struct {
|
||||||
|
horizontal int
|
||||||
|
vertical int
|
||||||
|
direction rune // E W N S
|
||||||
|
}
|
||||||
|
|
||||||
|
// both horizontal/vertical are relative to ship
|
||||||
|
type waypoint struct {
|
||||||
|
horizontal int
|
||||||
|
vertical int
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseLine(s string) (rune, int) {
|
||||||
|
i, _ := strconv.Atoi(s[1:])
|
||||||
|
return []rune(s)[0], i
|
||||||
|
}
|
||||||
|
|
||||||
|
func movePartOne(s ship, action rune, vector int) ship {
|
||||||
|
switch action {
|
||||||
|
case 'R', 'L':
|
||||||
|
s.direction = rotateShip(s.direction, vector, action)
|
||||||
|
case 'N':
|
||||||
|
s.vertical = s.vertical + vector
|
||||||
|
case 'S':
|
||||||
|
s.vertical = s.vertical - vector
|
||||||
|
case 'E':
|
||||||
|
s.horizontal = s.horizontal + vector
|
||||||
|
case 'W':
|
||||||
|
s.horizontal = s.horizontal - vector
|
||||||
|
case 'F':
|
||||||
|
s = movePartOne(s, s.direction, vector)
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func movePartTwo(s ship, w waypoint, action rune, vector int) (ship, waypoint) {
|
||||||
|
switch action {
|
||||||
|
case 'R', 'L':
|
||||||
|
w = rotateWaypoint(w, action, vector)
|
||||||
|
case 'N':
|
||||||
|
w.vertical = w.vertical + vector
|
||||||
|
case 'S':
|
||||||
|
w.vertical = w.vertical - vector
|
||||||
|
case 'E':
|
||||||
|
w.horizontal = w.horizontal + vector
|
||||||
|
case 'W':
|
||||||
|
w.horizontal = w.horizontal - vector
|
||||||
|
case 'F':
|
||||||
|
s.horizontal = s.horizontal + (w.horizontal * vector)
|
||||||
|
s.vertical = s.vertical + (w.vertical * vector)
|
||||||
|
}
|
||||||
|
return s, w
|
||||||
|
}
|
||||||
|
|
||||||
|
// for example E, 90, L => N; E, 180, R => W; E, 90, R => S
|
||||||
|
func rotateShip(current rune, degrees int, rl rune) rune {
|
||||||
|
// easy
|
||||||
|
if degrees == 180 {
|
||||||
|
switch current {
|
||||||
|
case 'N':
|
||||||
|
return 'S'
|
||||||
|
case 'S':
|
||||||
|
return 'N'
|
||||||
|
case 'E':
|
||||||
|
return 'W'
|
||||||
|
case 'W':
|
||||||
|
return 'E'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// translate L to R
|
||||||
|
if rl == 'L' {
|
||||||
|
if degrees == 90 {
|
||||||
|
degrees = 270
|
||||||
|
} else {
|
||||||
|
degrees = 90
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// the R set
|
||||||
|
if degrees == 90 {
|
||||||
|
switch current {
|
||||||
|
case 'N':
|
||||||
|
return 'E'
|
||||||
|
case 'S':
|
||||||
|
return 'W'
|
||||||
|
case 'E':
|
||||||
|
return 'S'
|
||||||
|
case 'W':
|
||||||
|
return 'N'
|
||||||
|
}
|
||||||
|
} else if degrees == 270 {
|
||||||
|
switch current {
|
||||||
|
case 'N':
|
||||||
|
return 'W'
|
||||||
|
case 'S':
|
||||||
|
return 'E'
|
||||||
|
case 'E':
|
||||||
|
return 'N'
|
||||||
|
case 'W':
|
||||||
|
return 'S'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return current // we're made a terrible mistake somewhere
|
||||||
|
}
|
||||||
|
|
||||||
|
func rotateWaypoint(w waypoint, action rune, vector int) waypoint {
|
||||||
|
if vector == 180 {
|
||||||
|
w.horizontal, w.vertical = -w.horizontal, -w.vertical
|
||||||
|
} else if action == 'R' {
|
||||||
|
if vector == 90 {
|
||||||
|
w.horizontal, w.vertical = w.vertical, -w.horizontal
|
||||||
|
}
|
||||||
|
if vector == 270 {
|
||||||
|
w.horizontal, w.vertical = -w.vertical, w.horizontal
|
||||||
|
}
|
||||||
|
} else if action == 'L' {
|
||||||
|
if vector == 90 {
|
||||||
|
w.horizontal, w.vertical = -w.vertical, w.horizontal
|
||||||
|
}
|
||||||
|
if vector == 270 {
|
||||||
|
w.horizontal, w.vertical = w.vertical, -w.horizontal
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return w
|
||||||
|
}
|
||||||
|
|
||||||
|
func manhattan(i, j int) int {
|
||||||
|
return abs(i) + abs(j)
|
||||||
|
}
|
||||||
|
|
||||||
|
func abs(x int) int {
|
||||||
|
if x < 0 {
|
||||||
|
return -x
|
||||||
|
}
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
|
||||||
|
func partOne() {
|
||||||
|
f, _ := os.Open("input")
|
||||||
|
reader := bufio.NewReader(f)
|
||||||
|
scanner := bufio.NewScanner(reader)
|
||||||
|
|
||||||
|
s := ship{
|
||||||
|
horizontal: 0,
|
||||||
|
vertical: 0,
|
||||||
|
direction: 'E',
|
||||||
|
}
|
||||||
|
|
||||||
|
for scanner.Scan() {
|
||||||
|
dir, vec := parseLine(scanner.Text())
|
||||||
|
s = movePartOne(s, dir, vec)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(manhattan(s.horizontal, s.vertical))
|
||||||
|
}
|
||||||
|
|
||||||
|
func partTwo() {
|
||||||
|
f, _ := os.Open("input")
|
||||||
|
reader := bufio.NewReader(f)
|
||||||
|
scanner := bufio.NewScanner(reader)
|
||||||
|
|
||||||
|
s := ship{
|
||||||
|
horizontal: 0,
|
||||||
|
vertical: 0,
|
||||||
|
// no longer care about ship direction
|
||||||
|
}
|
||||||
|
w := waypoint{
|
||||||
|
horizontal: 10,
|
||||||
|
vertical: 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
for scanner.Scan() {
|
||||||
|
dir, vec := parseLine(scanner.Text())
|
||||||
|
s, w = movePartTwo(s, w, dir, vec)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(manhattan(s.horizontal, s.vertical))
|
||||||
|
}
|
89
13/main.go
Normal file
89
13/main.go
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"math"
|
||||||
|
"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 partOne() {
|
||||||
|
f, _ := os.Open("input")
|
||||||
|
reader := bufio.NewReader(f)
|
||||||
|
scanner := bufio.NewScanner(reader)
|
||||||
|
|
||||||
|
busWaitTimes := map[int]int{}
|
||||||
|
shortestWait := -1
|
||||||
|
|
||||||
|
// don't actually need loop logic for a two-line input
|
||||||
|
scanner.Scan()
|
||||||
|
ts := scanner.Text()
|
||||||
|
currentTimestamp, _ := strconv.Atoi(ts)
|
||||||
|
|
||||||
|
scanner.Scan()
|
||||||
|
buses := strings.Split(scanner.Text(), ",")
|
||||||
|
for _, b := range buses {
|
||||||
|
if b != "x" {
|
||||||
|
j, _ := strconv.Atoi(b)
|
||||||
|
busWaitTimes[j] = (((currentTimestamp / j) + 1) * j) - currentTimestamp
|
||||||
|
if shortestWait == -1 || busWaitTimes[shortestWait] > busWaitTimes[j] {
|
||||||
|
shortestWait = j
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(busWaitTimes[shortestWait] * shortestWait)
|
||||||
|
}
|
||||||
|
|
||||||
|
type bus struct {
|
||||||
|
route float64
|
||||||
|
offset float64
|
||||||
|
}
|
||||||
|
|
||||||
|
func partTwo() {
|
||||||
|
f, _ := os.Open("input")
|
||||||
|
reader := bufio.NewReader(f)
|
||||||
|
scanner := bufio.NewScanner(reader)
|
||||||
|
|
||||||
|
buses := []bus{}
|
||||||
|
|
||||||
|
scanner.Scan() // discard first line
|
||||||
|
scanner.Scan()
|
||||||
|
line := strings.Split(scanner.Text(), ",")
|
||||||
|
for i, b := range line {
|
||||||
|
if b != "x" {
|
||||||
|
j, _ := strconv.Atoi(b)
|
||||||
|
buses = append(buses, bus{
|
||||||
|
route: float64(j),
|
||||||
|
offset: float64(i),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
t := float64(0)
|
||||||
|
offset := buses[0].route
|
||||||
|
loop:
|
||||||
|
t = t + offset
|
||||||
|
offset = 1
|
||||||
|
for i := range buses {
|
||||||
|
if math.Remainder(t+buses[i].offset, buses[i].route) != 0 {
|
||||||
|
goto loop
|
||||||
|
} else {
|
||||||
|
offset = offset * buses[i].route
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(int(t))
|
||||||
|
}
|
148
14/main.go
Normal file
148
14/main.go
Normal file
@@ -0,0 +1,148 @@
|
|||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
type bitset struct {
|
||||||
|
bits []string
|
||||||
|
}
|
||||||
|
|
||||||
|
func newBitset(i int) bitset {
|
||||||
|
b := strings.Split(fmt.Sprintf("%036b", i), "")
|
||||||
|
bs := bitset{
|
||||||
|
bits: strings.Split("000000000000000000000000000000000000", ""),
|
||||||
|
}
|
||||||
|
for i, bt := range b {
|
||||||
|
if bt != "0" {
|
||||||
|
bs.bits[i] = bt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bs
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b bitset) ToInt() int {
|
||||||
|
i, _ := strconv.ParseInt(strings.Join(b.bits, ""), 2, 64)
|
||||||
|
return int(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseMask(s string) string {
|
||||||
|
return strings.Split(s, " = ")[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseMemoryToAddrAndBitset(s string) (int, bitset) {
|
||||||
|
a := strings.Split(s, " = ")
|
||||||
|
addr, _ := strconv.Atoi(strings.TrimFunc(a[0], func(r rune) bool {
|
||||||
|
if r == 'm' || r == 'e' || r == '[' || r == ']' {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}))
|
||||||
|
i, _ := strconv.Atoi(a[1])
|
||||||
|
return addr, newBitset(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseMemoryToBitsetAndValue(s string) (bitset, int) {
|
||||||
|
a := strings.Split(s, " = ")
|
||||||
|
addr, _ := strconv.Atoi(strings.TrimFunc(a[0], func(r rune) bool {
|
||||||
|
if r == 'm' || r == 'e' || r == '[' || r == ']' {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}))
|
||||||
|
i, _ := strconv.Atoi(a[1])
|
||||||
|
return newBitset(addr), i
|
||||||
|
}
|
||||||
|
|
||||||
|
func applyMaskToValue(m string, b bitset) int {
|
||||||
|
for i, r := range m {
|
||||||
|
if r == '0' {
|
||||||
|
b.bits[i] = "0"
|
||||||
|
}
|
||||||
|
if r == '1' {
|
||||||
|
b.bits[i] = "1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return b.ToInt()
|
||||||
|
}
|
||||||
|
|
||||||
|
func applyMaskToAddr(prefix []string, m string, attr bitset) []bitset {
|
||||||
|
if len(m) == 0 {
|
||||||
|
return []bitset{{bits: prefix}}
|
||||||
|
}
|
||||||
|
res := []bitset{}
|
||||||
|
for _, r := range m {
|
||||||
|
if r == '0' || r == 'X' {
|
||||||
|
res = append(res, applyMaskToAddr(append(prefix[:], "0"), m[1:], attr)...)
|
||||||
|
}
|
||||||
|
if r == '1' || r == 'X' {
|
||||||
|
res = append(res, applyMaskToAddr(append(prefix[:], "1"), m[1:], attr)...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
func partOne() {
|
||||||
|
f, _ := os.Open("input")
|
||||||
|
reader := bufio.NewReader(f)
|
||||||
|
scanner := bufio.NewScanner(reader)
|
||||||
|
|
||||||
|
mem := map[int]int{}
|
||||||
|
var currentMask string
|
||||||
|
|
||||||
|
for scanner.Scan() {
|
||||||
|
line := scanner.Text()
|
||||||
|
if strings.HasPrefix(line, "mask") {
|
||||||
|
currentMask = parseMask(line)
|
||||||
|
} else {
|
||||||
|
addr, value := parseMemoryToAddrAndBitset(line)
|
||||||
|
mem[addr] = applyMaskToValue(currentMask, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sum := 0
|
||||||
|
for _, v := range mem {
|
||||||
|
sum = sum + v
|
||||||
|
}
|
||||||
|
fmt.Println(sum)
|
||||||
|
}
|
||||||
|
|
||||||
|
func partTwo() {
|
||||||
|
f, _ := os.Open("testinput")
|
||||||
|
reader := bufio.NewReader(f)
|
||||||
|
scanner := bufio.NewScanner(reader)
|
||||||
|
|
||||||
|
mem := map[int]int{}
|
||||||
|
var currentMask string
|
||||||
|
|
||||||
|
for scanner.Scan() {
|
||||||
|
line := scanner.Text()
|
||||||
|
if strings.HasPrefix(line, "mask") {
|
||||||
|
currentMask = parseMask(line)
|
||||||
|
} else {
|
||||||
|
addr, value := parseMemoryToBitsetAndValue(line)
|
||||||
|
for _, b := range applyMaskToAddr([]string{}, currentMask, addr) {
|
||||||
|
mem[b.ToInt()] = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sum := 0
|
||||||
|
for _, v := range mem {
|
||||||
|
sum = sum + v
|
||||||
|
}
|
||||||
|
fmt.Println(sum)
|
||||||
|
}
|
85
15/main.go
Normal file
85
15/main.go
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
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 partOne() {
|
||||||
|
f, _ := os.Open("input")
|
||||||
|
reader := bufio.NewReader(f)
|
||||||
|
scanner := bufio.NewScanner(reader)
|
||||||
|
|
||||||
|
// naive implementation
|
||||||
|
scanner.Scan()
|
||||||
|
numbers := strings.Split(scanner.Text(), ",")
|
||||||
|
for {
|
||||||
|
i := len(numbers) - 1
|
||||||
|
lastNumber := numbers[i]
|
||||||
|
// walk backward through the list, looking for a match
|
||||||
|
for j := range numbers {
|
||||||
|
if len(numbers) == 2020 {
|
||||||
|
fmt.Println(numbers[2019])
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if i-j == 0 {
|
||||||
|
// made it to the head of the list, no matches; append 0
|
||||||
|
numbers = append(numbers, "0")
|
||||||
|
break
|
||||||
|
} else if numbers[i-j-1] == lastNumber {
|
||||||
|
// a number matched; insert the difference between the last number and when we last saw it
|
||||||
|
numbers = append(numbers, fmt.Sprintf("%d", len(numbers)-1-(i-j-1)))
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func partTwo() {
|
||||||
|
f, _ := os.Open("input")
|
||||||
|
reader := bufio.NewReader(f)
|
||||||
|
scanner := bufio.NewScanner(reader)
|
||||||
|
|
||||||
|
// caching implementation. It's still slow, but it at least finishes...!
|
||||||
|
scanner.Scan()
|
||||||
|
numbers := strings.Split(scanner.Text(), ",")
|
||||||
|
seen := make(map[int]int)
|
||||||
|
|
||||||
|
// load in numbers
|
||||||
|
for i, v := range numbers[:len(numbers)-1] {
|
||||||
|
j, _ := strconv.Atoi(v)
|
||||||
|
seen[j] = i
|
||||||
|
}
|
||||||
|
|
||||||
|
i := len(numbers) - 1
|
||||||
|
lastNumber, _ := strconv.Atoi(numbers[i])
|
||||||
|
for {
|
||||||
|
if seen[lastNumber] == 30000000-1 {
|
||||||
|
fmt.Println(lastNumber)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if v, ok := seen[lastNumber]; ok {
|
||||||
|
// a number matched; insert the difference between the last number and when we last saw it
|
||||||
|
seen[lastNumber] = i
|
||||||
|
lastNumber = i - v
|
||||||
|
} else {
|
||||||
|
// never seen that before
|
||||||
|
seen[lastNumber] = i
|
||||||
|
lastNumber = 0
|
||||||
|
}
|
||||||
|
i = i + 1
|
||||||
|
}
|
||||||
|
}
|
232
16/main.go
Normal file
232
16/main.go
Normal file
@@ -0,0 +1,232 @@
|
|||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
type valuerange struct {
|
||||||
|
min int
|
||||||
|
max int
|
||||||
|
}
|
||||||
|
|
||||||
|
type rule struct {
|
||||||
|
name string
|
||||||
|
ranges []valuerange
|
||||||
|
field int
|
||||||
|
}
|
||||||
|
|
||||||
|
type ticket struct {
|
||||||
|
values []int
|
||||||
|
valid bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseRule(s string) rule {
|
||||||
|
q := strings.Split(s, ": ")
|
||||||
|
ru := rule{
|
||||||
|
name: q[0],
|
||||||
|
ranges: make([]valuerange, 0, 2),
|
||||||
|
}
|
||||||
|
r := strings.Split(q[1], " or ")
|
||||||
|
for _, rr := range r {
|
||||||
|
mm := strings.Split(rr, "-")
|
||||||
|
min, _ := strconv.Atoi(mm[0])
|
||||||
|
max, _ := strconv.Atoi(mm[1])
|
||||||
|
ru.ranges = append(ru.ranges, valuerange{min: min, max: max})
|
||||||
|
}
|
||||||
|
return ru
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseTicket(s string) ticket {
|
||||||
|
t := ticket{
|
||||||
|
values: []int{},
|
||||||
|
}
|
||||||
|
vs := strings.Split(s, ",")
|
||||||
|
for _, v := range vs {
|
||||||
|
vi, _ := strconv.Atoi(v)
|
||||||
|
t.values = append(t.values, vi)
|
||||||
|
}
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
|
||||||
|
// return valid/invalid and the invalid value, if found
|
||||||
|
func validateTicket(r []rule, t ticket) (bool, int) {
|
||||||
|
for _, ta := range t.values {
|
||||||
|
ok := false
|
||||||
|
for _, ru := range r {
|
||||||
|
outsideRule := (ta < ru.ranges[0].min || (ta > ru.ranges[0].max && ta < ru.ranges[1].min) || ta > ru.ranges[1].max)
|
||||||
|
if ok || !outsideRule {
|
||||||
|
ok = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !ok {
|
||||||
|
return false, ta
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true, 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns a mapping of fields to possible rules
|
||||||
|
func guessFields(rules []rule, tickets []ticket) map[int][]int {
|
||||||
|
guesses := map[int][]int{}
|
||||||
|
for ri, r := range rules {
|
||||||
|
for i := range tickets[0].values { // loop over the fields on tickets, and...
|
||||||
|
ok := true
|
||||||
|
for _, t := range tickets { // loop over all the tickets...
|
||||||
|
ta := t.values[i] // checking the current field value...
|
||||||
|
outsideRule := (ta < r.ranges[0].min || (ta > r.ranges[0].max && ta < r.ranges[1].min) || ta > r.ranges[1].max)
|
||||||
|
if !ok || outsideRule { // checking if any of the tickets fall outside our rule's range.
|
||||||
|
ok = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ok { // if all tickets pass, we've got a hit
|
||||||
|
guesses[i] = append(guesses[i], ri)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return guesses
|
||||||
|
}
|
||||||
|
|
||||||
|
func reduce(g map[int][]int) (int, int) {
|
||||||
|
for i, j := range g {
|
||||||
|
if len(j) == 1 {
|
||||||
|
return i, j[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0, 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func remove(a []int, rule int) []int {
|
||||||
|
for i, j := range a {
|
||||||
|
if j == rule {
|
||||||
|
a[i] = a[len(a)-1]
|
||||||
|
a[len(a)-1] = 0
|
||||||
|
return a[:len(a)-1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
|
||||||
|
func partOne() {
|
||||||
|
f, _ := os.Open("input")
|
||||||
|
reader := bufio.NewReader(f)
|
||||||
|
scanner := bufio.NewScanner(reader)
|
||||||
|
|
||||||
|
rules := []rule{}
|
||||||
|
tickets := []ticket{}
|
||||||
|
invalidityRate := 0
|
||||||
|
|
||||||
|
seenAllRules := false
|
||||||
|
seenMyTicket := false
|
||||||
|
for scanner.Scan() {
|
||||||
|
line := scanner.Text()
|
||||||
|
// check for end of rules list
|
||||||
|
if line == "" && !seenAllRules {
|
||||||
|
seenAllRules = true
|
||||||
|
scanner.Scan() // clear out the following line
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// parse rules until we run out
|
||||||
|
if !seenAllRules {
|
||||||
|
rules = append(rules, parseRule(line))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// parse own ticket, then clear for remaining tickets
|
||||||
|
if !seenMyTicket {
|
||||||
|
tickets = append(tickets, parseTicket(scanner.Text()))
|
||||||
|
seenMyTicket = true
|
||||||
|
scanner.Scan() // clear out the next two lines
|
||||||
|
scanner.Scan()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// parse and validate other people's tickets
|
||||||
|
t := parseTicket(line)
|
||||||
|
ok, i := validateTicket(rules, t)
|
||||||
|
if !ok {
|
||||||
|
t.valid = false
|
||||||
|
invalidityRate = invalidityRate + i
|
||||||
|
} else {
|
||||||
|
t.valid = true
|
||||||
|
tickets = append(tickets, t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt.Println(invalidityRate)
|
||||||
|
}
|
||||||
|
|
||||||
|
func partTwo() {
|
||||||
|
f, _ := os.Open("input")
|
||||||
|
reader := bufio.NewReader(f)
|
||||||
|
scanner := bufio.NewScanner(reader)
|
||||||
|
|
||||||
|
rules := []rule{}
|
||||||
|
myTicket := ticket{}
|
||||||
|
tickets := []ticket{}
|
||||||
|
|
||||||
|
seenAllRules := false
|
||||||
|
seenMyTicket := false
|
||||||
|
for scanner.Scan() {
|
||||||
|
line := scanner.Text()
|
||||||
|
// check for end of rules list
|
||||||
|
if line == "" && !seenAllRules {
|
||||||
|
seenAllRules = true
|
||||||
|
scanner.Scan() // clear out the following line
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// parse rules until we run out
|
||||||
|
if !seenAllRules {
|
||||||
|
rules = append(rules, parseRule(line))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// parse own ticket, then clear for remaining tickets
|
||||||
|
if !seenMyTicket {
|
||||||
|
myTicket = parseTicket(scanner.Text())
|
||||||
|
tickets = append(tickets, myTicket)
|
||||||
|
seenMyTicket = true
|
||||||
|
scanner.Scan() // clear out the next two lines
|
||||||
|
scanner.Scan()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// parse and validate other people's tickets
|
||||||
|
t := parseTicket(line)
|
||||||
|
ok, _ := validateTicket(rules, t)
|
||||||
|
if ok {
|
||||||
|
t.valid = true
|
||||||
|
tickets = append(tickets, t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
guesses := guessFields(rules, tickets)
|
||||||
|
var lastRuleSolved int
|
||||||
|
// iterate over the guesses list. on every iteration, only one field has only one rule remaining that's valid
|
||||||
|
// save it off into the rules list, then remove that rule from all fields.
|
||||||
|
// Luckily, we don't need any higher-order elimination logic.
|
||||||
|
for i := 1; i < len(guesses); i++ {
|
||||||
|
for i, g := range guesses {
|
||||||
|
if len(g) == 1 {
|
||||||
|
rules[g[0]].field = i
|
||||||
|
lastRuleSolved = g[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for i := range guesses {
|
||||||
|
guesses[i] = remove(guesses[i], lastRuleSolved)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result := 1
|
||||||
|
// first 6 rules are our "departure" rules
|
||||||
|
for _, r := range rules[:6] {
|
||||||
|
result = result * myTicket.values[r.field]
|
||||||
|
}
|
||||||
|
fmt.Println(result)
|
||||||
|
}
|
235
17/main.go
Normal file
235
17/main.go
Normal file
@@ -0,0 +1,235 @@
|
|||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
type cell struct {
|
||||||
|
x int // length
|
||||||
|
y int // width
|
||||||
|
z int // depth
|
||||||
|
w int // spissitude
|
||||||
|
}
|
||||||
|
|
||||||
|
type universe struct {
|
||||||
|
cells map[cell]bool
|
||||||
|
hyper bool // true: 4-dimensional; false: 3-dimensional
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeNeighborsList(c cell, hyper bool) []cell {
|
||||||
|
cells := []cell{}
|
||||||
|
if hyper {
|
||||||
|
cells = append(cells, []cell{
|
||||||
|
// outward...?
|
||||||
|
// above
|
||||||
|
{x: c.x + 1, y: c.y + 1, z: c.z + 1, w: c.w + 1},
|
||||||
|
{x: c.x + 1, y: c.y, z: c.z + 1, w: c.w + 1},
|
||||||
|
{x: c.x + 1, y: c.y - 1, z: c.z + 1, w: c.w + 1},
|
||||||
|
{x: c.x, y: c.y + 1, z: c.z + 1, w: c.w + 1},
|
||||||
|
{x: c.x, y: c.y, z: c.z + 1, w: c.w + 1},
|
||||||
|
{x: c.x, y: c.y - 1, z: c.z + 1, w: c.w + 1},
|
||||||
|
{x: c.x - 1, y: c.y + 1, z: c.z + 1, w: c.w + 1},
|
||||||
|
{x: c.x - 1, y: c.y, z: c.z + 1, w: c.w + 1},
|
||||||
|
{x: c.x - 1, y: c.y - 1, z: c.z + 1, w: c.w + 1},
|
||||||
|
|
||||||
|
// same layer
|
||||||
|
{x: c.x + 1, y: c.y + 1, z: c.z, w: c.w + 1},
|
||||||
|
{x: c.x + 1, y: c.y, z: c.z, w: c.w + 1},
|
||||||
|
{x: c.x + 1, y: c.y - 1, z: c.z, w: c.w + 1},
|
||||||
|
{x: c.x, y: c.y + 1, z: c.z, w: c.w + 1},
|
||||||
|
{x: c.x, y: c.y, z: c.z, w: c.w + 1},
|
||||||
|
{x: c.x, y: c.y - 1, z: c.z, w: c.w + 1},
|
||||||
|
{x: c.x - 1, y: c.y + 1, z: c.z, w: c.w + 1},
|
||||||
|
{x: c.x - 1, y: c.y, z: c.z, w: c.w + 1},
|
||||||
|
{x: c.x - 1, y: c.y - 1, z: c.z, w: c.w + 1},
|
||||||
|
|
||||||
|
// below
|
||||||
|
{x: c.x + 1, y: c.y + 1, z: c.z - 1, w: c.w + 1},
|
||||||
|
{x: c.x + 1, y: c.y, z: c.z - 1, w: c.w + 1},
|
||||||
|
{x: c.x + 1, y: c.y - 1, z: c.z - 1, w: c.w + 1},
|
||||||
|
{x: c.x, y: c.y + 1, z: c.z - 1, w: c.w + 1},
|
||||||
|
{x: c.x, y: c.y, z: c.z - 1, w: c.w + 1},
|
||||||
|
{x: c.x, y: c.y - 1, z: c.z - 1, w: c.w + 1},
|
||||||
|
{x: c.x - 1, y: c.y + 1, z: c.z - 1, w: c.w + 1},
|
||||||
|
{x: c.x - 1, y: c.y, z: c.z - 1, w: c.w + 1},
|
||||||
|
{x: c.x - 1, y: c.y - 1, z: c.z - 1, w: c.w + 1},
|
||||||
|
// inward...?
|
||||||
|
// above
|
||||||
|
{x: c.x + 1, y: c.y + 1, z: c.z + 1, w: c.w - 1},
|
||||||
|
{x: c.x + 1, y: c.y, z: c.z + 1, w: c.w - 1},
|
||||||
|
{x: c.x + 1, y: c.y - 1, z: c.z + 1, w: c.w - 1},
|
||||||
|
{x: c.x, y: c.y + 1, z: c.z + 1, w: c.w - 1},
|
||||||
|
{x: c.x, y: c.y, z: c.z + 1, w: c.w - 1},
|
||||||
|
{x: c.x, y: c.y - 1, z: c.z + 1, w: c.w - 1},
|
||||||
|
{x: c.x - 1, y: c.y + 1, z: c.z + 1, w: c.w - 1},
|
||||||
|
{x: c.x - 1, y: c.y, z: c.z + 1, w: c.w - 1},
|
||||||
|
{x: c.x - 1, y: c.y - 1, z: c.z + 1, w: c.w - 1},
|
||||||
|
|
||||||
|
// same layer
|
||||||
|
{x: c.x + 1, y: c.y + 1, z: c.z, w: c.w - 1},
|
||||||
|
{x: c.x + 1, y: c.y, z: c.z, w: c.w - 1},
|
||||||
|
{x: c.x + 1, y: c.y - 1, z: c.z, w: c.w - 1},
|
||||||
|
{x: c.x, y: c.y + 1, z: c.z, w: c.w - 1},
|
||||||
|
{x: c.x, y: c.y, z: c.z, w: c.w - 1},
|
||||||
|
{x: c.x, y: c.y - 1, z: c.z, w: c.w - 1},
|
||||||
|
{x: c.x - 1, y: c.y + 1, z: c.z, w: c.w - 1},
|
||||||
|
{x: c.x - 1, y: c.y, z: c.z, w: c.w - 1},
|
||||||
|
{x: c.x - 1, y: c.y - 1, z: c.z, w: c.w - 1},
|
||||||
|
|
||||||
|
// below
|
||||||
|
{x: c.x + 1, y: c.y + 1, z: c.z - 1, w: c.w - 1},
|
||||||
|
{x: c.x + 1, y: c.y, z: c.z - 1, w: c.w - 1},
|
||||||
|
{x: c.x + 1, y: c.y - 1, z: c.z - 1, w: c.w - 1},
|
||||||
|
{x: c.x, y: c.y + 1, z: c.z - 1, w: c.w - 1},
|
||||||
|
{x: c.x, y: c.y, z: c.z - 1, w: c.w - 1},
|
||||||
|
{x: c.x, y: c.y - 1, z: c.z - 1, w: c.w - 1},
|
||||||
|
{x: c.x - 1, y: c.y + 1, z: c.z - 1, w: c.w - 1},
|
||||||
|
{x: c.x - 1, y: c.y, z: c.z - 1, w: c.w - 1},
|
||||||
|
{x: c.x - 1, y: c.y - 1, z: c.z - 1, w: c.w - 1},
|
||||||
|
}...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// "normal" space
|
||||||
|
cells = append(cells, []cell{
|
||||||
|
// above
|
||||||
|
{x: c.x + 1, y: c.y + 1, z: c.z + 1, w: c.w},
|
||||||
|
{x: c.x + 1, y: c.y, z: c.z + 1, w: c.w},
|
||||||
|
{x: c.x + 1, y: c.y - 1, z: c.z + 1, w: c.w},
|
||||||
|
{x: c.x, y: c.y + 1, z: c.z + 1, w: c.w},
|
||||||
|
{x: c.x, y: c.y, z: c.z + 1, w: c.w},
|
||||||
|
{x: c.x, y: c.y - 1, z: c.z + 1, w: c.w},
|
||||||
|
{x: c.x - 1, y: c.y + 1, z: c.z + 1, w: c.w},
|
||||||
|
{x: c.x - 1, y: c.y, z: c.z + 1, w: c.w},
|
||||||
|
{x: c.x - 1, y: c.y - 1, z: c.z + 1, w: c.w},
|
||||||
|
|
||||||
|
// same layer
|
||||||
|
{x: c.x + 1, y: c.y + 1, z: c.z, w: c.w},
|
||||||
|
{x: c.x + 1, y: c.y, z: c.z, w: c.w},
|
||||||
|
{x: c.x + 1, y: c.y - 1, z: c.z, w: c.w},
|
||||||
|
{x: c.x, y: c.y + 1, z: c.z, w: c.w},
|
||||||
|
// <-- original cell
|
||||||
|
{x: c.x, y: c.y - 1, z: c.z, w: c.w},
|
||||||
|
{x: c.x - 1, y: c.y + 1, z: c.z, w: c.w},
|
||||||
|
{x: c.x - 1, y: c.y, z: c.z, w: c.w},
|
||||||
|
{x: c.x - 1, y: c.y - 1, z: c.z, w: c.w},
|
||||||
|
|
||||||
|
// below
|
||||||
|
{x: c.x + 1, y: c.y + 1, z: c.z - 1, w: c.w},
|
||||||
|
{x: c.x + 1, y: c.y, z: c.z - 1, w: c.w},
|
||||||
|
{x: c.x + 1, y: c.y - 1, z: c.z - 1, w: c.w},
|
||||||
|
{x: c.x, y: c.y + 1, z: c.z - 1, w: c.w},
|
||||||
|
{x: c.x, y: c.y, z: c.z - 1, w: c.w},
|
||||||
|
{x: c.x, y: c.y - 1, z: c.z - 1, w: c.w},
|
||||||
|
{x: c.x - 1, y: c.y + 1, z: c.z - 1, w: c.w},
|
||||||
|
{x: c.x - 1, y: c.y, z: c.z - 1, w: c.w},
|
||||||
|
{x: c.x - 1, y: c.y - 1, z: c.z - 1, w: c.w},
|
||||||
|
}...)
|
||||||
|
|
||||||
|
return cells
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkNeighbors(u universe, c cell) bool {
|
||||||
|
sum := 0
|
||||||
|
for _, c := range makeNeighborsList(c, u.hyper) {
|
||||||
|
if u.cells[c] {
|
||||||
|
sum = sum + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if sum == 3 {
|
||||||
|
return true
|
||||||
|
} else if u.cells[c] && sum == 2 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func step(old universe) universe {
|
||||||
|
new := universe{
|
||||||
|
cells: make(map[cell]bool, len(old.cells)),
|
||||||
|
hyper: old.hyper,
|
||||||
|
}
|
||||||
|
cellsToCheck := make([]cell, 0, len(old.cells)*80)
|
||||||
|
for c := range old.cells {
|
||||||
|
cellsToCheck = append(cellsToCheck, makeNeighborsList(c, old.hyper)...)
|
||||||
|
}
|
||||||
|
for _, c := range cellsToCheck {
|
||||||
|
if checkNeighbors(old, c) {
|
||||||
|
new.cells[c] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new
|
||||||
|
}
|
||||||
|
|
||||||
|
func newUniverse(input []string, hyper bool) universe {
|
||||||
|
u := universe{
|
||||||
|
cells: make(map[cell]bool, len(input)),
|
||||||
|
hyper: hyper,
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, r := range input {
|
||||||
|
for j, c := range r {
|
||||||
|
if c == '#' {
|
||||||
|
u.cells[cell{z: 0, x: i, y: j, w: 0}] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return u
|
||||||
|
}
|
||||||
|
|
||||||
|
func countActivesInUniverse(u universe) {
|
||||||
|
fmt.Println(len(u.cells))
|
||||||
|
}
|
||||||
|
|
||||||
|
func partOne() {
|
||||||
|
f, _ := os.Open("input")
|
||||||
|
reader := bufio.NewReader(f)
|
||||||
|
scanner := bufio.NewScanner(reader)
|
||||||
|
|
||||||
|
var input []string
|
||||||
|
|
||||||
|
for scanner.Scan() {
|
||||||
|
input = append(input, scanner.Text())
|
||||||
|
}
|
||||||
|
|
||||||
|
u := newUniverse(input, false)
|
||||||
|
u = step(u)
|
||||||
|
u = step(u)
|
||||||
|
u = step(u)
|
||||||
|
u = step(u)
|
||||||
|
u = step(u)
|
||||||
|
u = step(u)
|
||||||
|
countActivesInUniverse(u)
|
||||||
|
}
|
||||||
|
|
||||||
|
func partTwo() {
|
||||||
|
f, _ := os.Open("input")
|
||||||
|
reader := bufio.NewReader(f)
|
||||||
|
scanner := bufio.NewScanner(reader)
|
||||||
|
|
||||||
|
var input []string
|
||||||
|
for scanner.Scan() {
|
||||||
|
input = append(input, scanner.Text())
|
||||||
|
}
|
||||||
|
|
||||||
|
u := newUniverse(input, true)
|
||||||
|
u = step(u)
|
||||||
|
u = step(u)
|
||||||
|
u = step(u)
|
||||||
|
u = step(u)
|
||||||
|
u = step(u)
|
||||||
|
u = step(u)
|
||||||
|
countActivesInUniverse(u)
|
||||||
|
}
|
180
18/main.go
Normal file
180
18/main.go
Normal file
@@ -0,0 +1,180 @@
|
|||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
// an expression is a list of expressions and a list of operators that intersperse those expressions, OR a number.
|
||||||
|
// as a sanity check, the length of the body list should always be one more than operators, unless both are 0,
|
||||||
|
// in which case number must be set. Luckily, we don't have to worry about 0 (the "empty" state for numbers).
|
||||||
|
type expression struct {
|
||||||
|
body []expression
|
||||||
|
operators []op
|
||||||
|
number int
|
||||||
|
}
|
||||||
|
|
||||||
|
// op can be one of two things.
|
||||||
|
type op struct {
|
||||||
|
plus bool
|
||||||
|
multiply bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1 + 2 should parse to
|
||||||
|
// expression{
|
||||||
|
// body:[
|
||||||
|
// expression{number: 1},
|
||||||
|
// expression{number: 2},
|
||||||
|
// ],
|
||||||
|
// operators:[
|
||||||
|
// op{plus: true},
|
||||||
|
// ],
|
||||||
|
// }
|
||||||
|
|
||||||
|
// (2 * 2) + 2 should parse to:
|
||||||
|
// expression{
|
||||||
|
// body:[
|
||||||
|
// expression{
|
||||||
|
// body: [
|
||||||
|
// expression{number: 2},
|
||||||
|
// expression{number: 2},
|
||||||
|
// ],
|
||||||
|
// operators: [
|
||||||
|
// op{multiply: true},
|
||||||
|
// ],
|
||||||
|
// },
|
||||||
|
// expression{number: 2},
|
||||||
|
// ],
|
||||||
|
// operators:[
|
||||||
|
// op{plus:true}
|
||||||
|
// ]
|
||||||
|
// }
|
||||||
|
|
||||||
|
func parseExpression(e expression, s string) (expression, string) {
|
||||||
|
for i := 0; i < len(s); {
|
||||||
|
switch s[i] {
|
||||||
|
case '(':
|
||||||
|
sub, remainder := parseExpression(expression{}, s[i+1:])
|
||||||
|
e.body = append(e.body, sub)
|
||||||
|
i = len(s) - len(remainder) + 1 // skip everything we just parsed in the subexpression
|
||||||
|
case ')':
|
||||||
|
return e, s[i:]
|
||||||
|
case '*':
|
||||||
|
e.operators = append(e.operators, op{multiply: true})
|
||||||
|
i = i + 1
|
||||||
|
case '+':
|
||||||
|
e.operators = append(e.operators, op{plus: true})
|
||||||
|
i = i + 1
|
||||||
|
case ' ':
|
||||||
|
i = i + 1
|
||||||
|
case '1', '2', '3', '4', '5', '6', '7', '8', '9':
|
||||||
|
// luckily, it's all single-digit numbers and I don't need to track parser state
|
||||||
|
// an ASCII byte number minus the rune value of 0 equals the integer itself: '1' - '0' == 49 - 48;
|
||||||
|
// rune math returns a platform-specific int, so cast to generic int.
|
||||||
|
e.body = append(e.body, expression{number: int(s[i] - '0')})
|
||||||
|
i = i + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return e, ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func printExpression(e expression) string {
|
||||||
|
result := ""
|
||||||
|
for i := 0; i < len(e.body); i = i + 1 {
|
||||||
|
if e.body[i].number != 0 {
|
||||||
|
result = result + fmt.Sprintf("%d ", e.body[i].number)
|
||||||
|
} else {
|
||||||
|
result = result + "(" + printExpression(e.body[i]) + ") "
|
||||||
|
}
|
||||||
|
if i < len(e.operators) {
|
||||||
|
if e.operators[i].multiply {
|
||||||
|
result = result + "* "
|
||||||
|
} else if e.operators[i].plus {
|
||||||
|
result = result + "+ "
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return strings.TrimSpace(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
// evaluation starts at the root then descends into the sub-expressions.
|
||||||
|
func evalLeftToRight(e expression) int {
|
||||||
|
var result int
|
||||||
|
if e.number != 0 {
|
||||||
|
result = e.number
|
||||||
|
} else {
|
||||||
|
result = evalLeftToRight(e.body[0])
|
||||||
|
}
|
||||||
|
for i := 0; i < len(e.operators); i = i + 1 {
|
||||||
|
if e.operators[i].multiply {
|
||||||
|
result = result * evalLeftToRight(e.body[i+1])
|
||||||
|
}
|
||||||
|
if e.operators[i].plus {
|
||||||
|
result = result + evalLeftToRight(e.body[i+1])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// previous approach might not work...
|
||||||
|
func evalPlusThenMultiplication(e expression) int {
|
||||||
|
var result int
|
||||||
|
if e.number != 0 {
|
||||||
|
result = e.number
|
||||||
|
} else {
|
||||||
|
result = evalPlusThenMultiplication(e.body[0])
|
||||||
|
}
|
||||||
|
for i := 0; i < len(e.operators); i = i + 1 {
|
||||||
|
if e.operators[i].multiply {
|
||||||
|
result = result * evalPlusThenMultiplication(e.body[i+1])
|
||||||
|
}
|
||||||
|
if e.operators[i].plus {
|
||||||
|
result = result + evalPlusThenMultiplication(e.body[i+1])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func partOne() {
|
||||||
|
f, _ := os.Open("input")
|
||||||
|
reader := bufio.NewReader(f)
|
||||||
|
scanner := bufio.NewScanner(reader)
|
||||||
|
|
||||||
|
total := 0
|
||||||
|
|
||||||
|
for scanner.Scan() {
|
||||||
|
line := scanner.Text()
|
||||||
|
e, _ := parseExpression(expression{}, line)
|
||||||
|
total = total + evalLeftToRight(e)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(total)
|
||||||
|
}
|
||||||
|
|
||||||
|
func partTwo() {
|
||||||
|
f, _ := os.Open("testinput")
|
||||||
|
reader := bufio.NewReader(f)
|
||||||
|
scanner := bufio.NewScanner(reader)
|
||||||
|
|
||||||
|
total := 0
|
||||||
|
|
||||||
|
for scanner.Scan() {
|
||||||
|
line := scanner.Text()
|
||||||
|
e, _ := parseExpression(expression{}, line)
|
||||||
|
fmt.Println(printExpression(e), "=", evalPlusThenMultiplication(e))
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(total)
|
||||||
|
}
|
175
19/main.go
Normal file
175
19/main.go
Normal file
@@ -0,0 +1,175 @@
|
|||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
// options: 20 => [][20]; 20 10 => [][20, 10]; 20 | 10 => [][20][10]; 20 10 | 39 12 => [][20, 10][39, 12];
|
||||||
|
// token is only set for the two "bottom" rules of "a" and "b"
|
||||||
|
// options and token will never both be set
|
||||||
|
// ints all point to rule numbers in overall rule list
|
||||||
|
type rule struct {
|
||||||
|
name int
|
||||||
|
options [][]int
|
||||||
|
token rune
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseRule(s string) rule {
|
||||||
|
r := rule{
|
||||||
|
options: make([][]int, 0),
|
||||||
|
}
|
||||||
|
sp := strings.Split(s, ": ")
|
||||||
|
r.name, _ = strconv.Atoi(sp[0])
|
||||||
|
|
||||||
|
// either it's a token rule...
|
||||||
|
if sp[1] == `"a"` || sp[1] == `"b"` {
|
||||||
|
r.token = []rune(strings.Trim(sp[1], `"`))[0]
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
// ...or an options rule.
|
||||||
|
opts := strings.Split(sp[1], " | ")
|
||||||
|
for _, o := range opts {
|
||||||
|
opt := []int{}
|
||||||
|
for _, i := range strings.Split(o, " ") {
|
||||||
|
ii, _ := strconv.Atoi(i)
|
||||||
|
opt = append(opt, ii)
|
||||||
|
}
|
||||||
|
r.options = append(r.options, opt)
|
||||||
|
}
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateString(rules []rule, currentRule int, s string) (bool, string) {
|
||||||
|
activeRule := rules[currentRule]
|
||||||
|
// if we're run out of string, the rule obviously cannot match
|
||||||
|
if len(s) == 0 {
|
||||||
|
return false, ""
|
||||||
|
}
|
||||||
|
// we've reached a leaf; check if the current head of the string matches our expected rune
|
||||||
|
if len(activeRule.options) == 0 {
|
||||||
|
return []rune(s)[0] == activeRule.token, s[1:]
|
||||||
|
}
|
||||||
|
// if there's only one option, attempt to apply the rules
|
||||||
|
if len(activeRule.options) == 1 {
|
||||||
|
option := activeRule.options[0]
|
||||||
|
if len(option) == 1 {
|
||||||
|
return validateString(rules, option[0], s)
|
||||||
|
}
|
||||||
|
if len(option) == 2 {
|
||||||
|
ok, remainder := validateString(rules, option[0], s)
|
||||||
|
if ok {
|
||||||
|
return validateString(rules, option[1], remainder)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(option) == 3 {
|
||||||
|
ok, remainder := validateString(rules, option[0], s)
|
||||||
|
if ok {
|
||||||
|
ok, remainder = validateString(rules, option[1], remainder)
|
||||||
|
}
|
||||||
|
if ok {
|
||||||
|
return validateString(rules, option[2], remainder)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// otherwise, we need to branch into our options and try and apply their rules
|
||||||
|
if len(activeRule.options) == 2 {
|
||||||
|
ok := false
|
||||||
|
remainder := ""
|
||||||
|
optionOne := activeRule.options[0]
|
||||||
|
if len(optionOne) == 1 {
|
||||||
|
ok, remainder = validateString(rules, optionOne[0], s)
|
||||||
|
}
|
||||||
|
if len(optionOne) == 2 {
|
||||||
|
ok, remainder = validateString(rules, optionOne[0], s)
|
||||||
|
if ok {
|
||||||
|
ok, remainder = validateString(rules, optionOne[1], remainder)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(optionOne) == 3 {
|
||||||
|
ok, remainder = validateString(rules, optionOne[0], s)
|
||||||
|
if ok {
|
||||||
|
ok, remainder = validateString(rules, optionOne[1], remainder)
|
||||||
|
}
|
||||||
|
if ok {
|
||||||
|
ok, remainder = validateString(rules, optionOne[2], remainder)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ok {
|
||||||
|
return ok, remainder
|
||||||
|
}
|
||||||
|
optionTwo := activeRule.options[1]
|
||||||
|
if len(optionTwo) == 1 {
|
||||||
|
ok, _ = validateString(rules, optionTwo[0], s)
|
||||||
|
}
|
||||||
|
if len(optionTwo) == 2 {
|
||||||
|
ok, remainder = validateString(rules, optionTwo[0], s)
|
||||||
|
if ok {
|
||||||
|
return validateString(rules, optionTwo[1], remainder)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(optionTwo) == 3 {
|
||||||
|
ok, remainder = validateString(rules, optionTwo[0], s)
|
||||||
|
if ok {
|
||||||
|
ok, remainder = validateString(rules, optionTwo[1], remainder)
|
||||||
|
}
|
||||||
|
if ok {
|
||||||
|
return validateString(rules, optionTwo[2], remainder)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false, s
|
||||||
|
}
|
||||||
|
|
||||||
|
func partOne() {
|
||||||
|
f, _ := os.Open("input")
|
||||||
|
reader := bufio.NewReader(f)
|
||||||
|
scanner := bufio.NewScanner(reader)
|
||||||
|
|
||||||
|
rules := make([]rule, 134)
|
||||||
|
for scanner.Scan() {
|
||||||
|
line := scanner.Text()
|
||||||
|
if line == "" {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
rule := parseRule(line)
|
||||||
|
rules[rule.name] = rule
|
||||||
|
}
|
||||||
|
|
||||||
|
total := 0
|
||||||
|
for scanner.Scan() {
|
||||||
|
line := scanner.Text()
|
||||||
|
if ok, _ := validateString(rules, 0, line); ok {
|
||||||
|
fmt.Println("VALID:", line)
|
||||||
|
total = total + 1
|
||||||
|
} else {
|
||||||
|
fmt.Println("INVALID:", line)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(total)
|
||||||
|
}
|
||||||
|
|
||||||
|
func partTwo() {
|
||||||
|
f, _ := os.Open("input")
|
||||||
|
reader := bufio.NewReader(f)
|
||||||
|
scanner := bufio.NewScanner(reader)
|
||||||
|
|
||||||
|
for scanner.Scan() {
|
||||||
|
// line := scanner.Text()
|
||||||
|
}
|
||||||
|
}
|
244
20/main.go
Normal file
244
20/main.go
Normal file
@@ -0,0 +1,244 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"math"
|
||||||
|
"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)
|
||||||
|
}
|
||||||
|
|
||||||
|
type tile struct {
|
||||||
|
id int
|
||||||
|
neighbors map[int]int // key matches the edge key, so we can skip existing matches if we want
|
||||||
|
edges map[int]string
|
||||||
|
image map[int]string
|
||||||
|
}
|
||||||
|
|
||||||
|
// edges are always defined clockwise starting from 0:north
|
||||||
|
// as long as there's only ever one match for an edge, I don't _think_ I need to keep track of piece orientation...?
|
||||||
|
func parseTile(header string, body []string) tile {
|
||||||
|
id, _ := strconv.Atoi(strings.Trim(header, "Tile :"))
|
||||||
|
t := tile{
|
||||||
|
id: id,
|
||||||
|
neighbors: make(map[int]int, 4),
|
||||||
|
edges: make(map[int]string, 4),
|
||||||
|
image: make(map[int]string, 8),
|
||||||
|
}
|
||||||
|
// make edges and extract picture data...
|
||||||
|
left := []byte{}
|
||||||
|
right := []byte{}
|
||||||
|
for i := range body {
|
||||||
|
left = append(left, body[i][0])
|
||||||
|
right = append(right, body[i][9])
|
||||||
|
// image has edges removed; still want 0-indexed for sanity later!
|
||||||
|
if i != 0 && i != 9 {
|
||||||
|
t.image[i-1] = body[i-1][1:9]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
t.edges[0] = body[0]
|
||||||
|
t.edges[1] = string(right)
|
||||||
|
t.edges[2] = body[9]
|
||||||
|
t.edges[3] = string(left)
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
|
||||||
|
// return is match, inverted
|
||||||
|
func testEdge(one, two string) (bool, bool) {
|
||||||
|
if one == two {
|
||||||
|
return true, false
|
||||||
|
}
|
||||||
|
// go doesn't have a built-in "string reversal" method, so we just check it the hard way
|
||||||
|
// 9 is our magic number for a 10-character string, which we know they all are.
|
||||||
|
// This might not be 100% sound for unicode (byte != rune), but our string is ASCII so it's... fine.
|
||||||
|
for i := range one {
|
||||||
|
if one[i] != two[9-i] {
|
||||||
|
return false, false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// this is wasteful in that it happily checks edges that we've already determined neighbors for,
|
||||||
|
// but it's performant enough that I don't really care to fix it
|
||||||
|
func findPartners(id int, tiles map[int]tile) map[int]tile {
|
||||||
|
currentTile := tiles[id]
|
||||||
|
for tile := range tiles {
|
||||||
|
if tile != id {
|
||||||
|
for edgeID := range tiles[tile].edges {
|
||||||
|
for i := range currentTile.edges {
|
||||||
|
if ok, _ := testEdge(tiles[tile].edges[edgeID], currentTile.edges[i]); ok {
|
||||||
|
tiles[tile].neighbors[edgeID] = tiles[id].id
|
||||||
|
tiles[id].neighbors[i] = tiles[tile].id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return tiles
|
||||||
|
}
|
||||||
|
|
||||||
|
// Starting from a corner, we can "walk" through the image by:
|
||||||
|
// stepping to the next tile in a known direction
|
||||||
|
// checking where _that_ tile thinks we came from
|
||||||
|
// then re-orienting ourselves and stepping again.
|
||||||
|
// For example, if we take a corner and go to its 0 neighbor,
|
||||||
|
// and that neighbor thinks our previous tile was 3,
|
||||||
|
// a "straight line" along the edge would be 1. Repeat as necessary until you hit an edge.
|
||||||
|
// Once we hit an edge, return to the start of the row,
|
||||||
|
// step to its 90° neighbor, then walk parallel to the initial edge.
|
||||||
|
// Repeat until we reach the far corner.
|
||||||
|
// Additionally, we need to "line up" the edges, so there's some alignment checking that has to happen.
|
||||||
|
func mergeTiles(corner int, tiles map[int]tile) []string {
|
||||||
|
// just to make the counting a little easier
|
||||||
|
sideLength := int(math.Sqrt(float64(len(tiles))))
|
||||||
|
result := make([]string, sideLength*8)
|
||||||
|
headOfRow := tiles[corner]
|
||||||
|
currentRowDirection := 0
|
||||||
|
nextRowDirection := 0
|
||||||
|
// what an absurd way to "pick" between two keys in a two-key map
|
||||||
|
for i := range headOfRow.neighbors {
|
||||||
|
if currentRowDirection == 0 {
|
||||||
|
currentRowDirection = i
|
||||||
|
} else if nextRowDirection == 0 {
|
||||||
|
nextRowDirection = i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
currentTile := tiles[corner]
|
||||||
|
image := imageFromEdge(currentTile, 0)
|
||||||
|
for row, s := range image {
|
||||||
|
result[row] = result[row] + s
|
||||||
|
}
|
||||||
|
for i := 0; i < sideLength; i = i + 1 {
|
||||||
|
nextID := currentTile.neighbors[currentRowDirection]
|
||||||
|
for e, id := range tiles[nextID].neighbors {
|
||||||
|
if id == currentTile.id {
|
||||||
|
_, invert := testEdge(currentTile.edges[currentRowDirection], tiles[nextID].edges[e])
|
||||||
|
image := imageFromEdge(tiles[nextID], (e+1)%4)
|
||||||
|
if !invert {
|
||||||
|
for row, s := range image {
|
||||||
|
result[row] = result[row] + s
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for row, s := range image {
|
||||||
|
result[7-row] = result[7-row] + s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
currentRowDirection = (e + 2) % 4 // flip 180 around the compass
|
||||||
|
}
|
||||||
|
}
|
||||||
|
currentTile = tiles[nextID]
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns the image "rotated" so that the provided edge is on "top" (the 0 position)
|
||||||
|
func imageFromEdge(t tile, edge int) map[int]string {
|
||||||
|
if edge == 1 {
|
||||||
|
newImage := make(map[int]string, 8)
|
||||||
|
for i := 0; i < 8; i = i + 1 {
|
||||||
|
b := []byte{t.image[0][7-i], t.image[1][7-i], t.image[2][7-i], t.image[3][7-i], t.image[4][7-i], t.image[5][7-i], t.image[6][7-i], t.image[7][7-i]}
|
||||||
|
newImage[i] = string(b)
|
||||||
|
}
|
||||||
|
return newImage
|
||||||
|
}
|
||||||
|
if edge == 2 {
|
||||||
|
newImage := make(map[int]string, 8)
|
||||||
|
for i := 0; i < 8; i = i + 1 {
|
||||||
|
b := []byte{t.image[7-i][7], t.image[7-i][6], t.image[7-i][5], t.image[7-i][4], t.image[7-i][3], t.image[7-i][2], t.image[7-i][1], t.image[7-i][0]}
|
||||||
|
newImage[i] = string(b)
|
||||||
|
}
|
||||||
|
return newImage
|
||||||
|
}
|
||||||
|
if edge == 3 {
|
||||||
|
newImage := make(map[int]string, 8)
|
||||||
|
for i := 0; i < 8; i = i + 1 {
|
||||||
|
b := []byte{t.image[7][i], t.image[6][i], t.image[5][i], t.image[4][i], t.image[3][i], t.image[2][i], t.image[1][i], t.image[0][i]}
|
||||||
|
newImage[i] = string(b)
|
||||||
|
}
|
||||||
|
return newImage
|
||||||
|
}
|
||||||
|
// edge == 0 does nothing
|
||||||
|
return t.image
|
||||||
|
}
|
||||||
|
|
||||||
|
func partOne() {
|
||||||
|
f, _ := os.Open("input")
|
||||||
|
reader := bufio.NewReader(f)
|
||||||
|
scanner := bufio.NewScanner(reader)
|
||||||
|
|
||||||
|
buffer := []string{}
|
||||||
|
tiles := make(map[int]tile)
|
||||||
|
|
||||||
|
for scanner.Scan() {
|
||||||
|
line := scanner.Text()
|
||||||
|
if line == "" {
|
||||||
|
tile := parseTile(buffer[0], buffer[1:])
|
||||||
|
tiles[tile.id] = tile
|
||||||
|
buffer = []string{}
|
||||||
|
} else {
|
||||||
|
buffer = append(buffer, line)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// catch that last tile
|
||||||
|
// weirdly, I'd think the trailing newline in the input would have done this for us
|
||||||
|
tile := parseTile(buffer[0], buffer[1:])
|
||||||
|
tiles[tile.id] = tile
|
||||||
|
|
||||||
|
corners := 1
|
||||||
|
for id := range tiles {
|
||||||
|
tiles = findPartners(id, tiles)
|
||||||
|
if len(tiles[id].neighbors) == 2 {
|
||||||
|
corners = corners * id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(corners)
|
||||||
|
}
|
||||||
|
|
||||||
|
func partTwo() {
|
||||||
|
f, _ := os.Open("testinput")
|
||||||
|
reader := bufio.NewReader(f)
|
||||||
|
scanner := bufio.NewScanner(reader)
|
||||||
|
|
||||||
|
buffer := []string{}
|
||||||
|
tiles := make(map[int]tile)
|
||||||
|
|
||||||
|
for scanner.Scan() {
|
||||||
|
line := scanner.Text()
|
||||||
|
if line == "" {
|
||||||
|
tile := parseTile(buffer[0], buffer[1:])
|
||||||
|
tiles[tile.id] = tile
|
||||||
|
buffer = []string{}
|
||||||
|
} else {
|
||||||
|
buffer = append(buffer, line)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// catch that last tile
|
||||||
|
tile := parseTile(buffer[0], buffer[1:])
|
||||||
|
tiles[tile.id] = tile
|
||||||
|
|
||||||
|
corner := 0
|
||||||
|
for id := range tiles {
|
||||||
|
tiles = findPartners(id, tiles)
|
||||||
|
// grab a corner to start the merge from
|
||||||
|
if len(tiles[id].neighbors) == 2 && corner == 0 {
|
||||||
|
corner = id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, line := range mergeTiles(corner, tiles) {
|
||||||
|
fmt.Println(line)
|
||||||
|
}
|
||||||
|
}
|
140
21/main.go
Normal file
140
21/main.go
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
type food struct {
|
||||||
|
allergens []string
|
||||||
|
ingredients []string
|
||||||
|
}
|
||||||
|
|
||||||
|
func intersection(a, b []string) []string {
|
||||||
|
// special-case starting out
|
||||||
|
if len(a) == 0 {
|
||||||
|
return b
|
||||||
|
} else if len(b) == 0 {
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
result := []string{}
|
||||||
|
for _, s := range b {
|
||||||
|
for _, t := range a {
|
||||||
|
if s == t {
|
||||||
|
result = append(result, s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func countSafeIngredients(f food, allergens map[string][]string) int {
|
||||||
|
for c, i := range f.ingredients {
|
||||||
|
for _, l := range allergens {
|
||||||
|
for _, a := range l {
|
||||||
|
if i == a {
|
||||||
|
f.ingredients[c] = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result := 0
|
||||||
|
for _, i := range f.ingredients {
|
||||||
|
if i != "" {
|
||||||
|
result = result + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func remove(ingredients []string, ingredient string) []string {
|
||||||
|
for i, j := range ingredients {
|
||||||
|
if j == ingredient {
|
||||||
|
ingredients[i] = ingredients[len(ingredients)-1]
|
||||||
|
ingredients[len(ingredients)-1] = ""
|
||||||
|
return ingredients[:len(ingredients)-1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ingredients
|
||||||
|
}
|
||||||
|
|
||||||
|
func partOne() {
|
||||||
|
f, _ := os.Open("input")
|
||||||
|
reader := bufio.NewReader(f)
|
||||||
|
scanner := bufio.NewScanner(reader)
|
||||||
|
|
||||||
|
foods := []food{}
|
||||||
|
allergens := map[string][]string{}
|
||||||
|
|
||||||
|
for scanner.Scan() {
|
||||||
|
line := strings.Split(scanner.Text(), " (contains ")
|
||||||
|
f := food{
|
||||||
|
ingredients: strings.Split(line[0], " "),
|
||||||
|
allergens: strings.Split(strings.TrimSuffix(line[1], ")"), ", "),
|
||||||
|
}
|
||||||
|
foods = append(foods, f)
|
||||||
|
for _, a := range f.allergens {
|
||||||
|
allergens[a] = intersection(f.ingredients, allergens[a])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sum := 0
|
||||||
|
for _, f := range foods {
|
||||||
|
sum = sum + countSafeIngredients(f, allergens)
|
||||||
|
}
|
||||||
|
fmt.Println(sum)
|
||||||
|
}
|
||||||
|
|
||||||
|
func partTwo() {
|
||||||
|
f, _ := os.Open("input")
|
||||||
|
reader := bufio.NewReader(f)
|
||||||
|
scanner := bufio.NewScanner(reader)
|
||||||
|
|
||||||
|
foods := []food{}
|
||||||
|
allergens := map[string][]string{}
|
||||||
|
|
||||||
|
for scanner.Scan() {
|
||||||
|
line := strings.Split(scanner.Text(), " (contains ")
|
||||||
|
f := food{
|
||||||
|
ingredients: strings.Split(line[0], " "),
|
||||||
|
allergens: strings.Split(strings.TrimSuffix(line[1], ")"), ", "),
|
||||||
|
}
|
||||||
|
foods = append(foods, f)
|
||||||
|
for _, a := range f.allergens {
|
||||||
|
allergens[a] = intersection(f.ingredients, allergens[a])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// hey, this is the same reduction logic as day 16!
|
||||||
|
trueAllergens := map[string]string{}
|
||||||
|
var lastAllergenSolved string
|
||||||
|
for i := 0; i < len(allergens); i = i + 1 {
|
||||||
|
for i, a := range allergens {
|
||||||
|
if len(a) == 1 {
|
||||||
|
trueAllergens[i] = a[0]
|
||||||
|
lastAllergenSolved = a[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for i := range allergens {
|
||||||
|
allergens[i] = remove(allergens[i], lastAllergenSolved)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
formatted := "" // in theory we shouldn't hard-code this allergen order...
|
||||||
|
for _, a := range []string{"dairy", "eggs", "fish", "nuts", "peanuts", "sesame", "soy", "wheat"} {
|
||||||
|
formatted = formatted + trueAllergens[a] + ","
|
||||||
|
}
|
||||||
|
fmt.Println(strings.TrimSuffix(formatted, ","))
|
||||||
|
}
|
155
22/main.go
Normal file
155
22/main.go
Normal file
@@ -0,0 +1,155 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"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)
|
||||||
|
}
|
||||||
|
|
||||||
|
type deck struct {
|
||||||
|
cards []int
|
||||||
|
}
|
||||||
|
|
||||||
|
type cacheKey struct {
|
||||||
|
one int
|
||||||
|
two int
|
||||||
|
}
|
||||||
|
|
||||||
|
func countWinningDeck(deck []int) int {
|
||||||
|
sum := 0
|
||||||
|
for i := range deck {
|
||||||
|
sum = sum + ((len(deck) - i) * deck[i])
|
||||||
|
}
|
||||||
|
return sum
|
||||||
|
}
|
||||||
|
|
||||||
|
// return values is who won/their score: true for player one, false for player two
|
||||||
|
func playCombat(one, two []int) (bool, int) {
|
||||||
|
round := 0
|
||||||
|
for len(one) > 0 && len(two) > 0 {
|
||||||
|
round = round + 1
|
||||||
|
if one[0] > two[0] {
|
||||||
|
one = append(one[1:], one[0], two[0])
|
||||||
|
two = two[1:]
|
||||||
|
} else if one[0] < two[0] {
|
||||||
|
two = append(two[1:], two[0], one[0])
|
||||||
|
one = one[1:]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(one) == 0 {
|
||||||
|
return false, countWinningDeck(two)
|
||||||
|
}
|
||||||
|
return true, countWinningDeck(one)
|
||||||
|
}
|
||||||
|
|
||||||
|
func playRecursiveCombat(one, two []int) (bool, int) {
|
||||||
|
loopCache := make(map[cacheKey]bool, 0)
|
||||||
|
round := 0
|
||||||
|
for len(one) > 0 && len(two) > 0 {
|
||||||
|
// check for loops
|
||||||
|
if loopCache[cacheKey{one: countWinningDeck(one), two: countWinningDeck(two)}] {
|
||||||
|
return true, countWinningDeck(one)
|
||||||
|
}
|
||||||
|
loopCache[cacheKey{one: countWinningDeck(one), two: countWinningDeck(two)}] = true
|
||||||
|
|
||||||
|
// otherwise, play a round
|
||||||
|
round = round + 1
|
||||||
|
if len(one[1:]) >= one[0] && len(two[1:]) >= two[0] {
|
||||||
|
// fuckin' go slice internals
|
||||||
|
subDeckOne := make([]int, len(one))
|
||||||
|
subDeckTwo := make([]int, len(two))
|
||||||
|
copy(subDeckOne, one)
|
||||||
|
copy(subDeckTwo, two)
|
||||||
|
winner, _ := playRecursiveCombat(subDeckOne[1:one[0]+1], subDeckTwo[1:two[0]+1])
|
||||||
|
if winner { // p1 wins
|
||||||
|
one = append(one[1:], one[0], two[0])
|
||||||
|
two = two[1:]
|
||||||
|
} else { // p2 wins
|
||||||
|
two = append(two[1:], two[0], one[0])
|
||||||
|
one = one[1:]
|
||||||
|
}
|
||||||
|
} else if one[0] > two[0] {
|
||||||
|
one = append(one[1:], one[0], two[0])
|
||||||
|
two = two[1:]
|
||||||
|
} else if one[0] < two[0] {
|
||||||
|
two = append(two[1:], two[0], one[0])
|
||||||
|
one = one[1:]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(one) == 0 {
|
||||||
|
return false, countWinningDeck(two)
|
||||||
|
}
|
||||||
|
return true, countWinningDeck(one)
|
||||||
|
}
|
||||||
|
|
||||||
|
func partOne() {
|
||||||
|
f, _ := os.Open("input")
|
||||||
|
reader := bufio.NewReader(f)
|
||||||
|
scanner := bufio.NewScanner(reader)
|
||||||
|
|
||||||
|
// deal the decks
|
||||||
|
playerone := deck{}
|
||||||
|
for scanner.Scan() {
|
||||||
|
line := scanner.Text()
|
||||||
|
if line == "" {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
i, err := strconv.Atoi(line)
|
||||||
|
if err == nil {
|
||||||
|
playerone.cards = append(playerone.cards, i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
playertwo := deck{}
|
||||||
|
for scanner.Scan() {
|
||||||
|
line := scanner.Text()
|
||||||
|
i, err := strconv.Atoi(line)
|
||||||
|
if err == nil {
|
||||||
|
playertwo.cards = append(playertwo.cards, i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// play a game and determine a winner
|
||||||
|
_, score := playCombat(playerone.cards, playertwo.cards)
|
||||||
|
fmt.Println(score)
|
||||||
|
}
|
||||||
|
|
||||||
|
func partTwo() {
|
||||||
|
f, _ := os.Open("input")
|
||||||
|
reader := bufio.NewReader(f)
|
||||||
|
scanner := bufio.NewScanner(reader)
|
||||||
|
|
||||||
|
// deal the decks
|
||||||
|
playerone := deck{}
|
||||||
|
for scanner.Scan() {
|
||||||
|
line := scanner.Text()
|
||||||
|
if line == "" {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
i, err := strconv.Atoi(line)
|
||||||
|
if err == nil {
|
||||||
|
playerone.cards = append(playerone.cards, i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
playertwo := deck{}
|
||||||
|
for scanner.Scan() {
|
||||||
|
line := scanner.Text()
|
||||||
|
i, err := strconv.Atoi(line)
|
||||||
|
if err == nil {
|
||||||
|
playertwo.cards = append(playertwo.cards, i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_, score := playRecursiveCombat(playerone.cards, playertwo.cards)
|
||||||
|
fmt.Println(score)
|
||||||
|
}
|
137
23/main.go
Normal file
137
23/main.go
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
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 cupInList(cup int, cups []int) bool {
|
||||||
|
for _, c := range cups {
|
||||||
|
if c == cup {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateFullCupset(cups []int, totalCups int) []int {
|
||||||
|
for i := len(cups); i < totalCups; i = i + 1 {
|
||||||
|
cups = append(cups, i)
|
||||||
|
}
|
||||||
|
return cups
|
||||||
|
}
|
||||||
|
|
||||||
|
func findTargetCupIndex(cup int, cups []int) int {
|
||||||
|
for i, c := range cups {
|
||||||
|
if c == cup {
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0 // uh-oh
|
||||||
|
}
|
||||||
|
|
||||||
|
func step(cups []int) []int {
|
||||||
|
cupCount := len(cups)
|
||||||
|
currentCup := cups[0]
|
||||||
|
removedCups := cups[1:4]
|
||||||
|
newList := make([]int, 0, cupCount)
|
||||||
|
newList = append([]int{cups[0]}, cups[4:]...)
|
||||||
|
var targetCup int
|
||||||
|
if currentCup == 1 {
|
||||||
|
targetCup = cupCount
|
||||||
|
} else {
|
||||||
|
targetCup = currentCup - 1
|
||||||
|
}
|
||||||
|
for cupInList(targetCup, removedCups) {
|
||||||
|
targetCup = targetCup - 1
|
||||||
|
if targetCup == 0 {
|
||||||
|
targetCup = cupCount
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tc := findTargetCupIndex(targetCup, newList)
|
||||||
|
result := make([]int, 0, cupCount)
|
||||||
|
result = append(result, newList[1:tc+1]...)
|
||||||
|
result = append(result, removedCups...)
|
||||||
|
result = append(result, newList[tc+1:]...)
|
||||||
|
result = append(result, newList[0])
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func runabout(cups []int) string {
|
||||||
|
oneIndex := findTargetCupIndex(1, cups)
|
||||||
|
result := ""
|
||||||
|
for i := oneIndex + 1; i < len(cups); i = i + 1 {
|
||||||
|
result = result + strconv.Itoa(cups[i])
|
||||||
|
}
|
||||||
|
for i := 0; i < len(cups[:oneIndex]); i = i + 1 {
|
||||||
|
result = result + strconv.Itoa(cups[i])
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func nextTwo(cups []int) (int, int) {
|
||||||
|
oneIndex := findTargetCupIndex(1, cups)
|
||||||
|
if oneIndex+1 > len(cups) {
|
||||||
|
return cups[0], cups[1]
|
||||||
|
}
|
||||||
|
if oneIndex+2 > len(cups) {
|
||||||
|
return cups[len(cups)], cups[0]
|
||||||
|
}
|
||||||
|
return cups[oneIndex+1], cups[oneIndex+2]
|
||||||
|
}
|
||||||
|
|
||||||
|
func partOne() {
|
||||||
|
f, _ := os.Open("testinput")
|
||||||
|
reader := bufio.NewReader(f)
|
||||||
|
scanner := bufio.NewScanner(reader)
|
||||||
|
|
||||||
|
cups := []int{}
|
||||||
|
|
||||||
|
scanner.Scan()
|
||||||
|
for _, s := range strings.Split(scanner.Text(), "") {
|
||||||
|
i, _ := strconv.Atoi(s)
|
||||||
|
cups = append(cups, i)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < 100; i = i + 1 {
|
||||||
|
cups = step(cups)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(runabout(cups))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func partTwo() {
|
||||||
|
f, _ := os.Open("testinput")
|
||||||
|
reader := bufio.NewReader(f)
|
||||||
|
scanner := bufio.NewScanner(reader)
|
||||||
|
|
||||||
|
cups := []int{}
|
||||||
|
|
||||||
|
scanner.Scan()
|
||||||
|
for _, s := range strings.Split(scanner.Text(), "") {
|
||||||
|
i, _ := strconv.Atoi(s)
|
||||||
|
cups = append(cups, i)
|
||||||
|
}
|
||||||
|
|
||||||
|
allCups := generateFullCupset(cups, 10000000)
|
||||||
|
for i := 0; i < 10000000; i = i + 1 {
|
||||||
|
allCups = step(allCups)
|
||||||
|
fmt.Println(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(nextTwo(allCups))
|
||||||
|
}
|
186
24/main.go
Normal file
186
24/main.go
Normal file
@@ -0,0 +1,186 @@
|
|||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Our grid is a hex, so let's represent that as follows:
|
||||||
|
// x runs east-west, y runs north-south. Yes, these coordinates here are backward.
|
||||||
|
// 2,-2 2,0 2,2 2,4
|
||||||
|
// 1,-2 1,-1 1,1 1,2
|
||||||
|
// 0,-2 0,0 0,2 0,4
|
||||||
|
// -1,-2 -1,-1 -1,1 -1,2
|
||||||
|
// -2,-2 -2,0 -2,2 -2,4
|
||||||
|
// 0,0 -> e -> 0, 2
|
||||||
|
// -> w -> 0,-2
|
||||||
|
// -> se -> -1, 1
|
||||||
|
// -> sw -> -1,-1
|
||||||
|
// -> ne -> 1, 1
|
||||||
|
// -> nw -> 1,-1
|
||||||
|
|
||||||
|
// 0 == white, 1 == black
|
||||||
|
type tiles map[coord]int
|
||||||
|
|
||||||
|
type coord struct {
|
||||||
|
x int
|
||||||
|
y int
|
||||||
|
}
|
||||||
|
|
||||||
|
func walkGrid(directions []string) (int, int) {
|
||||||
|
var y, x int
|
||||||
|
for _, d := range directions {
|
||||||
|
switch d {
|
||||||
|
case "e":
|
||||||
|
x = x + 2
|
||||||
|
case "se":
|
||||||
|
y = y - 1
|
||||||
|
x = x + 1
|
||||||
|
case "sw":
|
||||||
|
y = y - 1
|
||||||
|
x = x - 1
|
||||||
|
case "w":
|
||||||
|
x = x - 2
|
||||||
|
case "ne":
|
||||||
|
y = y + 1
|
||||||
|
x = x + 1
|
||||||
|
case "nw":
|
||||||
|
y = y + 1
|
||||||
|
x = x - 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return y, x
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseLine(s string) []string {
|
||||||
|
directions := []string{}
|
||||||
|
for i := 0; i < len(s); {
|
||||||
|
switch s[i] {
|
||||||
|
case 'e':
|
||||||
|
directions = append(directions, "e")
|
||||||
|
i = i + 1
|
||||||
|
case 's':
|
||||||
|
if s[i+1] == 'e' {
|
||||||
|
directions = append(directions, "se")
|
||||||
|
i = i + 2
|
||||||
|
} else if s[i+1] == 'w' {
|
||||||
|
directions = append(directions, "sw")
|
||||||
|
i = i + 2
|
||||||
|
}
|
||||||
|
case 'w':
|
||||||
|
directions = append(directions, "w")
|
||||||
|
i = i + 1
|
||||||
|
case 'n':
|
||||||
|
if s[i+1] == 'e' {
|
||||||
|
directions = append(directions, "ne")
|
||||||
|
i = i + 2
|
||||||
|
} else if s[i+1] == 'w' {
|
||||||
|
directions = append(directions, "nw")
|
||||||
|
i = i + 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return directions
|
||||||
|
}
|
||||||
|
|
||||||
|
func generation(t tiles) tiles {
|
||||||
|
newTiles := tiles{}
|
||||||
|
seenWhiteTiles := tiles{}
|
||||||
|
for coord, tile := range t {
|
||||||
|
// walk black tile list
|
||||||
|
if tile == 1 {
|
||||||
|
neighbors := getNeighbors(coord)
|
||||||
|
bn := 0
|
||||||
|
for _, n := range neighbors {
|
||||||
|
if t[n] == 0 {
|
||||||
|
seenWhiteTiles[n] = seenWhiteTiles[n] + 1
|
||||||
|
} else {
|
||||||
|
bn = bn + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// black tiles only survive if they have one or two black neighbors
|
||||||
|
if bn == 1 || bn == 2 {
|
||||||
|
newTiles[coord] = 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// white tiles turn black if they have two black neighbors
|
||||||
|
for c, n := range seenWhiteTiles {
|
||||||
|
if n == 2 {
|
||||||
|
newTiles[c] = 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return newTiles
|
||||||
|
}
|
||||||
|
|
||||||
|
func getNeighbors(c coord) []coord {
|
||||||
|
return []coord{
|
||||||
|
{x: c.x + 2, y: c.y}, // e
|
||||||
|
{x: c.x - 2, y: c.y}, // w
|
||||||
|
{x: c.x + 1, y: c.y + 1}, // ne
|
||||||
|
{x: c.x + 1, y: c.y - 1}, // nw
|
||||||
|
{x: c.x - 1, y: c.y + 1}, // se
|
||||||
|
{x: c.x - 1, y: c.y - 1}, // sw
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func countBlackTiles(t tiles) int {
|
||||||
|
sum := 0
|
||||||
|
for _, tile := range t {
|
||||||
|
sum = sum + tile
|
||||||
|
}
|
||||||
|
return sum
|
||||||
|
}
|
||||||
|
|
||||||
|
func partOne() {
|
||||||
|
f, _ := os.Open("testinput")
|
||||||
|
reader := bufio.NewReader(f)
|
||||||
|
scanner := bufio.NewScanner(reader)
|
||||||
|
|
||||||
|
t := tiles{}
|
||||||
|
|
||||||
|
for scanner.Scan() {
|
||||||
|
line := scanner.Text()
|
||||||
|
x, y := walkGrid(parseLine(line))
|
||||||
|
if t[coord{x: x, y: y}] == 0 {
|
||||||
|
t[coord{x: x, y: y}] = 1
|
||||||
|
} else {
|
||||||
|
t[coord{x: x, y: y}] = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt.Println(countBlackTiles(t))
|
||||||
|
}
|
||||||
|
|
||||||
|
func partTwo() {
|
||||||
|
f, _ := os.Open("input")
|
||||||
|
reader := bufio.NewReader(f)
|
||||||
|
scanner := bufio.NewScanner(reader)
|
||||||
|
|
||||||
|
t := tiles{}
|
||||||
|
|
||||||
|
for scanner.Scan() {
|
||||||
|
line := scanner.Text()
|
||||||
|
y, x := walkGrid(parseLine(line))
|
||||||
|
if t[coord{x: x, y: y}] == 0 {
|
||||||
|
t[coord{x: x, y: y}] = 1
|
||||||
|
} else {
|
||||||
|
t[coord{x: x, y: y}] = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for day := 1; day <= 100; day = day + 1 {
|
||||||
|
t = generation(t)
|
||||||
|
}
|
||||||
|
fmt.Println(countBlackTiles(t))
|
||||||
|
|
||||||
|
}
|
54
25/main.go
Normal file
54
25/main.go
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
start := time.Now()
|
||||||
|
partOne()
|
||||||
|
duration := time.Since(start)
|
||||||
|
fmt.Printf("p1: %s, p2: n/a\n", duration)
|
||||||
|
}
|
||||||
|
|
||||||
|
func partOne() {
|
||||||
|
f, _ := os.Open("input")
|
||||||
|
reader := bufio.NewReader(f)
|
||||||
|
scanner := bufio.NewScanner(reader)
|
||||||
|
|
||||||
|
scanner.Scan()
|
||||||
|
doorPubKey, _ := strconv.Atoi(scanner.Text())
|
||||||
|
scanner.Scan()
|
||||||
|
cardPubKey, _ := strconv.Atoi(scanner.Text())
|
||||||
|
|
||||||
|
subjectNumber := 7
|
||||||
|
value := 1
|
||||||
|
magicPrime := 20201227
|
||||||
|
loopCount := 1
|
||||||
|
doorLoopCount := 0
|
||||||
|
cardLoopCount := 0
|
||||||
|
for {
|
||||||
|
value = (value * subjectNumber) % magicPrime
|
||||||
|
if value == doorPubKey {
|
||||||
|
doorLoopCount = loopCount
|
||||||
|
}
|
||||||
|
if value == cardPubKey {
|
||||||
|
cardLoopCount = loopCount
|
||||||
|
}
|
||||||
|
loopCount = loopCount + 1
|
||||||
|
if doorLoopCount != 0 && cardLoopCount != 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
value = 1
|
||||||
|
subjectNumber = cardPubKey
|
||||||
|
for i := 0; i < doorLoopCount; i = i + 1 {
|
||||||
|
value = (value * subjectNumber) % magicPrime
|
||||||
|
}
|
||||||
|
fmt.Println(value)
|
||||||
|
}
|
37
main.go.tmpl
Normal file
37
main.go.tmpl
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
func partOne() {
|
||||||
|
f, _ := os.Open("input")
|
||||||
|
reader := bufio.NewReader(f)
|
||||||
|
scanner := bufio.NewScanner(reader)
|
||||||
|
|
||||||
|
for scanner.Scan() {
|
||||||
|
// line := scanner.Text()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func partTwo() {
|
||||||
|
f, _ := os.Open("input")
|
||||||
|
reader := bufio.NewReader(f)
|
||||||
|
scanner := bufio.NewScanner(reader)
|
||||||
|
|
||||||
|
for scanner.Scan() {
|
||||||
|
// line := scanner.Text()
|
||||||
|
}
|
||||||
|
}
|
7
new.sh
Executable file
7
new.sh
Executable file
@@ -0,0 +1,7 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
if [ "${1}" != "" ]; then
|
||||||
|
mkdir -p ${1}
|
||||||
|
touch ${1}/{input,testinput}
|
||||||
|
cp -n main.go.tmpl ${1}/main.go
|
||||||
|
fi
|
Reference in New Issue
Block a user