Problem Solving

Common Patterns & Idioms

The reusable building blocks you'll combine to solve any LC-3 problem.

Why Patterns Matter

You know what ADD, AND, NOT, LD, ST, LEA, LDR, STR, and BR do individually. But when you face a problem like "check if a string is a palindrome," it's hard to know where to start.

The secret: every LC-3 program is built from a small set of patterns. Once you recognize them, complex programs become a matter of snapping pieces together.

Pattern 1: Clear and Initialize a Register

Almost every program starts by clearing registers and loading initial values.

; Clear a register to 0
AND R0, R0, #0        ; R0 = 0

; Set to a small value (-16 to 15)
AND R1, R1, #0
ADD R1, R1, #7        ; R1 = 7

; Set to a larger value (build it up)
AND R2, R2, #0
ADD R2, R2, #15       ; 15
ADD R2, R2, #15       ; 30
ADD R2, R2, #2        ; 32 (ASCII space)

; Load a value from memory (any size)
LD R3, MY_VALUE       ; R3 = whatever is at MY_VALUE
When to use which: Use ADD #imm for values -16 to 15. For larger constants, either chain multiple ADDs or store the value in memory with .FILL and use LD. Memory is cleaner for values like ASCII codes or addresses.

Pattern 2: Copy a Register

You often need the same value in two places. There is no MOV instruction — use ADD with 0.

; Copy R0 into R1
ADD R1, R0, #0        ; R1 = R0 + 0 = R0

Pattern 3: Compare Two Values

This is the most important pattern for problem solving. The LC-3 has no CMP instruction — you compare by subtracting and checking the condition codes.

; Are R0 and R1 equal?
; Strategy: compute R0 - R1, check if zero
NOT R2, R1
ADD R2, R2, #1        ; R2 = -R1
ADD R2, R0, R2        ; R2 = R0 - R1
BRz THEY_ARE_EQUAL    ; branch if R0 == R1
; ... they are not equal ...

; Is R0 > R1?
; Same subtraction, but check positive
NOT R2, R1
ADD R2, R2, #1
ADD R2, R0, R2        ; R2 = R0 - R1
BRp R0_IS_GREATER     ; branch if R0 > R1

; Is R0 a specific value (e.g., ASCII space = 32)?
; Strategy: subtract the constant and check zero
LD R2, NEG_SPACE      ; R2 = -32
ADD R2, R0, R2        ; R2 = R0 - 32
BRz ITS_A_SPACE       ; branch if R0 == 32
; ...
NEG_SPACE .FILL #-32

Subtraction destroys a value! NOT R1, R1 / ADD R1, R1, #1 overwrites R1. If you need R1 later, do the subtraction into a temporary register instead, or save R1 first.

Pattern 4: Walk Through a String or Array

Use a pointer register and LDR to visit each element.

; Walk a null-terminated string
LEA R1, STR           ; R1 = pointer to first character
LOOP
LDR R0, R1, #0        ; R0 = current character
BRz DONE              ; null terminator? stop
; ... do something with R0 ...
ADD R1, R1, #1        ; advance pointer
BR LOOP
DONE

Pattern 5: Two-Pointer Technique

Many string/array problems use two pointers that move toward each other. This is exactly what palindrome, reverse, and similar problems need.

; R1 = left pointer (start of data)
; R3 = right pointer (end of data)
;
; Loop while R1 < R3:
TWO_PTR_LOOP
  NOT R4, R1
  ADD R4, R4, #1
  ADD R4, R3, R4      ; R4 = R3 - R1
  BRnz DONE           ; if R3 <= R1, pointers crossed → stop

  LDR R0, R1, #0      ; load left element
  LDR R2, R3, #0      ; load right element
  ; ... compare or swap R0 and R2 ...

  ADD R1, R1, #1      ; left moves right
  ADD R3, R3, #-1     ; right moves left
  BR TWO_PTR_LOOP
DONE

Pattern 6: Find the End of a String

Before using a right pointer, you need to find where the string ends.

; R1 = start of string
; After this, R3 = pointer to last character
ADD R3, R1, #0        ; R3 starts at beginning
FIND_END
LDR R0, R3, #0        ; load character
BRz FOUND_END         ; null? we passed the end
ADD R3, R3, #1        ; keep going
BR FIND_END
FOUND_END
ADD R3, R3, #-1       ; back up to last real character

Pattern 7: Skip/Filter Characters

Need to skip spaces, ignore certain characters, or find the next vowel? Load, check, and conditionally advance.

; Skip spaces going forward (R1 = pointer)
SKIP_FWD
LDR R0, R1, #0            ; load character
LD R4, NEG_SPACE           ; R4 = -32
ADD R4, R0, R4             ; R4 = char - 32
BRnp NOT_SPACE_FWD         ; not a space? continue
ADD R1, R1, #1             ; skip it, advance
BR SKIP_FWD
NOT_SPACE_FWD
; R1 now points to a non-space character

; Skip spaces going backward (R3 = pointer)
SKIP_BACK
LDR R0, R3, #0
LD R4, NEG_SPACE
ADD R4, R0, R4
BRnp NOT_SPACE_BACK
ADD R3, R3, #-1
BR SKIP_BACK
NOT_SPACE_BACK

NEG_SPACE .FILL #-32

Pattern 8: Store a Result to Memory

Many projects ask you to put a result at a specific address (like x6000).

; Store R0 to a nearby label
ST R0, RESULT
RESULT .FILL #0

; Store R0 to a far-away address (like x6000)
STI R0, RESULT_PTR
RESULT_PTR .FILL x6000
ST vs STI: Use ST when the target is close (within ±256 of the PC). Use STI when the target is far away — STI follows a pointer, so you store the far address in a nearby .FILL.

Quick Reference: "I need to ___"

I need to...Use this pattern
Set a register to 0AND Rx, Rx, #0
Copy a registerADD Rdst, Rsrc, #0
Check if two values are equalSubtract, then BRz
Check if A > BSubtract (A - B), then BRp
Check if a character is a spaceSubtract 32, then BRz
Walk through a stringPointer + LDR + ADD ptr, ptr, #1
Find end of stringWalk until LDR gives null (BRz)
Use two pointersOne at start, one at end, move inward
Store result at far addressSTI with a .FILL pointer
Negate a valueNOT then ADD #1
Build a constant > 15Chain ADD #15 or use .FILL + LD
Quiz

You need to check if the character in R0 is the letter "A" (ASCII 65). What's the best approach?

Quiz

You have two pointers R1 (left) and R3 (right). How do you check if R1 has passed R3 (i.e., R1 >= R3)?