diff --git a/2022/README.md b/2022/README.md
index 808f8f35329a00548061c885ebb79fd325865642..2398981145cea24518a7a15f1119aecb6d200520 100644
--- a/2022/README.md
+++ b/2022/README.md
@@ -51,7 +51,7 @@ Seems pretty straight-forward.
 ### Refactoring opportunity
 
 Parts 1 & 2 differ in whether we determine the outcome based off of "my" hand, or whether we determine "my" hand based 
-o ff of the outcome.
+off of the outcome.
 Where we parameterized the commonality on Day 1, today we'll simply extract the commonality into a helper method.
 
 ## Day 3
@@ -119,5 +119,40 @@ No, the thing to do is to extract the common part out into a helper method.
 
 ## Day 5
 
+- [The problem](https://adventofcode.com/2022/day/5)
+- [The solution](src/main/java/edu/unl/cse/bohn/year2022/Day5.java)
+
+We've hit the first puzzle whose input will require a little creativity when parsing.
+
+### Part 1
+
+The subproblems are
+- Separate the initial conditions from the subsequent instructions
+  - Assume there is exactly one blank line between them
+- Represent the stacks
+  - At the risk of diving into the solution space, *obviously* we'll do this with a list of stacks
+  - Determine how many stacks there are
+    - Assume that the last line of the initial conditions is the stack numbers, beginning with ' ' followed by a '1'
+    - Assume the stack numbers are in-order (*i.e.*, the last index tells us how many there are)
+    - Can we assume there are only a single-digit number of stacks?
+  - Assume all crates are of the form "[?]"
+    - Part of that is an assumption that a crate can be represented with a single character -- and I'm going to further 
+      assume it's not ' '
+  - Assume an empty space atop a stack is of the form "   "
+  - Assume exactly one space between stacks
+- Follow the instructions
+  - The regular format of the instructions will make them easy to parse
+  - (Solution space) pop/push will be easy
+- Output the top of each stack, in order
+
+Why do I have the feeling that there'll be some version of 
+[The Towers of Hanoi](https://en.wikipedia.org/wiki/Tower_of_Hanoi) before we're done?
+
+### Part 2
+
+### Refactoring opportunity
+
+## Day 6
+
 (coming soon)
 
diff --git a/2022/src/main/java/edu/unl/cse/bohn/year2022/Day5.java b/2022/src/main/java/edu/unl/cse/bohn/year2022/Day5.java
new file mode 100644
index 0000000000000000000000000000000000000000..dfa5b323da06bd2d413062861fae78c2fae76f61
--- /dev/null
+++ b/2022/src/main/java/edu/unl/cse/bohn/year2022/Day5.java
@@ -0,0 +1,95 @@
+package edu.unl.cse.bohn.year2022;
+
+import edu.unl.cse.bohn.Puzzle;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Stack;
+
+@SuppressWarnings("unused")
+public class Day5 extends Puzzle {
+    public Day5(boolean isProductionReady) {
+        super(isProductionReady);
+        //noinspection EscapedSpace
+        sampleData = """
+                \s   [D]   \s
+                [N] [C]   \s
+                [Z] [M] [P]
+                 1   2   3\s
+                                
+                move 1 from 2 to 1
+                move 3 from 1 to 3
+                move 2 from 2 to 1
+                move 1 from 1 to 2""";
+    }
+
+    @Override
+    public long computePart1(List<String> data) {
+        List<Stack<Character>> stacks = createStacks(data);
+        rearrangeCrates(stacks, data);
+        String topsOfStacks = getTopsOfStacks(stacks);
+        System.out.println("Crates at the top of the stacks: " + topsOfStacks);
+        return 0;
+    }
+
+    @Override
+    public long computePart2(List<String> data) {
+        return 0;
+    }
+
+    private List<Stack<Character>> createStacks(List<String> data) {
+        Integer rowWithIndices = null;
+        int i = 0;
+        while (rowWithIndices == null) {
+            if (data.get(i).startsWith(" 1")) {
+                rowWithIndices = i;
+            }
+            i++;
+        }
+        String[] indexStrings = data.get(rowWithIndices).strip().split(" ");
+        int numberOfStacks = Integer.parseInt(indexStrings[indexStrings.length - 1]);
+        List<Stack<Character>> stacks = new ArrayList<>(numberOfStacks);
+        for (i = 0; i < numberOfStacks; i++) {
+            stacks.add(new Stack<>());
+        }
+        for (i = rowWithIndices - 1; i >= 0; i--) {
+            for (int stack = 0; stack < numberOfStacks; stack++) {
+                char crate = data.get(i).charAt(4 * stack + 1);
+                if (crate != ' ') {
+                    stacks.get(stack).push(crate);
+                }
+            }
+        }
+        return Collections.unmodifiableList(stacks);
+    }
+
+    private void rearrangeCrates(List<Stack<Character>> stacks, List<String> data) {
+        for (String instruction : data) {
+            if (instruction.startsWith("move")) {   // then it really is an instruction
+                String[] tokens = instruction.strip().split(" ");
+                int numberOfCratesToMove = Integer.parseInt(tokens[1]);
+                for (int i = 0; i < numberOfCratesToMove; i++) {
+                    int source = Integer.parseInt(tokens[3]) - 1;       // -1 because the original stacks were 1-indexed
+                    int destination = Integer.parseInt(tokens[5]) - 1;
+                    char crate = stacks.get(source).pop();
+                    stacks.get(destination).push(crate);
+                }
+            }
+        }
+    }
+
+    private String getTopsOfStacks(List<Stack<Character>> stacks) {
+        StringBuilder stringBuilder = new StringBuilder();
+        for (Stack<Character> stack : stacks) {
+            if (stack.empty()) {
+                stringBuilder.append(' ');          // this isn't in the spec, but we'll go with it for now
+            } else {
+                Character crate = stack.pop();
+                stack.push(crate);                  // leave it the way we found it
+                stringBuilder.append(crate);
+            }
+        }
+        return stringBuilder.toString();
+    }
+}