I've got this solved now, Eugene Nonko put me on the right path here.
The trick, from my perspective, was to convert the machine code into executable J. And, to ensure that I could use J's dimensionality to manage multiple tests at the same time. Specifically, I parameterized the three "block specific" values as C, B and A (I initially used D for digits, but later spelled that out). parse=: {{ blks=: _18]\];._2 input C=: ". 6}."1]4 {"_1 blks B=: ". 6}."1]5 {"_1 blks A=: ". 6}."1]_3{"_1 blks }} digits=:14#<1+i.9 BLOCK=: {{ W=: x{::digits X7=: W~:/(x{B)+26|y if.X7 -:&$ y do. ((W+x{A)*X7)+(1+25*X7)*<.y%x{C else. ((W+x{A)*X7)+(1+25*X7)*"_1 _<.y%x{C end. }} Here, x indicated the digit number (0 for the leftmost digit, 13 for the right most digit), and y indicated the result from the previous block (0 initially). The if statement was because I could not figure out how to build a rank statement that worked consistently for all of my example cases. I'm not sure if this was due to my limited imagination, or if it's an artifact of J's rank conjunction. Maybe I'll circle back on that later... With this in place, the ALU became: ALU=: BLOCK/@((i.-14),0) Except, of course, my laptop is not powerful enough to handle this expression because there's too many possible digits. But it's rather quick to run through all the possibilities to constrain the search space: plausible=: {{ hist=:<need=:,0 for_k.i.-14 do. try=. ~.(<.need%26),,(26*need)+/i.26 need=. ~.;((k BLOCK try)e.need)<@#try assert.1e8>#need assert.0<#need hist=:(<need),hist end. trial=: {{(y BLOCK y{::hist) <@(#&(y{::digits))@:(+./"1)@:e. (y+1){::hist}} ref=:digits=:trial"0 i.14 }} And, once I had that, it was straightforward to find the largest viable serial number: a24=: {{ digits=:14#<1+i.9 plausible'' i=. #@>digits k1=.+/7>10^.*/\.i k0=.14-k1 for_j.(k0{.i)#:i.-*/k0{.i do. NB. echo ;j {&.> k0{.ref digits=: (j {&.> k0{.ref) (i.k0)} digits t=: |:ALU'' if.0 e.,t do. ' '-.~":;(k0{.digits),(($t)#:>./I.,0=t){each k0}.digits return. end. end. }} timespacex 'a24 0' 2.26213 1.59913e8 Part b was to find the smallest viable serial number, and for that, I got rid of the negative in the for loop: for_j.(k0{.i)#:i.*/k0{.i do. And changed the max reduce to a min reduce in the result line: ' '-.~":;(k0{.digits),(($t)#:<./I.,0=t){each k0}.digits return. And that also ran quickly for me: timespacex 'b24 0' 0.252415 1.59913e8 (But... caution: actual running time will depend on the puzzle input you're working with. I am not sure how much of my running time here is luck and how much is decent approach.) I am somewhat disappointed that it took me so long to see some of the (now) obvious features of this puzzle. But... I have to admit some of my other efforts were at least kind of fun. Thanks, -- Raul ---------------------------------------------------------------------- For information about J forums see http://www.jsoftware.com/forums.htm