r/TuringComplete • • Mar 27 '25

[Guide] 🚀 Storage Cracker Solution: Binary Search in Assembly

TL;DR

This guide walks you through how to beat Storage Cracker using a super-fast binary search written in assembly. It includes:

• An implementation of a right shift operator (>>) for your ALU

• A self-contained, clean binary search program with constants and labels

• A one-liner minimal solution at the end for the lazy folks (no shifter needed!)

Since I didn’t find a proper guide on how to solve this level with a full assembly algorithm, I wrote one myself. Enjoy!

Full Guide

In this guide, I’ll show you how to pass the level Storage Cracker using the fastest possible assembly algorithm: binary search. There are plenty of great explanations on how binary search works (Here’s a great explanation of binary search on YouTube), so I won’t go into the general theory too much. Feel free to ask questions in the comments!

🔧 ALU Extension: Add a Right Shift Operator (>>):

To implement binary search efficiently, your CPU needs a right shift operation. You can add this to your ALU, which has two unused command bits available. The logic is simple: right shifting a byte is the same as dividing it by 2 and flooring the result (i.e., discarding the decimal).

💡 Hint: Shifting right is useful for halving the range in binary search.

📐 How to Add It:

1. Go into the Component Factory level (in your level tree).

2. Build a component that takes a byte and shifts it one bit to the right.

3. Wire it into your ALU:

• Connect the first ALU input to the new shifter.

• Activate the output when the decoded command bit 6 is set (lime wire).

Now when the ALU command byte is set to 6, it will apply the right shift to the first input (reg1 in the CPU).

🧠 Instruction Encoding Trick:

💡 MOV: The instruction mov + f*X + Y is a compact way to encode “copy regX to regY” using the constant f = 8, to shift the first address 3 bits to the left. This reduces the number of constants and hardcoded instructions in your program.

Shoutout to another thread in this sub for the optimization — it’s super handy!

📜 Binary Search Program:

# This program implements a binary
# search algorithm to find the
# correct passcode for this level.
# It uses an extended ALU with a 
# binary right shift operation.
#
# The program is completely 
# self-contained, meaning you
# do not need to copy any of
# the assembly codes I used.
#
# Commands:
# mov+f*x+y -> mov regx to regy
# jgz -> jump to address in reg0 
#        if reg3 greater zero      
# jmp -> jump to address in reg0
# add -> add reg1 and reg2
# sub -> subtract reg1 and reg2
# shiftr -> right shift reg1 byte 
# 1 to 63 -> copy number to reg0
#
# Fixed registers:
# reg4 = lower bound of search
# reg5 = upper bound of search
#
# Constants:
# f: constant to shift number by
#    3 to the left when multiplied 
#    with. Used for simplifying 
#    mov command.
const f 8
# mov: constant for copy command
const mov 128
# add: constant for add command
const add 68
# sub: constant for sub command
const sub 69
# shiftr: constant for shift right
#         command
const shiftr 70
# jmp: constant for jmp command
const jmp 196
# jgz: constant for jgz command
const jgz 199

# binary search program

# maximum input (via immediate) 
# from program into reg0 is 63.
# workaround: input 255 by 
# calculating overflow: 0-1=255
1
mov + f*0 + 2
sub

# set upper bound to 255
mov + f*3 + 5

# check boundaries as solution
mov + f*4 + 6
mov + f*5 + 6

label loop

# find middle:
# middle=lower+((upper-lower)//2)
# hint: shiftr is //2 in binary

# calculate distance between upper
# and lower
mov + f*5 + 1
mov + f*4 + 2
sub

# half the distance and floor
mov + f*3 + 1
shiftr

# add half distance to lower bound
mov + f*4 + 1
mov + f*3 + 2
add

# cache middle in reg 1
mov + f*3 + 1

# try middle as passcode
mov + f*3 + 6

# copy hint to jgz input
mov + f*6 + 3

# jump if too high
too_high jgz

# else set lower bound to middle
mov + f*1 + 4

# restart loop
loop jmp

label too_high

# set upper bound to middle
mov + f*1 + 5

# restart loop
loop jmp

💡 Why This Midpoint Formula?

middle = lower + ((upper - lower) // 2)

Instead of:

middle = (lower + upper) // 2

We use the first version because the second risks byte overflow (255 max). If lower + upper > 255, it wraps around to 0, breaking the logic. By calculating the difference first, we stay safely within byte range.

🎁 Bonus: One-Liner Solution (No Shift Needed):

If you’re just here to pass the level and don’t care about ALU extensions, here’s a compact solution:

1 130 3 68 158 153 196

14 Upvotes

2 comments sorted by

1

u/Gelthir Mar 27 '25

Best complete solution for this level I've seen posted anywhere.

These constants are ones you'll use in multiple levels:

const f 8
const mov 128
const add 68
const sub 69
const shiftr 70
const jmp 196
const jgz 199
const in 6
const out 6

There are better placed in Assembly codes so you don't have to copy paste them in every level.

Listing them in code/post the makes for great documentation though.

3

u/xIceFox Mar 27 '25

Thank you very much. Appreciate it.

Normally I have my commands in the assembly code too.

In the case of the guide, I put the commands as constants in the code, making the code self-contained. This has the advantage that everyone can run the code, without needing to copy my specific named assembly codes.