Skip to content

Instantly share code, notes, and snippets.

@mgwidmann
Last active December 3, 2019 06:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mgwidmann/bd4f2411d447dd627add22aaefb7e0d8 to your computer and use it in GitHub Desktop.
Save mgwidmann/bd4f2411d447dd627add22aaefb7e0d8 to your computer and use it in GitHub Desktop.
2019 AOC - golang
package main
import "fmt"
var allMasses []int = []int{
147308, 51605, 71317, 110882, 92545, 126856, 104937, 92433, 107850, 119538, 82733, 52216, 105704, 123682, 105919, 136265, 100540, 84245, 72006, 111652, 85116, 85841, 71374, 144196, 125493, 113529, 64637, 87489, 138161, 120897, 53384, 83310,
120672, 126144, 107681, 101369, 77469, 141056, 140426, 114920, 124454, 130867, 64611, 104813, 138808, 114234, 148654, 59031, 91367, 83316, 106192, 127495, 139980, 119024, 149567, 57007, 61075, 65637, 75293, 61670, 104044, 77230, 80201,
137094, 99733, 50801, 68922, 148404, 79980, 62716, 67666, 72694, 81951, 108427, 111721, 55532, 94442, 88562, 101088, 111656, 111649, 92085, 91730, 114744, 59355, 55842, 100926, 146370, 147829, 62160, 91447, 115745, 141815, 106837, 68151,
89077, 60357, 89856, 75040, 139131,
}
func fuelRequired(mass int) int {
return (mass / 3) - 2
}
func mainFirstStar() int {
sum := 0
for _, mass := range allMasses {
sum += fuelRequired(mass)
}
return sum
}
func fuelForFuel(fuel int) int {
if fuel <= 0 {
return 0
} else {
extraFuel := fuelRequired(fuel)
f2 := fuelForFuel(extraFuel)
return fuel + f2
}
}
func mainSecondStar() int {
sum := 0
for _, mass := range allMasses {
fuel := fuelRequired(mass)
extraFuel := fuelForFuel(fuel)
sum += extraFuel
}
return sum
}
func main() {
basicSum := mainFirstStar()
fmt.Println("(Basic) Sum fuel required:", basicSum)
extraFuel := mainSecondStar()
fmt.Println("Full Sum fuel required:", extraFuel)
}
package main
import (
"fmt"
"strings"
)
var instructions []int = []int{
1, 12, 2, 3, // Original was 1, 0, 0, 3,
1, 1, 2, 3,
1, 3, 4, 3,
1, 5, 0, 3,
2, 6, 1, 19,
2, 19, 9, 23,
1, 23, 5, 27,
2, 6, 27, 31,
1, 31, 5, 35,
1, 35, 5, 39,
2, 39, 6, 43,
2, 43, 10, 47,
1, 47, 6, 51,
1, 51, 6, 55,
2, 55, 6, 59,
1, 10, 59, 63,
1, 5, 63, 67,
2, 10, 67, 71,
1, 6, 71, 75,
1, 5, 75, 79,
1, 10, 79, 83,
2, 83, 10, 87,
1, 87, 9, 91,
1, 91, 10, 95,
2, 6, 95, 99,
1, 5, 99, 103,
1, 103, 13, 107,
1, 107, 10, 111,
2, 9, 111, 115,
1, 115, 6, 119,
2, 13, 119, 123,
1, 123, 6, 127,
1, 5, 127, 131,
2, 6, 131, 135,
2, 6, 135, 139,
1, 139, 5, 143,
1, 143, 10, 147,
1, 147, 2, 151,
1, 151, 13, 0,
99,
2, 0, 14, 0,
}
type InstructionType int
const (
Add InstructionType = iota + 1
Multiply
End InstructionType = 99
)
// Can't make real enum :(
// Making const gives the following error
// const initializer []InstructionType literal is not a constant
var Action []InstructionType = []InstructionType{Add, Multiply, End}
func (t InstructionType) String() string {
if t == 99 {
return "End"
}
if t < Add || t > Multiply {
return "INVALID"
}
return [...]string{"Add", "Multiply"}[t-1]
}
func printProgram(program []int) string {
var prog []string
for i := 0; i < len(program); i += 4 {
switch instruction := program[i]; InstructionType(instruction) {
case End:
prog = append(prog, fmt.Sprintf("%d: %v", i, program[i:i+1]))
i -= 3
default:
if i+4 >= len(program) {
prog = append(prog, fmt.Sprintf("%d: %v", i, program[i:]))
} else {
prog = append(prog, fmt.Sprintf("%d: %v", i, program[i:i+4]))
}
}
}
return strings.Join(prog, "\n")
}
type Instruction struct {
Action []InstructionType
Pos1 int
Pos2 int
StoreAt int
}
func executeInstruction(program []int, i int) int {
switch instruction := program[i]; InstructionType(instruction) {
case Add:
pos1 := program[i+1]
pos2 := program[i+2]
storeAt := program[i+3]
// fmt.Println("Adding", program[pos1], "(idx "+strconv.Itoa(pos1)+")", program[pos2], "(idx "+strconv.Itoa(pos2)+")", "and storing at", storeAt, "(before "+strconv.Itoa(program[storeAt])+" after "+strconv.Itoa(program[pos1]+program[pos2])+")")
program[storeAt] = program[pos1] + program[pos2]
return i + 4
case Multiply:
pos1 := program[i+1]
pos2 := program[i+2]
storeAt := program[i+3]
// fmt.Println("Multiplying", program[pos1], "(idx "+strconv.Itoa(pos1)+")", program[pos2], "(idx "+strconv.Itoa(pos2)+")", "and storing at", storeAt, "(before "+strconv.Itoa(program[storeAt])+" after "+strconv.Itoa(program[pos1]*program[pos2])+")")
program[storeAt] = program[pos1] * program[pos2]
return i + 4
case End:
return -1
default:
var fullInstruction []int
if i+4 >= len(program) {
fullInstruction = program[i:]
} else {
fullInstruction = program[i : i+4]
}
message := fmt.Sprintf("Unknown instruction %v at position %v (%v)\nCurrent program: \n%v", instruction, i, fullInstruction, printProgram(program))
panic(message)
}
}
func executeProgram(program []int) []int {
for i := 0; i < len(program); {
// if i+4 >= len(program) {
// fmt.Printf("Executing %v (%v)\n", i, program[i:])
// } else {
// fmt.Printf("Executing %v (%v)\n", i, program[i:i+4])
// }
i = executeInstruction(program, i)
if i == -1 {
// fmt.Println("BREAKING!!")
break
}
// fmt.Println("Next instruction:", i, "("+InstructionType(program[i]).String()+")")
// fmt.Println(printProgram(program))
}
return program
}
const NOUN_AND_VERB_ANSWER = 19690720
func findNounAndVerb() (int, int) {
for i := 0; i <= 99; i++ {
for j := 0; j <= 99; j++ {
newProgram := make([]int, len(instructions))
copy(newProgram, instructions)
newProgram[1] = i
newProgram[2] = j
modifiedInstructions := executeProgram(newProgram)
if modifiedInstructions[0] == NOUN_AND_VERB_ANSWER {
return i, j
}
}
}
return -1, -1
}
func main() {
program := make([]int, len(instructions))
copy(program, instructions)
modifiedInstructions := executeProgram(program)
fmt.Println("New program:", printProgram(modifiedInstructions))
noun, verb := findNounAndVerb()
fmt.Println("Found noun", noun, "and verb", verb, "(final answer is:", noun*100+verb, ")")
}
package main
import (
"fmt"
"reflect"
"testing"
)
func TestExecuteInstructionHalt(t *testing.T) {
program := []int{
1, 2, 3, 3,
1, 4, 5, 7,
99,
}
runTestExample(t, program, 8, -1, -1, 0)
}
func TestExecuteInstructionAdd(t *testing.T) {
program := []int{
1, 2, 3, 3, // Overwrites last 3 with 6 (3 + 3)
1, 4, 5, 7,
99,
}
runTestExample(t, program, 0, 4, 3, 6)
}
func TestExecuteInstructionMultiply(t *testing.T) {
program := []int{
2, 2, 3, 3, // Overwrites last 3 with 9 (3 * 3)
1, 4, 5, 7,
99,
}
runTestExample(t, program, 0, 4, 3, 9)
}
func TestExecuteProgram1(t *testing.T) {
program := []int{
2, 4, 4, 5,
99,
0,
}
originalProgram := make([]int, len(program))
copy(originalProgram, program)
got := executeProgram(program)
expected := []int{
2, 4, 4, 5,
99,
9801,
}
if !reflect.DeepEqual(expected, got) {
fmt.Println("Original Program:\n" + printProgram(originalProgram))
t.Errorf("Expected program:\n%s\nGot:\n%s", printProgram(expected), printProgram(got))
}
}
func runTestExample(t *testing.T, program []int, instruction int, expectedNextInstruction int, modifiedIndex int, modifiedValue int) {
currentInstruction := make([]int, 4)
if instruction+4 >= len(program) {
copy(currentInstruction, program[instruction:])
} else {
copy(currentInstruction, program[instruction:instruction+4])
}
nextInstruction := executeInstruction(program, instruction)
if nextInstruction != expectedNextInstruction {
fmt.Println(printProgram(program))
t.Errorf("Executing %v returned %d; want %v", currentInstruction, nextInstruction, expectedNextInstruction)
}
if modifiedIndex != -1 {
if program[modifiedIndex] != modifiedValue {
fmt.Println(printProgram(program))
t.Errorf("Executing %v did not modify index %d to set value to %d (was %d)", currentInstruction, modifiedIndex, modifiedValue, program[modifiedIndex])
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment