Compare commits
14 Commits
44c8a7659d
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| bec29a111c | |||
| b2ff2ac24c | |||
| 4a9afc8de6 | |||
| 711badad96 | |||
| 7c8ee5edcd | |||
| e13255ab2f | |||
| cc7256461e | |||
| 917be0d8f1 | |||
| 3340be88a1 | |||
| d1c2f5eb90 | |||
| 374dd4a9b7 | |||
| 41c58fa100 | |||
| 6ffa3b6dd4 | |||
| 562fc231a4 |
139
16/main.go
139
16/main.go
@@ -46,30 +46,30 @@ func makeScanner(test bool) *bufio.Scanner {
|
|||||||
return bufio.NewScanner(reader)
|
return bufio.NewScanner(reader)
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseNumber(stream []uint8, length int) int64 {
|
func parseNumber(stream []uint8, length int) int {
|
||||||
result := int64(0)
|
result := int(0)
|
||||||
for i := 0; i < length; i++ {
|
for i := 0; i < length; i++ {
|
||||||
result += int64(stream[i]) << (length - 1 - i)
|
result += int(stream[i]) << (length - 1 - i)
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
type packet struct {
|
type packet struct {
|
||||||
version int64
|
version int
|
||||||
typeID int64
|
typeID int
|
||||||
subPackets []packet
|
subPackets []packet
|
||||||
encodedNumber int64
|
encodedNumber int
|
||||||
}
|
}
|
||||||
|
|
||||||
func getPacketVersion(stream []uint8) int64 {
|
func getPacketVersion(stream []uint8) int {
|
||||||
return parseNumber(stream, 3)
|
return parseNumber(stream, 3)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getPacketType(stream []uint8) int64 {
|
func getPacketType(stream []uint8) int {
|
||||||
return parseNumber(stream, 3)
|
return parseNumber(stream, 3)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getSubpacketLength(t uint8, stream []uint8) (int, int64) {
|
func getSubpacketLength(t uint8, stream []uint8) (int, int) {
|
||||||
if t == 0 {
|
if t == 0 {
|
||||||
return 15, parseNumber(stream, 15)
|
return 15, parseNumber(stream, 15)
|
||||||
}
|
}
|
||||||
@@ -79,7 +79,7 @@ func getSubpacketLength(t uint8, stream []uint8) (int, int64) {
|
|||||||
return 0, 0
|
return 0, 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func parsePayload(stream []uint8) (int64, int) {
|
func parsePayload(stream []uint8) (int, int) {
|
||||||
num := []uint8{}
|
num := []uint8{}
|
||||||
pos := 0
|
pos := 0
|
||||||
chars := 0
|
chars := 0
|
||||||
@@ -95,9 +95,9 @@ func parsePayload(stream []uint8) (int64, int) {
|
|||||||
return parseNumber(num, chars), pos
|
return parseNumber(num, chars), pos
|
||||||
}
|
}
|
||||||
|
|
||||||
func parsePackets(stream []uint8) (int, []packet) {
|
func parsePackets(stream []uint8) (int, packet) {
|
||||||
if len(stream) <= 7 {
|
if len(stream) <= 7 {
|
||||||
return 0, []packet{}
|
return 0, packet{}
|
||||||
}
|
}
|
||||||
parsedPacket := packet{}
|
parsedPacket := packet{}
|
||||||
parsedPacket.version = getPacketVersion(stream[0:3])
|
parsedPacket.version = getPacketVersion(stream[0:3])
|
||||||
@@ -105,29 +105,31 @@ func parsePackets(stream []uint8) (int, []packet) {
|
|||||||
if parsedPacket.typeID == 4 {
|
if parsedPacket.typeID == 4 {
|
||||||
encoded, consumed := parsePayload(stream[6:])
|
encoded, consumed := parsePayload(stream[6:])
|
||||||
parsedPacket.encodedNumber = encoded
|
parsedPacket.encodedNumber = encoded
|
||||||
return consumed + 6, []packet{parsedPacket} // 6 is packet header length
|
return consumed + 6, parsedPacket // 6 is packet header length
|
||||||
} else {
|
} else {
|
||||||
parsed := 0
|
parsed := 0
|
||||||
size, subpacketlength := getSubpacketLength(stream[6], stream[7:])
|
size, subpacketlength := getSubpacketLength(stream[6], stream[7:])
|
||||||
for {
|
for {
|
||||||
consumed, subs := parsePackets(stream[7+size+parsed:])
|
consumed, subs := parsePackets(stream[7+size+parsed:])
|
||||||
parsedPacket.subPackets = append(parsedPacket.subPackets, subs...)
|
if consumed == 0 {
|
||||||
|
return parsed + 7 + size, parsedPacket
|
||||||
|
}
|
||||||
|
parsedPacket.subPackets = append(parsedPacket.subPackets, subs)
|
||||||
parsed += consumed
|
parsed += consumed
|
||||||
if size == 11 && int64(len(parsedPacket.subPackets)) == subpacketlength {
|
if size == 11 && len(parsedPacket.subPackets) == subpacketlength {
|
||||||
return parsed + 7 + size, []packet{parsedPacket}
|
return parsed + 7 + size, parsedPacket
|
||||||
|
|
||||||
} else if size == 15 && int64(parsed) > subpacketlength || consumed == 0 {
|
} else if size == 15 && parsed > subpacketlength {
|
||||||
return parsed + 7 + size, []packet{parsedPacket}
|
return parsed + 7 + size, parsedPacket
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func countVersions(packets []packet) int {
|
func countVersions(pac packet) int {
|
||||||
i := 0
|
i := int(pac.version)
|
||||||
for _, p := range packets {
|
for _, p := range pac.subPackets {
|
||||||
i += int(p.version)
|
i += countVersions(p)
|
||||||
i += countVersions(p.subPackets)
|
|
||||||
}
|
}
|
||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
@@ -145,10 +147,97 @@ func partOne() {
|
|||||||
fmt.Println(countVersions(parsedPacket))
|
fmt.Println(countVersions(parsedPacket))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func solve(p packet) int {
|
||||||
|
switch p.typeID {
|
||||||
|
case 0: // sum
|
||||||
|
if len(p.subPackets) == 1 {
|
||||||
|
return solve(p.subPackets[0])
|
||||||
|
} else {
|
||||||
|
acc := 0
|
||||||
|
for _, v := range p.subPackets {
|
||||||
|
acc += solve(v)
|
||||||
|
}
|
||||||
|
return acc
|
||||||
|
}
|
||||||
|
case 1: // product
|
||||||
|
if len(p.subPackets) == 1 {
|
||||||
|
return solve(p.subPackets[0])
|
||||||
|
} else {
|
||||||
|
acc := solve(p.subPackets[0])
|
||||||
|
for _, v := range p.subPackets[1:] {
|
||||||
|
acc *= solve(v)
|
||||||
|
}
|
||||||
|
return acc
|
||||||
|
}
|
||||||
|
case 2: // min
|
||||||
|
if len(p.subPackets) == 1 {
|
||||||
|
return solve(p.subPackets[0])
|
||||||
|
} else {
|
||||||
|
acc := solve(p.subPackets[0])
|
||||||
|
for _, v := range p.subPackets[1:] {
|
||||||
|
t := solve(v)
|
||||||
|
if t < acc {
|
||||||
|
acc = t
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return acc
|
||||||
|
}
|
||||||
|
case 3: // max
|
||||||
|
if len(p.subPackets) == 1 {
|
||||||
|
return solve(p.subPackets[0])
|
||||||
|
} else {
|
||||||
|
acc := solve(p.subPackets[0])
|
||||||
|
for _, v := range p.subPackets[1:] {
|
||||||
|
t := solve(v)
|
||||||
|
if t > acc {
|
||||||
|
acc = t
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return acc
|
||||||
|
}
|
||||||
|
case 4: // number
|
||||||
|
return p.encodedNumber
|
||||||
|
case 5: // >
|
||||||
|
if len(p.subPackets) != 2 {
|
||||||
|
panic(fmt.Sprintf("recevied type 5 packet with %d subpackets", len(p.subPackets)))
|
||||||
|
}
|
||||||
|
if solve(p.subPackets[0]) > solve(p.subPackets[1]) {
|
||||||
|
return 1
|
||||||
|
} else {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
case 6: // <
|
||||||
|
if len(p.subPackets) != 2 {
|
||||||
|
panic(fmt.Sprintf("recevied type 6 packet with %d subpackets", len(p.subPackets)))
|
||||||
|
}
|
||||||
|
if solve(p.subPackets[0]) < solve(p.subPackets[1]) {
|
||||||
|
return 1
|
||||||
|
} else {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
case 7: // ==
|
||||||
|
if len(p.subPackets) != 2 {
|
||||||
|
panic(fmt.Sprintf("recevied type 7 packet with %d subpackets", len(p.subPackets)))
|
||||||
|
}
|
||||||
|
if solve(p.subPackets[0]) == solve(p.subPackets[1]) {
|
||||||
|
return 1
|
||||||
|
} else {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
panic("unknown packet type")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func partTwo() {
|
func partTwo() {
|
||||||
scanner := makeScanner(false)
|
scanner := makeScanner(false)
|
||||||
|
|
||||||
for scanner.Scan() {
|
scanner.Scan()
|
||||||
// line := scanner.Text()
|
line := scanner.Text()
|
||||||
|
stream := []uint8{}
|
||||||
|
for _, hex := range line {
|
||||||
|
stream = append(stream, hexMap[hex]...)
|
||||||
}
|
}
|
||||||
|
_, parsedPacket := parsePackets(stream)
|
||||||
|
fmt.Println(solve(parsedPacket))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestVersionParse(t *testing.T) {
|
func TestVersionParse(t *testing.T) {
|
||||||
tests := map[int64][]uint8{
|
tests := map[int][]uint8{
|
||||||
0: {0, 0, 0},
|
0: {0, 0, 0},
|
||||||
1: {0, 0, 1},
|
1: {0, 0, 1},
|
||||||
2: {0, 1, 0},
|
2: {0, 1, 0},
|
||||||
@@ -59,3 +59,28 @@ func TestCases(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSolving(t *testing.T) {
|
||||||
|
inputs := map[string]int{
|
||||||
|
"C200B40A82": 3,
|
||||||
|
"04005AC33890": 54,
|
||||||
|
"880086C3E88112": 7,
|
||||||
|
"CE00C43D881120": 9,
|
||||||
|
"D8005AC2A8F0": 1,
|
||||||
|
"F600BC2D8F": 0,
|
||||||
|
"9C005AC2F8F0": 0,
|
||||||
|
"9C0141080250320F1802104A08": 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
for c, r := range inputs {
|
||||||
|
stream := []uint8{}
|
||||||
|
for _, hex := range c {
|
||||||
|
stream = append(stream, hexMap[hex]...)
|
||||||
|
}
|
||||||
|
_, parsedPacket := parsePackets(stream)
|
||||||
|
if r != solve(parsedPacket) {
|
||||||
|
t.Log(c, solve(parsedPacket))
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
159
17/main.go
Normal file
159
17/main.go
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func mustAtoi(line string) int {
|
||||||
|
i, _ := strconv.Atoi(line)
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
start := time.Now()
|
||||||
|
partOne()
|
||||||
|
duration := time.Since(start)
|
||||||
|
partTwo()
|
||||||
|
duration2 := time.Since(start)
|
||||||
|
fmt.Printf("p1: %s, p2: %s\n", duration, duration2-duration)
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeScanner(test bool) *bufio.Scanner {
|
||||||
|
var f *os.File
|
||||||
|
if test {
|
||||||
|
f, _ = os.Open("inputs/testinput")
|
||||||
|
} else {
|
||||||
|
f, _ = os.Open("inputs/input")
|
||||||
|
}
|
||||||
|
reader := bufio.NewReader(f)
|
||||||
|
return bufio.NewScanner(reader)
|
||||||
|
}
|
||||||
|
|
||||||
|
type targetArea struct {
|
||||||
|
startx int
|
||||||
|
endx int
|
||||||
|
starty int
|
||||||
|
endy int
|
||||||
|
}
|
||||||
|
|
||||||
|
func ParseInput(line string) targetArea {
|
||||||
|
target := targetArea{}
|
||||||
|
acc := ""
|
||||||
|
for i := 0; i < len(line); i++ {
|
||||||
|
switch line[i] {
|
||||||
|
case '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-':
|
||||||
|
acc += string(line[i])
|
||||||
|
case '.':
|
||||||
|
i++ // skip the second .
|
||||||
|
if target.startx == 0 {
|
||||||
|
target.startx = mustAtoi(acc)
|
||||||
|
} else {
|
||||||
|
target.starty = mustAtoi(acc)
|
||||||
|
}
|
||||||
|
acc = ""
|
||||||
|
case ',':
|
||||||
|
target.endx = mustAtoi(acc)
|
||||||
|
acc = ""
|
||||||
|
default: // all other characters do nothing
|
||||||
|
}
|
||||||
|
target.endy = mustAtoi(acc)
|
||||||
|
}
|
||||||
|
return target
|
||||||
|
}
|
||||||
|
|
||||||
|
func InTarget(x, y int, target targetArea) bool {
|
||||||
|
return x >= target.startx && x <= target.endx && y <= target.endy && y >= target.starty
|
||||||
|
}
|
||||||
|
|
||||||
|
func BeyondTarget(x, y int, target targetArea) bool {
|
||||||
|
return x > target.endx || y < target.starty
|
||||||
|
}
|
||||||
|
|
||||||
|
type probe struct {
|
||||||
|
xvelocity int
|
||||||
|
yvelocity int
|
||||||
|
x int
|
||||||
|
y int
|
||||||
|
maxy int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *probe) Step() {
|
||||||
|
p.x += p.xvelocity
|
||||||
|
p.y += p.yvelocity
|
||||||
|
if p.xvelocity > 0 {
|
||||||
|
p.xvelocity--
|
||||||
|
} else if p.xvelocity < 0 {
|
||||||
|
p.xvelocity++
|
||||||
|
}
|
||||||
|
p.yvelocity--
|
||||||
|
if p.y > p.maxy {
|
||||||
|
p.maxy = p.y
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func partOne() {
|
||||||
|
scanner := makeScanner(false)
|
||||||
|
|
||||||
|
// read line
|
||||||
|
scanner.Scan()
|
||||||
|
line := scanner.Text()
|
||||||
|
target := ParseInput(line)
|
||||||
|
highestArc := 0
|
||||||
|
for j := 1; j < 50; j++ {
|
||||||
|
for k := 1; k < 100; k++ {
|
||||||
|
initx := j
|
||||||
|
inity := k
|
||||||
|
p := &probe{
|
||||||
|
xvelocity: initx,
|
||||||
|
yvelocity: inity,
|
||||||
|
}
|
||||||
|
for {
|
||||||
|
p.Step()
|
||||||
|
if InTarget(p.x, p.y, target) {
|
||||||
|
if p.maxy > highestArc {
|
||||||
|
highestArc = p.maxy
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if BeyondTarget(p.x, p.y, target) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt.Println(highestArc)
|
||||||
|
}
|
||||||
|
|
||||||
|
func partTwo() {
|
||||||
|
scanner := makeScanner(false)
|
||||||
|
|
||||||
|
// read line
|
||||||
|
scanner.Scan()
|
||||||
|
line := scanner.Text()
|
||||||
|
target := ParseInput(line)
|
||||||
|
hits := 0
|
||||||
|
for j := 0; j < 1000; j++ {
|
||||||
|
for k := -200; k < 1000; k++ {
|
||||||
|
initx := j
|
||||||
|
inity := k
|
||||||
|
p := &probe{
|
||||||
|
xvelocity: initx,
|
||||||
|
yvelocity: inity,
|
||||||
|
}
|
||||||
|
for {
|
||||||
|
p.Step()
|
||||||
|
if InTarget(p.x, p.y, target) {
|
||||||
|
hits++
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if BeyondTarget(p.x, p.y, target) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt.Println(hits)
|
||||||
|
}
|
||||||
15
17/main_test.go
Normal file
15
17/main_test.go
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestInTarget(t *testing.T) {
|
||||||
|
target := targetArea{
|
||||||
|
startx: 20,
|
||||||
|
endx: 30,
|
||||||
|
starty: -10,
|
||||||
|
endy: -5,
|
||||||
|
}
|
||||||
|
if !InTarget(28, -7, target) {
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
}
|
||||||
225
18/main.go
Normal file
225
18/main.go
Normal file
@@ -0,0 +1,225 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func mustAtoi(line rune) int {
|
||||||
|
i, _ := strconv.Atoi(string(line))
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
start := time.Now()
|
||||||
|
partOne()
|
||||||
|
duration := time.Since(start)
|
||||||
|
partTwo()
|
||||||
|
duration2 := time.Since(start)
|
||||||
|
fmt.Printf("p1: %s, p2: %s\n", duration, duration2-duration)
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeScanner(test bool) *bufio.Scanner {
|
||||||
|
var f *os.File
|
||||||
|
if test {
|
||||||
|
f, _ = os.Open("inputs/testinput")
|
||||||
|
} else {
|
||||||
|
f, _ = os.Open("inputs/input")
|
||||||
|
}
|
||||||
|
reader := bufio.NewReader(f)
|
||||||
|
return bufio.NewScanner(reader)
|
||||||
|
}
|
||||||
|
|
||||||
|
type pair struct {
|
||||||
|
parent *pair
|
||||||
|
leftp *pair
|
||||||
|
left int
|
||||||
|
rightp *pair
|
||||||
|
right int
|
||||||
|
}
|
||||||
|
|
||||||
|
func Parse(raw string) *pair {
|
||||||
|
root := &pair{}
|
||||||
|
var current *pair
|
||||||
|
left := true
|
||||||
|
for _, v := range raw {
|
||||||
|
switch v {
|
||||||
|
case '[':
|
||||||
|
if current == nil {
|
||||||
|
current = root
|
||||||
|
} else {
|
||||||
|
p := &pair{parent: current}
|
||||||
|
if left {
|
||||||
|
current.leftp = p
|
||||||
|
} else {
|
||||||
|
current.rightp = p
|
||||||
|
}
|
||||||
|
current = p
|
||||||
|
}
|
||||||
|
left = true
|
||||||
|
case ']':
|
||||||
|
current = current.parent
|
||||||
|
case ',':
|
||||||
|
left = false
|
||||||
|
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
|
||||||
|
if left {
|
||||||
|
current.left = mustAtoi(v)
|
||||||
|
} else {
|
||||||
|
current.right = mustAtoi(v)
|
||||||
|
}
|
||||||
|
case ' ':
|
||||||
|
continue
|
||||||
|
default:
|
||||||
|
panic("what the: " + string(v))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return root
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *pair) String() string {
|
||||||
|
var left, right string
|
||||||
|
if p.leftp == nil {
|
||||||
|
left = fmt.Sprintf("%d", p.left)
|
||||||
|
} else {
|
||||||
|
left = p.leftp.String()
|
||||||
|
}
|
||||||
|
if p.rightp == nil {
|
||||||
|
right = fmt.Sprintf("%d", p.right)
|
||||||
|
} else {
|
||||||
|
right = p.rightp.String()
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("[%s,%s]", left, right)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *pair) Magnitude() int {
|
||||||
|
left := 0
|
||||||
|
right := 0
|
||||||
|
if p.leftp == nil {
|
||||||
|
left = p.left
|
||||||
|
} else {
|
||||||
|
left = p.leftp.Magnitude()
|
||||||
|
}
|
||||||
|
if p.rightp == nil {
|
||||||
|
right = p.right
|
||||||
|
} else {
|
||||||
|
right = p.rightp.Magnitude()
|
||||||
|
}
|
||||||
|
return left*3 + right*2
|
||||||
|
}
|
||||||
|
|
||||||
|
func Add(left, right *pair) *pair {
|
||||||
|
return &pair{
|
||||||
|
leftp: left,
|
||||||
|
rightp: right,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Reduce(p *pair) {
|
||||||
|
for {
|
||||||
|
if MustExplode(0, p) {
|
||||||
|
Explode(p)
|
||||||
|
} else if MustSplit(p) {
|
||||||
|
Split(p)
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Split(p *pair) bool {
|
||||||
|
if p.left > 9 {
|
||||||
|
p.leftp = &pair{
|
||||||
|
left: p.left / 2,
|
||||||
|
right: (p.left / 2) + (p.left % 2),
|
||||||
|
}
|
||||||
|
p.left = 0
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if p.leftp != nil {
|
||||||
|
m := Split(p.leftp)
|
||||||
|
if m {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if p.right > 9 {
|
||||||
|
p.rightp = &pair{
|
||||||
|
left: p.right / 2,
|
||||||
|
right: (p.right / 2) + (p.right % 2),
|
||||||
|
}
|
||||||
|
p.right = 0
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if p.rightp != nil {
|
||||||
|
m := Split(p.rightp)
|
||||||
|
if m {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func MustSplit(p *pair) bool {
|
||||||
|
if p.left > 9 || p.right > 9 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if p.leftp != nil {
|
||||||
|
m := MustSplit(p.leftp)
|
||||||
|
if m {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if p.rightp != nil {
|
||||||
|
m := MustSplit(p.rightp)
|
||||||
|
if m {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func MustExplode(depth int, p *pair) bool {
|
||||||
|
if depth >= 4 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if p.leftp != nil {
|
||||||
|
m := MustExplode(depth+1, p.leftp)
|
||||||
|
if m {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if p.rightp != nil {
|
||||||
|
m := MustExplode(depth+1, p.rightp)
|
||||||
|
if m {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func Explode(p *pair) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func partOne() {
|
||||||
|
scanner := makeScanner(false)
|
||||||
|
|
||||||
|
scanner.Scan()
|
||||||
|
line := scanner.Text()
|
||||||
|
total := Parse(line)
|
||||||
|
for scanner.Scan() {
|
||||||
|
line := scanner.Text()
|
||||||
|
total = Add(total, Parse(line))
|
||||||
|
}
|
||||||
|
fmt.Println(total)
|
||||||
|
}
|
||||||
|
|
||||||
|
func partTwo() {
|
||||||
|
scanner := makeScanner(false)
|
||||||
|
|
||||||
|
for scanner.Scan() {
|
||||||
|
// line := scanner.Text()
|
||||||
|
}
|
||||||
|
}
|
||||||
160
18/main_test.go
Normal file
160
18/main_test.go
Normal file
@@ -0,0 +1,160 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestParse(t *testing.T) {
|
||||||
|
cases := []string{
|
||||||
|
"[1,2]",
|
||||||
|
"[[3,2],1]",
|
||||||
|
"[[3,2],[4,5]]",
|
||||||
|
"[[3,2],[[7,8],5]]",
|
||||||
|
"[[1,2],3]",
|
||||||
|
"[9,[8,7]]",
|
||||||
|
"[[1,9],[8,5]]",
|
||||||
|
"[[[[1,2],[3,4]],[[5,6],[7,8]]],9]",
|
||||||
|
"[[[9,[3,8]],[[0,9],6]],[[[3,7],[4,9]],3]]",
|
||||||
|
"[[[[1,3],[5,3]],[[1,3],[8,7]]],[[[4,9],[6,9]],[[8,2],[7,3]]]]",
|
||||||
|
}
|
||||||
|
for _, input := range cases {
|
||||||
|
p := Parse(input)
|
||||||
|
if input != p.String() {
|
||||||
|
t.Log(p.String())
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMustExplode(t *testing.T) {
|
||||||
|
cases := map[string]bool{
|
||||||
|
"[1,2]": false,
|
||||||
|
"[[[[2,4],4],[2,3]],1]": false,
|
||||||
|
"[[[[[4,3],4],4],1],3]": true,
|
||||||
|
"[2,[1,[4,[3,[4,3]]]]]": true,
|
||||||
|
"[[[[0,7],4],[7,[[8,4],9]]],[1,1]]": true,
|
||||||
|
}
|
||||||
|
for input, output := range cases {
|
||||||
|
if MustExplode(0, Parse(input)) != output {
|
||||||
|
t.Log(input)
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSplit(t *testing.T) {
|
||||||
|
cases := map[*pair]string{
|
||||||
|
{left: 1, right: 1}: "[1,1]",
|
||||||
|
{left: 10, right: 1}: "[[5,5],1]",
|
||||||
|
{left: 11, right: 1}: "[[5,6],1]",
|
||||||
|
{left: 12, right: 1}: "[[6,6],1]",
|
||||||
|
{left: 12, right: 12}: "[[6,6],12]",
|
||||||
|
{left: 2, right: 12}: "[2,[6,6]]",
|
||||||
|
{
|
||||||
|
leftp: &pair{left: 15, right: 9},
|
||||||
|
rightp: &pair{left: 8, right: 1},
|
||||||
|
}: "[[[7,8],9],[8,1]]",
|
||||||
|
{
|
||||||
|
leftp: &pair{left: 1, right: 9},
|
||||||
|
rightp: &pair{left: 8, right: 15},
|
||||||
|
}: "[[1,9],[8,[7,8]]]",
|
||||||
|
}
|
||||||
|
for input, expected := range cases {
|
||||||
|
Split(input)
|
||||||
|
if input.String() != expected {
|
||||||
|
t.Log(input.String(), expected)
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMustSplit(t *testing.T) {
|
||||||
|
cases := map[*pair]bool{
|
||||||
|
{left: 1, right: 1}: false,
|
||||||
|
{left: 10, right: 1}: true,
|
||||||
|
{left: 11, right: 1}: true,
|
||||||
|
{left: 12, right: 1}: true,
|
||||||
|
{left: 12, right: 12}: true,
|
||||||
|
{left: 2, right: 12}: true,
|
||||||
|
{
|
||||||
|
leftp: &pair{left: 1, right: 9},
|
||||||
|
rightp: &pair{left: 8, right: 5},
|
||||||
|
}: false,
|
||||||
|
{
|
||||||
|
leftp: &pair{left: 1, right: 9},
|
||||||
|
rightp: &pair{left: 8, right: 15},
|
||||||
|
}: true,
|
||||||
|
}
|
||||||
|
for input, output := range cases {
|
||||||
|
result := MustSplit(input)
|
||||||
|
if result != output {
|
||||||
|
t.Log(input.String())
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAdd(t *testing.T) {
|
||||||
|
cases := map[string][]*pair{
|
||||||
|
"[[1,2],[[3,4],5]]": {
|
||||||
|
&pair{left: 1, right: 2},
|
||||||
|
&pair{leftp: &pair{left: 3, right: 4}, right: 5},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for answer, pairs := range cases {
|
||||||
|
r := Add(pairs[0], pairs[1])
|
||||||
|
if r.String() != answer {
|
||||||
|
fmt.Printf("%s %s", r, answer)
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReduce(t *testing.T) {
|
||||||
|
cases := map[*pair]string{
|
||||||
|
{left: 1, right: 1}: "[1,1]",
|
||||||
|
{left: 10, right: 1}: "[[5,5],1]",
|
||||||
|
{left: 11, right: 1}: "[[5,6],1]",
|
||||||
|
{left: 12, right: 1}: "[[6,6],1]",
|
||||||
|
{left: 12, right: 13}: "[[6,6],[6,7]]",
|
||||||
|
{left: 2, right: 12}: "[2,[6,6]]",
|
||||||
|
{
|
||||||
|
leftp: &pair{left: 15, right: 9},
|
||||||
|
rightp: &pair{left: 8, right: 1},
|
||||||
|
}: "[[[7,8],9],[8,1]]",
|
||||||
|
{
|
||||||
|
leftp: &pair{left: 1, right: 9},
|
||||||
|
rightp: &pair{left: 8, right: 15},
|
||||||
|
}: "[[1,9],[8,[7,8]]]",
|
||||||
|
}
|
||||||
|
for input, expected := range cases {
|
||||||
|
Reduce(input)
|
||||||
|
if input.String() != expected {
|
||||||
|
t.Log(input.String(), expected)
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMagnitude(t *testing.T) {
|
||||||
|
cases := map[int]*pair{
|
||||||
|
29: {left: 9, right: 1},
|
||||||
|
21: {left: 1, right: 9},
|
||||||
|
129: {
|
||||||
|
leftp: &pair{left: 9, right: 1},
|
||||||
|
rightp: &pair{left: 1, right: 9},
|
||||||
|
},
|
||||||
|
143: {
|
||||||
|
leftp: &pair{left: 1, right: 2},
|
||||||
|
rightp: &pair{leftp: &pair{left: 3, right: 4}, right: 5},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for answer, pair := range cases {
|
||||||
|
r := pair.Magnitude()
|
||||||
|
if r != answer {
|
||||||
|
fmt.Printf("%d %d", r, answer)
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
180
20/main.go
Normal file
180
20/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)
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeScanner(test bool) *bufio.Scanner {
|
||||||
|
var f *os.File
|
||||||
|
if test {
|
||||||
|
f, _ = os.Open("inputs/testinput")
|
||||||
|
} else {
|
||||||
|
f, _ = os.Open("inputs/input")
|
||||||
|
}
|
||||||
|
reader := bufio.NewReader(f)
|
||||||
|
return bufio.NewScanner(reader)
|
||||||
|
}
|
||||||
|
|
||||||
|
type coord struct {
|
||||||
|
x int
|
||||||
|
y int
|
||||||
|
}
|
||||||
|
|
||||||
|
// grid SHOULD be like this:
|
||||||
|
// x ->
|
||||||
|
// y
|
||||||
|
// |
|
||||||
|
// V
|
||||||
|
|
||||||
|
type image struct {
|
||||||
|
background rune // what all uninitialized cells are set to; defaults to '.'
|
||||||
|
grid map[coord]rune
|
||||||
|
topleft coord
|
||||||
|
size int
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetNeighbors(c coord) []coord {
|
||||||
|
return []coord{
|
||||||
|
{x: c.x - 1, y: c.y - 1},
|
||||||
|
{x: c.x, y: c.y - 1},
|
||||||
|
{x: c.x + 1, y: c.y - 1},
|
||||||
|
|
||||||
|
{x: c.x - 1, y: c.y},
|
||||||
|
{x: c.x, y: c.y},
|
||||||
|
{x: c.x + 1, y: c.y},
|
||||||
|
|
||||||
|
{x: c.x - 1, y: c.y + 1},
|
||||||
|
{x: c.x, y: c.y + 1},
|
||||||
|
{x: c.x + 1, y: c.y + 1},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (img *image) GetNewRune(coord coord, enhancementMap string) rune {
|
||||||
|
index := 0
|
||||||
|
coords := GetNeighbors(coord)
|
||||||
|
for i := 0; i < len(coords); i++ {
|
||||||
|
value := img.grid[coords[i]]
|
||||||
|
if value == 0 {
|
||||||
|
value = img.background
|
||||||
|
}
|
||||||
|
if value == '#' {
|
||||||
|
index += (1 << (8 - i))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rune(enhancementMap[index])
|
||||||
|
}
|
||||||
|
|
||||||
|
func (img *image) CountBrightPixels() int {
|
||||||
|
count := 0
|
||||||
|
for _, v := range img.grid {
|
||||||
|
if v == '#' {
|
||||||
|
count++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count
|
||||||
|
}
|
||||||
|
|
||||||
|
func (img *image) Print() {
|
||||||
|
fmt.Println(strings.Repeat(string(img.background), img.size+2))
|
||||||
|
for y := img.topleft.y; y < img.size+img.topleft.y; y++ {
|
||||||
|
fmt.Print(string(img.background))
|
||||||
|
for x := img.topleft.x; x < img.size+img.topleft.x; x++ {
|
||||||
|
fmt.Printf("%s", string(img.grid[coord{x, y}]))
|
||||||
|
}
|
||||||
|
fmt.Printf("%s\n", string(img.background))
|
||||||
|
}
|
||||||
|
fmt.Println(strings.Repeat(string(img.background), img.size+2))
|
||||||
|
}
|
||||||
|
|
||||||
|
func Enhance(img *image, m string) *image {
|
||||||
|
next := &image{
|
||||||
|
topleft: coord{
|
||||||
|
x: img.topleft.x - 1,
|
||||||
|
y: img.topleft.y - 1,
|
||||||
|
},
|
||||||
|
size: img.size + 2,
|
||||||
|
grid: map[coord]rune{},
|
||||||
|
}
|
||||||
|
if img.background == '.' { // permute new "background" value
|
||||||
|
next.background = rune(m[0])
|
||||||
|
} else if img.background == '#' {
|
||||||
|
next.background = rune(m[511])
|
||||||
|
}
|
||||||
|
for y := img.topleft.y - 1; y < img.size+1; y++ {
|
||||||
|
for x := img.topleft.x - 1; x < img.size+1; x++ {
|
||||||
|
next.grid[coord{x, y}] = img.GetNewRune(coord{x, y}, m)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return next
|
||||||
|
}
|
||||||
|
|
||||||
|
func partOne() {
|
||||||
|
scanner := makeScanner(false)
|
||||||
|
|
||||||
|
scanner.Scan()
|
||||||
|
enhancementString := scanner.Text()
|
||||||
|
scanner.Scan() // eat empty line
|
||||||
|
|
||||||
|
img := &image{
|
||||||
|
background: '.',
|
||||||
|
grid: map[coord]rune{},
|
||||||
|
topleft: coord{0, 0},
|
||||||
|
}
|
||||||
|
|
||||||
|
y := 0
|
||||||
|
for scanner.Scan() {
|
||||||
|
line := scanner.Text()
|
||||||
|
img.size = len(line)
|
||||||
|
for x, c := range line {
|
||||||
|
img.grid[coord{x, y}] = c
|
||||||
|
}
|
||||||
|
y++
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < 2; i++ {
|
||||||
|
img = Enhance(img, enhancementString)
|
||||||
|
}
|
||||||
|
fmt.Println(img.CountBrightPixels())
|
||||||
|
}
|
||||||
|
|
||||||
|
func partTwo() {
|
||||||
|
scanner := makeScanner(false)
|
||||||
|
|
||||||
|
scanner.Scan()
|
||||||
|
enhancementString := scanner.Text()
|
||||||
|
scanner.Scan() // eat empty line
|
||||||
|
|
||||||
|
img := &image{
|
||||||
|
background: '.',
|
||||||
|
grid: map[coord]rune{},
|
||||||
|
topleft: coord{0, 0},
|
||||||
|
}
|
||||||
|
|
||||||
|
y := 0
|
||||||
|
for scanner.Scan() {
|
||||||
|
line := scanner.Text()
|
||||||
|
img.size = len(line)
|
||||||
|
for x, c := range line {
|
||||||
|
img.grid[coord{x, y}] = c
|
||||||
|
}
|
||||||
|
y++
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < 50; i++ {
|
||||||
|
img = Enhance(img, enhancementString)
|
||||||
|
}
|
||||||
|
fmt.Println(img.CountBrightPixels())
|
||||||
|
}
|
||||||
66
20/main_test.go
Normal file
66
20/main_test.go
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestGetNewRune(t *testing.T) {
|
||||||
|
img := image{
|
||||||
|
grid: map[coord]rune{
|
||||||
|
{0, 0}: '.', {1, 0}: '.', {2, 0}: '.',
|
||||||
|
{0, 1}: '.', {1, 1}: '.', {2, 1}: '.',
|
||||||
|
{0, 2}: '.', {1, 2}: '.', {2, 2}: '.',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
if img.GetNewRune(coord{1, 1}, ".") != '.' {
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
|
||||||
|
img = image{
|
||||||
|
grid: map[coord]rune{
|
||||||
|
{0, 0}: '.', {1, 0}: '.', {2, 0}: '.',
|
||||||
|
{0, 1}: '.', {1, 1}: '.', {2, 1}: '.',
|
||||||
|
{0, 2}: '.', {1, 2}: '.', {2, 2}: '#',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
if img.GetNewRune(coord{1, 1}, ".#") != '#' {
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
|
||||||
|
img = image{
|
||||||
|
grid: map[coord]rune{
|
||||||
|
{0, 0}: '.', {1, 0}: '.', {2, 0}: '.',
|
||||||
|
{0, 1}: '.', {1, 1}: '.', {2, 1}: '.',
|
||||||
|
{0, 2}: '.', {1, 2}: '#', {2, 2}: '.',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
if img.GetNewRune(coord{1, 1}, "..#.") != '#' {
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
|
||||||
|
img = image{
|
||||||
|
grid: map[coord]rune{
|
||||||
|
{0, 0}: '.', {1, 0}: '.', {2, 0}: '.',
|
||||||
|
{0, 1}: '.', {1, 1}: '.', {2, 1}: '.',
|
||||||
|
{0, 2}: '.', {1, 2}: '#', {2, 2}: '#',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
if img.GetNewRune(coord{1, 1}, "...#") != '#' {
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
|
||||||
|
img = image{
|
||||||
|
background: '#',
|
||||||
|
grid: map[coord]rune{
|
||||||
|
{0, 0}: '.', {1, 0}: '.', {2, 0}: '.',
|
||||||
|
{0, 1}: '.', {1, 1}: '.', {2, 1}: '.',
|
||||||
|
{0, 2}: '.', {1, 2}: '#', {2, 2}: '#',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
m := strings.Repeat(".", 484)
|
||||||
|
m += "#"
|
||||||
|
if img.GetNewRune(coord{0, 0}, m) != '#' { // 111100100, or 484
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
}
|
||||||
95
21/main.go
Normal file
95
21/main.go
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func mustAtoi(line string) int {
|
||||||
|
i, _ := strconv.Atoi(line)
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
start := time.Now()
|
||||||
|
partOne()
|
||||||
|
duration := time.Since(start)
|
||||||
|
partTwo()
|
||||||
|
duration2 := time.Since(start)
|
||||||
|
fmt.Printf("p1: %s, p2: %s\n", duration, duration2-duration)
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeScanner(test bool) *bufio.Scanner {
|
||||||
|
var f *os.File
|
||||||
|
if test {
|
||||||
|
f, _ = os.Open("inputs/testinput")
|
||||||
|
} else {
|
||||||
|
f, _ = os.Open("inputs/input")
|
||||||
|
}
|
||||||
|
reader := bufio.NewReader(f)
|
||||||
|
return bufio.NewScanner(reader)
|
||||||
|
}
|
||||||
|
|
||||||
|
func MakeDeterministicDie(max int) func() int {
|
||||||
|
currentDieValue := 0
|
||||||
|
return func() int {
|
||||||
|
if currentDieValue >= max {
|
||||||
|
currentDieValue = 0
|
||||||
|
}
|
||||||
|
currentDieValue++
|
||||||
|
return currentDieValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func RollThree(f func() int) int {
|
||||||
|
return f() + f() + f()
|
||||||
|
}
|
||||||
|
|
||||||
|
func partOne() {
|
||||||
|
scanner := makeScanner(false)
|
||||||
|
|
||||||
|
scanner.Scan()
|
||||||
|
player1 := mustAtoi(strings.Split(scanner.Text(), " ")[4])
|
||||||
|
scanner.Scan()
|
||||||
|
player2 := mustAtoi(strings.Split(scanner.Text(), " ")[4])
|
||||||
|
|
||||||
|
die := MakeDeterministicDie(100)
|
||||||
|
score1 := 0
|
||||||
|
score2 := 0
|
||||||
|
rolls := 0
|
||||||
|
|
||||||
|
for {
|
||||||
|
player1 = player1 + RollThree(die)
|
||||||
|
rolls += 3
|
||||||
|
for player1 > 10 {
|
||||||
|
player1 -= 10
|
||||||
|
}
|
||||||
|
score1 += player1
|
||||||
|
if score1 >= 1000 {
|
||||||
|
fmt.Println(score2 * rolls)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
player2 = player2 + RollThree(die)
|
||||||
|
rolls += 3
|
||||||
|
for player2 > 10 {
|
||||||
|
player2 -= 10
|
||||||
|
}
|
||||||
|
score2 += player2
|
||||||
|
if score2 >= 1000 {
|
||||||
|
fmt.Println(score1 * rolls)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func partTwo() {
|
||||||
|
scanner := makeScanner(false)
|
||||||
|
|
||||||
|
for scanner.Scan() {
|
||||||
|
// line := scanner.Text()
|
||||||
|
}
|
||||||
|
}
|
||||||
134
22/main.go
Normal file
134
22/main.go
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func mustAtoi(line string) int {
|
||||||
|
i, _ := strconv.Atoi(line)
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
start := time.Now()
|
||||||
|
partOne()
|
||||||
|
duration := time.Since(start)
|
||||||
|
partTwo()
|
||||||
|
duration2 := time.Since(start)
|
||||||
|
fmt.Printf("p1: %s, p2: %s\n", duration, duration2-duration)
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeScanner(test bool) *bufio.Scanner {
|
||||||
|
var f *os.File
|
||||||
|
if test {
|
||||||
|
f, _ = os.Open("inputs/testinput")
|
||||||
|
} else {
|
||||||
|
f, _ = os.Open("inputs/input")
|
||||||
|
}
|
||||||
|
reader := bufio.NewReader(f)
|
||||||
|
return bufio.NewScanner(reader)
|
||||||
|
}
|
||||||
|
|
||||||
|
type step struct {
|
||||||
|
on bool
|
||||||
|
x []int
|
||||||
|
y []int
|
||||||
|
z []int
|
||||||
|
}
|
||||||
|
|
||||||
|
func ParseInput(line string) step {
|
||||||
|
s := step{}
|
||||||
|
var state byte
|
||||||
|
acc := ""
|
||||||
|
for i := 0; i < len(line); i++ {
|
||||||
|
switch line[i] {
|
||||||
|
case '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-':
|
||||||
|
acc += string(line[i])
|
||||||
|
case 'f':
|
||||||
|
s.on = false
|
||||||
|
case 'n':
|
||||||
|
s.on = true
|
||||||
|
case 'x', 'y', 'z':
|
||||||
|
state = line[i]
|
||||||
|
case '.', ',':
|
||||||
|
if line[i] == '.' {
|
||||||
|
i++ // skip second .
|
||||||
|
}
|
||||||
|
switch state {
|
||||||
|
case 'x':
|
||||||
|
s.x = append(s.x, mustAtoi(acc))
|
||||||
|
case 'y':
|
||||||
|
s.y = append(s.y, mustAtoi(acc))
|
||||||
|
case 'z':
|
||||||
|
s.z = append(s.z, mustAtoi(acc))
|
||||||
|
}
|
||||||
|
acc = ""
|
||||||
|
default: // all other characters do nothing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s.z = append(s.z, mustAtoi(acc)) // catch last number
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
type coord struct {
|
||||||
|
x int
|
||||||
|
y int
|
||||||
|
z int
|
||||||
|
}
|
||||||
|
|
||||||
|
func GenerateCoords(s step) []coord {
|
||||||
|
c := []coord{}
|
||||||
|
for x := s.x[0]; x <= s.x[1]; x++ {
|
||||||
|
for y := s.y[0]; y <= s.y[1]; y++ {
|
||||||
|
for z := s.z[0]; z <= s.z[1]; z++ {
|
||||||
|
c = append(c, coord{x, y, z})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
func partOne() {
|
||||||
|
scanner := makeScanner(true)
|
||||||
|
|
||||||
|
grid := map[coord]struct{}{}
|
||||||
|
steps := []step{}
|
||||||
|
for scanner.Scan() {
|
||||||
|
steps = append(steps, ParseInput(scanner.Text()))
|
||||||
|
}
|
||||||
|
for _, step := range steps[0:20] {
|
||||||
|
for _, coord := range GenerateCoords(step) {
|
||||||
|
if step.on {
|
||||||
|
grid[coord] = struct{}{}
|
||||||
|
} else {
|
||||||
|
delete(grid, coord)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt.Println(len(grid))
|
||||||
|
}
|
||||||
|
|
||||||
|
func partTwo() {
|
||||||
|
scanner := makeScanner(true)
|
||||||
|
|
||||||
|
grid := map[coord]struct{}{}
|
||||||
|
steps := []step{}
|
||||||
|
for scanner.Scan() {
|
||||||
|
steps = append(steps, ParseInput(scanner.Text()))
|
||||||
|
}
|
||||||
|
// this ain't gonna work
|
||||||
|
for _, step := range steps {
|
||||||
|
for _, coord := range GenerateCoords(step) {
|
||||||
|
if step.on {
|
||||||
|
grid[coord] = struct{}{}
|
||||||
|
} else {
|
||||||
|
delete(grid, coord)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt.Println(len(grid))
|
||||||
|
}
|
||||||
110
25/main.go
Normal file
110
25/main.go
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
start := time.Now()
|
||||||
|
partOne()
|
||||||
|
duration := time.Since(start)
|
||||||
|
fmt.Printf("p1: %s\n", duration)
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeScanner(test bool) *bufio.Scanner {
|
||||||
|
var f *os.File
|
||||||
|
if test {
|
||||||
|
f, _ = os.Open("inputs/testinput")
|
||||||
|
} else {
|
||||||
|
f, _ = os.Open("inputs/input")
|
||||||
|
}
|
||||||
|
reader := bufio.NewReader(f)
|
||||||
|
return bufio.NewScanner(reader)
|
||||||
|
}
|
||||||
|
|
||||||
|
type coord struct {
|
||||||
|
x int
|
||||||
|
y int
|
||||||
|
}
|
||||||
|
|
||||||
|
type floor struct {
|
||||||
|
steps int
|
||||||
|
width int
|
||||||
|
height int
|
||||||
|
m map[coord]rune
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *floor) Print() {
|
||||||
|
for y := 0; y < f.height; y++ {
|
||||||
|
for x := 0; x < f.width; x++ {
|
||||||
|
fmt.Printf("%s", string(f.m[coord{x: x, y: y}]))
|
||||||
|
}
|
||||||
|
fmt.Printf("\n")
|
||||||
|
}
|
||||||
|
fmt.Printf("\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *floor) Step() bool {
|
||||||
|
f.steps++
|
||||||
|
moved := false
|
||||||
|
toMove := map[coord]coord{}
|
||||||
|
for y := 0; y < f.height; y++ {
|
||||||
|
for x := 0; x < f.width; x++ {
|
||||||
|
current := coord{x: x, y: y}
|
||||||
|
x += 1
|
||||||
|
if x >= f.width {
|
||||||
|
x = 0
|
||||||
|
}
|
||||||
|
if f.m[current] == '>' && f.m[coord{x: x, y: y}] == '.' {
|
||||||
|
toMove[current] = coord{x: x, y: y}
|
||||||
|
moved = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for current, next := range toMove {
|
||||||
|
f.m[next] = f.m[current]
|
||||||
|
f.m[current] = '.'
|
||||||
|
}
|
||||||
|
toMove = map[coord]coord{}
|
||||||
|
for y := 0; y < f.height; y++ {
|
||||||
|
for x := 0; x < f.width; x++ {
|
||||||
|
current := coord{x: x, y: y}
|
||||||
|
y += 1
|
||||||
|
if y >= f.height {
|
||||||
|
y = 0
|
||||||
|
}
|
||||||
|
if f.m[current] == 'v' && f.m[coord{x: x, y: y}] == '.' {
|
||||||
|
toMove[current] = coord{x: x, y: y}
|
||||||
|
moved = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for current, next := range toMove {
|
||||||
|
f.m[next] = f.m[current]
|
||||||
|
f.m[current] = '.'
|
||||||
|
}
|
||||||
|
return moved
|
||||||
|
}
|
||||||
|
|
||||||
|
func partOne() {
|
||||||
|
scanner := makeScanner(false)
|
||||||
|
f := &floor{
|
||||||
|
m: make(map[coord]rune),
|
||||||
|
}
|
||||||
|
y := 0
|
||||||
|
for scanner.Scan() {
|
||||||
|
line := scanner.Text()
|
||||||
|
f.width = len(line)
|
||||||
|
for x, v := range line {
|
||||||
|
f.m[coord{x: x, y: y}] = v
|
||||||
|
}
|
||||||
|
y++
|
||||||
|
}
|
||||||
|
f.height = y
|
||||||
|
for f.Step() {
|
||||||
|
}
|
||||||
|
fmt.Println(f.steps)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user