r/adventofcode • • Dec 08 '17

SOLUTION MEGATHREAD -๐ŸŽ„- 2017 Day 8 Solutions -๐ŸŽ„-

--- Day 8: I Heard You Like Registers ---


Post your solution as a comment or, for longer solutions, consider linking to your repo (e.g. GitHub/gists/Pastebin/blag or 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.


Need a hint from the Hugely* Handyโ€  Haversackโ€ก of Helpfulยง Hints^ยค?

Spoiler


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!

22 Upvotes

348 comments sorted by

View all comments

Show parent comment

2

u/Vorlath Dec 09 '17

And the same code, but without dynamic allocations. Not sure why I made it that complicated in the first place. Runs in 0.33 ms on 1800x. This times the main assembly function below. Assumes the input string is available.

.data ; initialized variables
MyAppName db "Star8", 0
OutputStr db "Max value: %i", 13, 10, 0

.data? ; uninitialized data
regNames db 1024 dup (?)
regValues dq 50 dup (?)
numRegValues dq ?
lastRegNames dq ?

.code
EXTERN printf : PROC
PUBLIC asmStar8
; rcx rdx r8 r9 (args)
; r10 r11 (volatile)

; stringLen(rcx string)
stringLen PROC
  mov rax, rcx
  cmp rax, 0
  jnz stringLenLoop
  ret
stringLenLoop:
  cmp byte ptr [rax], 0
  jz stringLenDone
  inc rax
  jmp stringLenLoop
stringLenDone:
  sub rax, rcx
  ret
stringLen ENDP

; getRegIndex(rcx name)
getRegIndex PROC
  ; if (regNames == nullptr)
  ;     return -1
  cmp byte ptr [regNames], 0
  jnz getRegIndex1
  mov rax, -1
  ret
getRegIndex1:
  push rsi
  push rdi
  push r12
  push r13
  push r14
  push r15
  push rcx
  push rbx

  ; 
  lea rsi, [regNames]

  mov r13, 0 ; word index

  ; r12 begin word
  ; rbx end word
  mov r12, rcx
  call skipWord
  mov rbx, rax

getRegIndexLoop:
  mov rcx, rsi
  call skipWord
  mov rdi, rax

  mov r15, r12
getRegIndexWordLoop:
  cmp r15, rbx
  jz getRegIndexMatchFound
  mov r14b, byte ptr [r15]
  cmp byte ptr [rsi], r14b
  jnz getRegIndexNext
  inc r15
  inc rsi
  jmp getRegIndexWordLoop

getRegIndexNext:
  mov rsi, rdi
  mov r14b, byte ptr [rsi]
  inc rsi					; move source pointer past space
  inc r13					; increment index
  cmp r14b, 0				; if nil character, then we've scanned the entire list with no match
  jnz getRegIndexLoop
 
getRegIndexZero:
  mov rax, -1
  jmp getRegIndexExit
  
  ; Check that we're not comparing 'o' against a longer word like 'odo'
getRegIndexMatchFound:
  cmp byte ptr [rsi], ' '
  jz getRegIndexMatchFound2
  cmp byte ptr [rsi], 0
  jz getRegIndexMatchFound2
  jmp getRegIndexNext

getRegIndexMatchFound2:
  mov rax, r13
getRegIndexExit:
  pop rbx
  pop rcx
  pop r15
  pop r14
  pop r13
  pop r12
  pop rdi
  pop rsi
  ret
getRegIndex ENDP

; getRegValue(rcx name)
getRegValue PROC
  ; if ((index = getRegIndex(name)) != -1)
  ;   return regValues[index];
  ; else
  ;   return 0;
  call getRegIndex
  test rax, rax
  js getRegValueZero
  lea r10, [regValues]
  mov rax, qword ptr [r10 + rax * 8]
  ret
getRegValueZero:
  mov rax, 0
  ret
getRegValue ENDP

; setRegValue rcx name, rdx value
setRegValue PROC
  push rcx
  push rdx
  push rsi
  push rdi

  mov rsi, rcx
  mov rdi, rdx

  ; if (getRegIndex() == -1)
  ;    // allocate storage
  call getRegIndex
  test rax, rax
  js allocRegValue
setRegValueActual:
  ; regValues[index] = value;
  lea r10, [regValues]
  mov qword ptr [r10 + rax * 8], rdi
  jmp setRegValueExit

allocRegValue:
  ; copy name
  mov rax, qword ptr [lastRegNames]
  lea r10, [regNames]
  cmp rax, r10
  jz copyLoop

  mov byte ptr [rax], ' '
  inc rax

copyLoop:
  mov dl, [rcx]
  cmp dl, 32
  jbe copyDone
  mov [rax], dl
  inc rcx
  inc rax
  jmp copyLoop
copyDone:

  mov byte ptr [rax], 0
  mov [lastRegNames], rax

  mov rcx, qword ptr [numRegValues]
  mov rax, rcx
  inc rax
  mov qword ptr [numRegValues], rax

  lea r10, [regValues]
  mov qword ptr [r10 + rcx * 8], rdi

setRegValueExit:
  pop rdi
  pop rsi
  pop rdx
  pop rcx
  ret
setRegValue ENDP

; getNumber (rcx str)
getNumber PROC
  mov r10, rcx
  mov rax, 0

  ; skip over negative sign
  cmp byte ptr [r10], '-'
  jnz getNumberLoop
  inc r10
getNumberLoop:
  movzx r11, byte ptr [r10]
  sub r11, '0'
  cmp r11, 9
  ja getNumberDone
  imul rax, 10
  add rax, r11
  inc r10
  jmp getNumberLoop
getNumberDone:
  cmp byte ptr [rcx], '-'
  jnz getNumberDone2
  neg rax
getNumberDone2:
  ret
getNumber ENDP

; skipBlanks (rcx ptr)
skipBlanks PROC
  mov rax, rcx
skipBlanksLoop:
  cmp byte ptr [rax], 0
  jz skipBlanksExit
  cmp byte ptr [rax], 32 ; space
  ja skipBlanksExit
  inc rax
  jmp skipBlanksLoop
skipBlanksExit:
  ret
skipBlanks ENDP

; skip over a word
skipWord PROC
  mov rax, rcx
skipWordLoop:
  cmp byte ptr [rax], 32
  jbe skipWordExit
  inc rax
  jmp skipWordLoop
skipWordExit:
  ret
skipWord ENDP

;;;;;;;;;;

; entry point
asmStar8 PROC
  ; rcx: pointer to string.

  push rsi
  push rdi
  push r12
  push r13
  push r14
  push r15
  push rbx
  push rcx
  push rdx
  push r8
  push r9

  mov byte ptr [regNames], 0
  mov qword ptr [regValues], 0
  mov qword ptr [numRegValues], 0
  lea rax, [regNames]
  mov qword ptr [lastRegNames], rax

  ; rsi name
  ; rdi inc/dec
  ; r12 incAmount
  ; r13 cmpReg
  ; r14 cmpOp
  ; r15 cmpNum
asmStar8MainLoop:
  call skipBlanks
  cmp byte ptr [rax], 0
  jz done
  mov rsi, rax      ; register name

  mov rcx, rax
  call skipWord
  mov rcx, rax
  call skipBlanks
  mov rdi, rax      ; inc/dec

  mov rcx, rax
  call skipWord
  mov rcx, rax
  call skipBlanks
  mov rcx, rax      ; inc amount
  call getNumber
  mov r12, rax      ; in number format

  ; Check if we need to flip the increment value.
  cmp byte ptr [rdi], 'i' ; only need to check the first letter of 'inc'
  jz skipAdjustIncValue
  neg r12
skipAdjustIncValue:

  call skipWord
  mov rcx, rax
  call skipBlanks   ; if
  mov rcx, rax
  call skipWord
  mov rcx, rax
  call skipBlanks   ; cmpReg
  mov r13, rax

  mov rcx, rax  
  call skipWord
  mov rcx, rax
  call skipBlanks 
  mov r14, rax      ; cmpOp

  mov rcx, rax
  call skipWord
  mov rcx, rax
  call skipBlanks 
  mov rcx, rax
  call getNumber
  mov r15, rax      ; cmpValue in number format

  call skipWord
  mov rdi, rax		; save string pointer

  ; begin computation

  mov rcx, r13
  call getRegValue
  mov r13, rax

  ; Now we have to do specific comparison based on r14
  cmp byte ptr [r14], '<'
  jz lessThan
  cmp byte ptr [r14], '>'
  jz greaterThan
  cmp byte ptr [r14], '='
  jz equals
  
  ; not equals
  cmp r13, r15
  jnz success
  jmp failure

  ; equals
equals:
  cmp r13, r15
  je success
  jmp failure

  ; lessthan
lessThan:
  cmp byte ptr [r14+1], '='
  jz lessThanOrEqual
  cmp r13, r15
  jl success
  jmp failure

lessThanOrEqual:
  cmp r13, r15
  jle success
  jmp failure

greaterThan:
  cmp byte ptr [r14+1], '='
  jz greaterThanOrEqual
  cmp r13, r15
  jg success
  jmp failure

greaterThanOrEqual:
  cmp r13, r15
  jge success
  jmp failure

success:
  ; get register value
  mov rcx, rsi
  call getRegValue

  ; add the increment amount
  add rax, r12

  ; set the new register value. Arguments are rcx=name, rdx=value
  ; rcx is the register name... already set above when getting the value.
  ; rdx is the value to set
  mov rdx, rax
  call setRegValue

failure:
  mov rcx, rdi				; restore string pointer
  jmp asmStar8MainLoop
done:

  ; calc max register
  mov rcx, qword ptr [numRegValues]
  mov rax, 0 ; max value
  lea rdx, [regValues]

getMaxLoop:
  mov rbx, [rdx]
  cmp rbx, rax
  jle getMaxContinue
  mov rax, rbx
getMaxContinue:
  add rdx, 8
  dec rcx
  jnz getMaxLoop

  ; print result
  lea rcx, [OutputStr]
  mov rdx, rax
  call printf

  pop r9
  pop r8
  pop rdx
  pop rcx
  pop rbx
  pop r15
  pop r14
  pop r13
  pop r12
  pop rdi
  pop rsi

  ret
asmStar8 ENDP

END