Run it with set -x to see what the shell actually runs, the commands are shown in the lines starting with + :
+ printf 'Guess the number (1-10) : '
Guess the number (1-10) : + read -r n
+ '[' 'randint=$((' '(' RANDOM % 10 ')' + 1 '))' = ']'
bash: line 4: [: too many arguments
[...]
What's that in the test, inside [ ... ], the assignment randint=...(*)? It was supposed to be what read n gives. And it was supposed to ask the number from the user, but didn't?
Well, there's the thing, read reads from standard input, and in the pipeline base64 ... | bash the script that the shell runs also comes from standard input. So read dutifully reads the next line in the input stream, the one with randint=..., and puts it in the variable n...
(* $n is word-split to multiple arguments, of course, since $n was not quoted.)
You need to arrange for the script to come in from a different file descriptor, either by e.g. using process substitution to pass the script to the shell (in Bash/ksh/zsh):
bash <( base64 -d <<< "$exec" )
or by having read read from some other fd, e.g. directly from the terminal by redirecting the input to read from /dev/tty. Testing with an almost one-liner (the single-quoted string continues to the second line):
$ printf 'read -r -p "say something: " foo < /dev/tty;
echo "you entered: $foo"' | bash
say something: asdfsadf
you entered: asdfsadf
Then again, you might consider just passing input data as command line arguments, instead of interactively asking for it. Command line arguments are easier to script, and reading the terminal directly is also especially obnoxious, precisely because it prevents easily using a script to feed the program.
Note also that RANDOM isn't a standard shell feature, so you should probably run the script explicitly with bash (or ksh, or zsh), and not sh.
if. and use-eqwhen compare numbersshandbashare not equivalent.readis trying to read from the same stream that the script is being read from, I think...bash <( base64 -d <<<string )But I fail to see the point of the exercise.