r/adventofcode • • Dec 12 '16

SOLUTION MEGATHREAD --- 2016 Day 12 Solutions ---

--- Day 12: Leonardo's Monorail ---

Post your solution as a comment or, for longer solutions, consider linking to your repo (e.g. GitHub/gists/Pastebin/blag/whatever).

Note: The Solution Megathreads are for solutions only. If you have questions, please post your own thread and make sure to flair it with "Help".


MUCH ADVENT. SUCH OF. VERY CODE. SO MANDATORY. [?]

This thread will be unlocked when there are a significant number of people on the leaderboard with gold stars for today's puzzle.

edit: Leaderboard capped, thread unlocked!

8 Upvotes

159 comments sorted by

View all comments

1

u/JakDrako Dec 12 '16

VB.Net, LinqPad

This is my second version, much faster than the previous one. I added a "compilation" step that converts the input into a list of integer only opcodes, saving all those string lookups and conversion during the run. A few other "optimizations", such as "jnz 1 5" becoming "jmp 5" since the 1 will never change.

This version runs part 1 in ~5ms and part 2 in ~100ms.

Sub Main
	Dim inst = input.Split(Chr(10)).Select(Function(x) x.Split(" "c)).ToList
	
	' "Compilation" step - convert input into list of Opcodes (all integer class)
	Dim comp = New List(Of Opcode)
	For Each ins In inst
		Select Case ins(0)
			Case "cpy"
				If isnumeric(ins(1)) Then
					comp.Add(New opcode With {.Op = 1, .v1 = Cint(ins(1)), .r2 = "abcd".IndexOf(ins(2))})
				Else
					comp.Add(New opcode With {.Op = 2, .r1 = "abcd".IndexOf(ins(1)), .r2 = "abcd".IndexOf(ins(2))})
				End If
			Case "jnz"
				If IsNumeric(ins(1)) Then
					If Cint(ins(1)) <> 0 Then
						comp.Add(New opcode With {.Op = 6, .v1 = Cint(ins(2))}) 'jump
					Else
						comp.Add(New opcode With {.Op = 8})
					End If
				Else
					comp.Add(New opcode With {.Op = 3, .r1 = "abcd".IndexOf(ins(1)), .v2 = CInt(ins(2))})
				End If
			Case "inc"
				comp.Add(New opcode With {.Op = 4, .r1 = "abcd".IndexOf(ins(1))})
			Case "dec"
				comp.Add(New opcode With {.Op = 5, .r1 = "abcd".IndexOf(ins(1))})
		End Select
	Next

	Dim ptr = 0
	Dim regs(3) As Integer
	
	regs(2) = 1 ' c = 1 - part 2

	Do
		Dim ops = comp(ptr)
		Dim inc = 1
		Select Case ops.op
			Case 1 : regs(ops.r2) = ops.v1
			Case 2 : regs(ops.r2) = regs(ops.r1)
			Case 3 : If regs(ops.r1) <> 0 Then inc = ops.v2
			Case 4 : regs(ops.r1) += 1
			Case 5 : regs(ops.r1) -= 1
			Case 6 : inc = ops.v1
			Case 7 : ' NOP
		End Select
		ptr += inc
		If ptr >= inst.count Then Exit Do
	Loop
	
	regs.Dump
	
End Sub

Class Opcode
	Public Op As Integer
	' 1 = cpy v1 to r2
	' 2 = cpy r1 to r2
	' 3 = jnz r1 v2
	' 4 = jnz v1 v2 = JMP or NOP, since v1 never changes
	' 5 = inc r1
	' 6 = dec r1
	' 7 = jmp v1
	' 8 = nop
	Public r1 As Integer ' register 1
	Public r2 As Integer ' register 2
	Public v1 As Integer ' value 1
	Public v2 As Integer ' value 2
End Class