bash -funroll-loops

For no reason at all, please enjoy a fun* number-guessing game written without loops or functions. There’s a simpler way to write this self-modifying loop-unrolling thing if your only goal is to execute correctly but I thought it would be cooler* if the script ended up containing a transcript of all guesses.

Note that the script relies on coreutils truncate to reset itself on every launch. If you’re on a Mac and desperate to play this outstanding game you can install a suitable equivalent with Homebrew: brew install truncate.

#!/bin/bash
script_name=$0
target=$(($RANDOM % 100 + 1))
truncate "$script_name" -s 583
echo "Guess the number between 1 and 100:"
GUESS=$(cat << END_GUESS
read guess
if (( guess > target )); then
    echo "echo '\$guess is too high!'" >> "\$script_name"
    echo "\$GUESS" >> "\$script_name"
elif (( guess < target )); then
    echo "echo '\$guess is too low!'" >> "\$script_name"
    echo "\$GUESS" >> "\$script_name"
else
    echo "echo 'You got it! The number was \$target.'" >> "\$script_name"
    echo "exit 0" >> "\$script_name"
fi
END_GUESS
)
echo "$GUESS" >> "$script_name"

Let’s have a playthrough:

$ ./guess.sh
Guess the number between 1 and 100:
50
50 is too low!
60
60 is too low!
90
90 is too high!
75
75 is too high!
63
63 is too low!
68
68 is too high!
66
66 is too low!
67
You got it! The number was 67.

I will grant that using a looping interpreter and saying “look no loops!” is a little misguided. That said, it’s turtles all the way down. You could write a similar self-modifying binary in machine code. There, the “EIP += (instruction size) && execute” loop just happens to be implemented in hardware so it’s kind of invisible.

* Adjectives in this post should not be taken seriously.
P.S. The cheat code is any floating point number.
P.P.S. You can play in hexadecimal if you want with the 0x prefix.