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

Reply via email to