Compare commits

14 Commits

11 changed files with 1284 additions and 26 deletions

View File

@@ -46,30 +46,30 @@ func makeScanner(test bool) *bufio.Scanner {
return bufio.NewScanner(reader)
}
func parseNumber(stream []uint8, length int) int64 {
result := int64(0)
func parseNumber(stream []uint8, length int) int {
result := int(0)
for i := 0; i < length; i++ {
result += int64(stream[i]) << (length - 1 - i)
result += int(stream[i]) << (length - 1 - i)
}
return result
}
type packet struct {
version int64
typeID int64
version int
typeID int
subPackets []packet
encodedNumber int64
encodedNumber int
}
func getPacketVersion(stream []uint8) int64 {
func getPacketVersion(stream []uint8) int {
return parseNumber(stream, 3)
}
func getPacketType(stream []uint8) int64 {
func getPacketType(stream []uint8) int {
return parseNumber(stream, 3)
}
func getSubpacketLength(t uint8, stream []uint8) (int, int64) {
func getSubpacketLength(t uint8, stream []uint8) (int, int) {
if t == 0 {
return 15, parseNumber(stream, 15)
}
@@ -79,7 +79,7 @@ func getSubpacketLength(t uint8, stream []uint8) (int, int64) {
return 0, 0
}
func parsePayload(stream []uint8) (int64, int) {
func parsePayload(stream []uint8) (int, int) {
num := []uint8{}
pos := 0
chars := 0
@@ -95,9 +95,9 @@ func parsePayload(stream []uint8) (int64, int) {
return parseNumber(num, chars), pos
}
func parsePackets(stream []uint8) (int, []packet) {
func parsePackets(stream []uint8) (int, packet) {
if len(stream) <= 7 {
return 0, []packet{}
return 0, packet{}
}
parsedPacket := packet{}
parsedPacket.version = getPacketVersion(stream[0:3])
@@ -105,29 +105,31 @@ func parsePackets(stream []uint8) (int, []packet) {
if parsedPacket.typeID == 4 {
encoded, consumed := parsePayload(stream[6:])
parsedPacket.encodedNumber = encoded
return consumed + 6, []packet{parsedPacket} // 6 is packet header length
return consumed + 6, parsedPacket // 6 is packet header length
} else {
parsed := 0
size, subpacketlength := getSubpacketLength(stream[6], stream[7:])
for {
consumed, subs := parsePackets(stream[7+size+parsed:])
parsedPacket.subPackets = append(parsedPacket.subPackets, subs...)
if consumed == 0 {
return parsed + 7 + size, parsedPacket
}
parsedPacket.subPackets = append(parsedPacket.subPackets, subs)
parsed += consumed
if size == 11 && int64(len(parsedPacket.subPackets)) == subpacketlength {
return parsed + 7 + size, []packet{parsedPacket}
if size == 11 && len(parsedPacket.subPackets) == subpacketlength {
return parsed + 7 + size, parsedPacket
} else if size == 15 && int64(parsed) > subpacketlength || consumed == 0 {
return parsed + 7 + size, []packet{parsedPacket}
} else if size == 15 && parsed > subpacketlength {
return parsed + 7 + size, parsedPacket
}
}
}
}
func countVersions(packets []packet) int {
i := 0
for _, p := range packets {
i += int(p.version)
i += countVersions(p.subPackets)
func countVersions(pac packet) int {
i := int(pac.version)
for _, p := range pac.subPackets {
i += countVersions(p)
}
return i
}
@@ -145,10 +147,97 @@ func partOne() {
fmt.Println(countVersions(parsedPacket))
}
func solve(p packet) int {
switch p.typeID {
case 0: // sum
if len(p.subPackets) == 1 {
return solve(p.subPackets[0])
} else {
acc := 0
for _, v := range p.subPackets {
acc += solve(v)
}
return acc
}
case 1: // product
if len(p.subPackets) == 1 {
return solve(p.subPackets[0])
} else {
acc := solve(p.subPackets[0])
for _, v := range p.subPackets[1:] {
acc *= solve(v)
}
return acc
}
case 2: // min
if len(p.subPackets) == 1 {
return solve(p.subPackets[0])
} else {
acc := solve(p.subPackets[0])
for _, v := range p.subPackets[1:] {
t := solve(v)
if t < acc {
acc = t
}
}
return acc
}
case 3: // max
if len(p.subPackets) == 1 {
return solve(p.subPackets[0])
} else {
acc := solve(p.subPackets[0])
for _, v := range p.subPackets[1:] {
t := solve(v)
if t > acc {
acc = t
}
}
return acc
}
case 4: // number
return p.encodedNumber
case 5: // >
if len(p.subPackets) != 2 {
panic(fmt.Sprintf("recevied type 5 packet with %d subpackets", len(p.subPackets)))
}
if solve(p.subPackets[0]) > solve(p.subPackets[1]) {
return 1
} else {
return 0
}
case 6: // <
if len(p.subPackets) != 2 {
panic(fmt.Sprintf("recevied type 6 packet with %d subpackets", len(p.subPackets)))
}
if solve(p.subPackets[0]) < solve(p.subPackets[1]) {
return 1
} else {
return 0
}
case 7: // ==
if len(p.subPackets) != 2 {
panic(fmt.Sprintf("recevied type 7 packet with %d subpackets", len(p.subPackets)))
}
if solve(p.subPackets[0]) == solve(p.subPackets[1]) {
return 1
} else {
return 0
}
default:
panic("unknown packet type")
}
}
func partTwo() {
scanner := makeScanner(false)
for scanner.Scan() {
// line := scanner.Text()
scanner.Scan()
line := scanner.Text()
stream := []uint8{}
for _, hex := range line {
stream = append(stream, hexMap[hex]...)
}
_, parsedPacket := parsePackets(stream)
fmt.Println(solve(parsedPacket))
}

View File

@@ -5,7 +5,7 @@ import (
)
func TestVersionParse(t *testing.T) {
tests := map[int64][]uint8{
tests := map[int][]uint8{
0: {0, 0, 0},
1: {0, 0, 1},
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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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)
}