I won't lie, first I wrote that solution in Python. It's much easier and
faster. Then the program was translated to J. The biggest problem was that
J didn't have dictionaries. While even K has! And sparse arrays don't
support strings or boxed values. Argh. And we are at the end of year 2016!
Anyway, we deal with small numbers, it's quite suitable to grow an array
when we need to insert some value there with an index a bit greater than
the length of the array. We could also allocate some big arrays, or just
bigger than input, or to calculate the sizes based on the input. Well, it's
possible, yes. But pretending to deal with dictionaries looks more pleasant
to me. So it was finally, the J solution for Day 10.
t =: cutLF CR-.~fread '10.dat'
'E O B' =: 0 0 1 NB. empty value; what:Output, what:Bot
b =: 0 6$0 NB. i-th bot: [lo-what lo-index hi-what hi-index slot1 slot2]
o =: i.0 NB. outputs, empty vector at first
NB. first we build the bot net
3 : 0 t
for_s. y do. s =. ' 'cut >s
if. -. 'bot'-:>{.s do. continue. end. NB. do only bots
'k lk hk' =.".>1 6 11{s NB. all numbers from string
lo=.('bot'-:> 5{s){O,B
hi=.('bot'-:>10{s){O,B
if. k>:#b do. b =: b,((>:k-#b),{:$b)$0 end. NB. expand b if needed
b =: (lo,lk,hi,hk,E,E) k}b
end.
)
pv =: 4 : 0 NB. pass value; x - value to set, y - pair what,index
k=.{:y
if. O={.y do. NB. output, set value in o
if. k>:#o do. o =: o,(>:k-#o)$E end. NB. expand o if needed
if. E~:k{o do. exit#echo 'output already set ',"k,k{o end.
o =: x k}o
else. NB. B - bot, set 1st slot, or 2nd slot and then propagate value
if. k>:#b do. exit#echo 'no such bot ',":k end.
'lw lx hw hx s1 s2' =. k{b
if. s1=E do. NB. both slots are empty, let's set the 1st
b =: x (<k,4)}b
else.
if. s2~:E do. exit#echo 'no empty slot ',":k,v,s1,s2 end.
b =: x (<k,5)}b
lv =. x <. s1
hv =. x >. s1
if. 17 61 -: lv,hv do. echo k end. NB. part 1: catch what was asked!
lv pv 0 1{k{b
hv pv 2 3{k{b
end.
end.
)
NB. then we spread values
3 : 0 t
for_s. y do. s =. ' 'cut >s
if. -. 'value'-:>{.s do. continue. end. NB. process only values
v pv B,k [ 'v k' =.".>1 5{s
end.
)
echo */0 1 2{o NB. part 2: multiply outputs
exit 0
It's rather long, but easy to understand, I hope. If you remove comments
and rearrange some pieces of code, it'll be down to 720+ chars and will fit
one screen.
The idea of the solution was first to build the whole network of bots, i.e.
to have them all with their connections to other bots, but without any real
values yet; then we start to put values to the bots and propagate those
values to other bots and to the output. Usually the puzzles of AoC allow
such simple solutions - all the data is correct, no conflicts, no races in
schemes, all will be perfect in the end. So such a solution works.
Then it comes the challenge -- to make it all J-style, all tacit and magic
:)
Well, there's still left one explicit definition, I guess it would've been
too complicated if it was tacit.
The basic ideas are the same, to build the bot net and put the values
there. On the second stage the reduce is used. J doesn't allow arbitrary
types for '/' or an initial/state value of different type, but here boxes
come to the rescue - we can put anything in the boxes and work with them as
with simple values.
t =: cutLF CR-.~fread '10.dat'
NB. verbs -----------------------------------
onlybots =: #~ ('bot'-:3{.>)"0
onlyvals =: #~ ('val'-:3{.>)"0
parsebot =: [:".[:>1 4 5 8 9{[:cut('to output';'0';'to bot';'1')rplc~>
parseval =: [:<[:".[:>1 5{[:cut >
val2out =: ([:{.])`([:<_1,5<.[:{:])`[ } NB. save value to output = last
bots item
val2slot1 =: ([:{.])`([:<4,~[:{:])`[ }
val2slot2 =: 4 : 0
if. 17 61 -: lh=./:~ ({.y),4{(k=.{:y){x do. echo {:y end. NB. part 1
answer
((({.y)(<k,5)}x)pv({.lh),0 1{k{x)pv({:lh),2 3{k{x NB. set slot2 and pass
both values
)
val2bot =: val2slot2`val2slot1 @. (0=4{([:{:]){[) NB. choose slot
pv =: val2out`val2bot @.(1{]) NB. pass value
av =: [:< ([:>]) pv 1j1 1#!.1[:>[ NB. apply value to bots
NB. nouns -----------------------------------
bots =: (0 0,~}.)"1 /:~ parsebot"0 onlybots t NB. get all bots from input
vals =: parseval"0 onlyvals t NB. get all vaules
echo */3{.{:> av/ |.(bots,0);vals NB. apply values to bots;
part 2 output
exit 0
I don't know if it's really readable. Anyway it works.
Enjoy :)
P.S. what was interesting there: v1`v2 @. vt, v1`v2`v3 }, / over boxes, AjB
#!.C.
Georgiy Pruss
----------------------------------------------------------------------
For information about J forums see http://www.jsoftware.com/forums.htm