This challenge turned from tricky to messy, and I'm in a bit of a pickle: I'm no longer sure what the shortest solution is. I think, though, that the challenge isn't over. There might be a solution of 6 or 7 commands, besting Jay's 8.
Bear with me, if you're patient.
The challenge was meant to not be about writing a solution program. But, rather, writing a program that will find the solution program.
That is, if you took the second approach of two approaches I saw:
Two approaches:
- Path of Admirable Intuition
- Brute Force
My basic assumption of the solution template to necessarily look like this
stringToStack instruction1..instructionN stackToString
where
instructionX: number ROLL
stringToStack: STR-> (check)
stackToString: needs "" (check) + bunch of string concatenations (+), " " (check), and SWAP (missing)
SWAP: 2 ROLL (check)
was proven wrong by Jay's solution, which meshes the ROLLs with building up the result string from the stack.
Here's my development of the brute force approach. It's invalidated to find *the* solution now that my assumed template is known to be not the shortest. But it may be re-tooled to either find a shorter solution OR prove that there are no shorter solutions.
Brute force: write an RPL program that writes all possible RPL programs (within our constraints) and test which ones, when applied to the input string, will yield the output string.
(ROLL was meant to be but one "shuffle" function that, when applied a few times would be non-linear/head-spinning enough to have people give up on finding a "manual" solution.)
Note, the challenge said nothing about constraints to a program that would be used to "come up" with the solution program. So you can use all RPL commands for former. (One of the twists...)
There's 6 chars in the string which will end up on the stack. That is, there's a max of 6 sensical ROLLs: 1 ROLL, 2 ROLL, 3 ROLL, 4 ROLL, 5 ROLL, 6 ROLL.
As no same-arg ROLLs are allowed -> 6 6 PERM (=720) possible programs.
One instruction is a no-op: 1 ROLL -> 5 5 PERM (=120) possible programs.
It's unknown how many instructionX we'll have. Except: it cannot be more than 11 (known number of instructions for a solution) minus 1 (STR->) minus # commands to implement stackToString.
We can write stackToString. Let's.
Given 6 numbers on the stack, we need five concatenations, of numbers and spaces.
stackToString: "" + " " + 2 ROLL + " " + 2 ROLL + " " + 2 ROLL + " " + 2 ROLL + " " + 2 ROLL +
# commands to implement stackToString: 5
-> upper limit for N: 11 - 1 - 5 -> 5
That is, as per challenge wording, a max of 5 ROLLs is needed. That matches the combinatorial complexity, and doesn't simplify things. But, reading between lines, "program using the smallest number of commands wins" suggests a solution with a lesser number of ROLLs exists. Since we cannot save on any other instructions (OR SO I THOUGHT), it's implied that <= 4 ROLLs are needed.
5 4 PERM (=120) possible programs
Let's implement a program generator:
\<< { 2 3 4 5 6 } permutate @ produce all non-no-op permutations of possible ROLL args
DUP SIZE V\-> DROP 4 \->V2 RDM @ reduce to 4 picks
1
\<<
"" SWAP
1
\<< + " ROLL " + \>> @ assemble RPL program, precede each ROLL with element
DOSUBS @ iterate over elements of each permutation
keepIfSolution @ test program; keep on stack (->DOSUBS will roll into result array) if it's a solution
\>>
DOSUBS @ iterate over permutations
\>>
permutate: your favorite implementation that will produce an array of permutations, given an array
And a program tester:
keepIfSolution:
\<< \-> prg \<<
X STR\-> @ unpack input string to stack
prog STR\-> @ unpack and execute (!) ROLL instructions
"" + " " + 2 ROLL + " " + 2 ROLL + " " + 2 ROLL + " " + 2 ROLL + " " + 2 ROLL +
Y == @ compare against desired result string
prg IFT @ keep ROLL instruction string, if match (implied drop, otherwise)
\>> \>>
X: input string
Y: desired output string
Run, and 2.6s later (on ND1), a single solution is found: "5 ROLL 3 ROLL 2 ROLL 6 ROLL"
Can we do better?
Change this
DUP SIZE V\-> DROP 4 \->V2 RDM @ reduce to 4 picks
to
DUP SIZE V\-> DROP 3 \->V2 RDM @ reduce to 3 picks
Run, and get another single solution: "2 ROLL 5 ROLL 6 ROLL"
That is, the shortest challenge solution program (UNDER THE ASSUMED TEMPLATE) is:
\<< STR->
2 ROLL 5 ROLL 6 ROLL
"" + " " + 2 ROLL + " " + 2 ROLL + " " + 2 ROLL + " " + 2 ROLL + " " + 2 ROLL +
\>>
9 commands, as per (odd) challenge definition of "command".
Note, STR-> is used to execute an RPL program that was written on-the-fly. I discovered this feature of STR-> only the other day. I found it so… arbitrary. But inspiring, too, to try and construct a challenge around it. (Btw, one can get the same effect with OBJ-> or LIST->, which seem far more canonical than STR-> for arbitrary command execution.)
The "Path of Admirable Intuition" was a no-go for me, but the solution offered a "Path of Knowing in Hindsight":
Play through how 2 ROLL, 5 ROLL, 6 ROLL work on the input.
Given the (deceptive) proximity of the input and desired output strings, it transpires that if someone had the intuition that
- the solution string will be built up in reverse
- the *reverse* of the solution is very close after doing one SWAP
they could possibly find the solution in seconds.
I find it hard to visualize more than one overlapping ROLL, let alone trying to aim for a solution in reverse.
Anyway. I'm not quite sure how Jay found the solution. If repeated application of overlapping ROLLs was linear enough to "just do it" (without a headache), my challenge failed to pose a challenge to finding *a* solution. But is it the best or only solution?
Can someone deliver a proof?
I'll report on my re-tooling to assume a new template but keeping the brute force approach.
Edited: 14 Mar 2011, 7:09 a.m.