I definitely see the appeal of a recursive solution which avoids globals.

That said, I've been parsing enough really large files that I've
gotten into the habit of using globals for managing parsing state.
Plausibly a *bad* habit...

Here, I could have made the data dependencies explicit by passing
'pos' and 'vsum' as m and 'packet' as n, for example. This would have
made my result structures a bit messier, but maybe that would have
been ok?

Thanks,

-- 
Raul


On Tue, Jan 18, 2022 at 5:58 PM Jan-Pieter Jacobs
<janpieter.jac...@gmail.com> wrote:
>
> Hi, very interesting to read different takes on the problem!
>
> I made it recursive, passing around whatever remains of the bit string,
> with no use of global state (just some auxiliary verbs and the list of
> operations). A trick I was particularly happy with is combining the
> stopping condition on package numbers and max length in bits in a single
> check/loop.
>
> I copy-pasted most of the code of part A to part B and while they could be
> joined, I did not bother. Either way, the requirements of part A don't play
> nice with the set up for part B, as also the versions of the operator
> packets should be summed, while for part B, the operators don't have a
> corresponding value.
>
> As Stefan, I also thought of an FSM, but it would be highly cumbersome (if
> at all possible) to code it with the variable lengths involved. Using it
> only to parse the header (and perhaps length) was not worth the effort.
>
> For part B, the loop for parsing the operator packet constructs an array of
> operands; I simply put all operator operations in a gerund and apply by
> agenda.
>
> NB. Day 16: Packet decoder
> NB. bitstream from hex
> bfh =: [: ,@#: dfh"0
> i16=: }: in 16 NB. }: removes redundant LF
>
> NB. 6 byte header: version;type
> header =: _3 #.\ 6 {. ] NB. version , type
> NB. type 4 indicates literal value, having different groups. each group has
> 5 bits, if first bit is 0, last group. other 4 bits encode value. trailing
> 0's after last group to be ignored.
> NB. decode literal (type 4) body in y (no header)
> literal=: ([: #.@,[: }."1 ({.~ [: >: 0 i.~ {."1))@(_5]\])
>
> NB. part A: parse entire transmission, and find the sum of all version
> numbers
> NB. pp is a recursive verb parsing packages, returning the version sum
> pp =: {{
> NB. extract version/type
> 'ver typ'=. header  y
> if. typ=4 do. NB. literals
>   NB. count length based on 5 bit fields (groups)
>   NB. #groups depends on the first 0 encountered, which indicates the last
>   len=. 6+5*>:0 i.~ _5{.\ 6}.y
>   sovn=. ver NB. sum of version numbers is the version number
> else. NB. operator packets
>   NB. sum of version numbers, initialise with container's version.
>   sovn =. ver
>   NB. base : pointer to start of first packet
>   NB. 6b header;12 for length id (lid)+length+ (if lid=0) 4 extra bits.
>   base =. 6+12+4*-.lid=.6{y
>   NB. stopping condition, length in bits or packets, stored overwriting
> default _
>   stop =. (#.(11+4*-.lid) {. 7 }. y) lid} _ _
>   NB. nbp is number of bits and packets processed
>   nbp=.0 0
>   while. *./ nbp < stop do. NB. no lengths exceeded
>     NB. recurse, get sub-packets sum of versions and bit length
>     'vv ll'=. pp (base+{.nbp)}.y
>     sovn =. sovn + vv NB. add version number
>     NB. increase total length in bits by ll, and in packets by 1
>     nbp=. nbp + ll,1
>     NB. next packet starts after header and length indication
>   end.
>   NB. total length is the base length plus the total number of bits
>   len=. base+{.nbp
> end.
> sovn, len NB. return sum of versions and length
> }}
> a16=:{.@pp@bfh
> NB. part B, parsing the actual expression
> NB. gerund encoding operators
> NB. type 4 is literal value (placeholder ])
> NB. operator types 0  1  2   3   4 5  6  7 is
> NB.                +/ */ <./ >./ ] >/ </ =/
> ger=:(+/)`(*/)`(<./)`(>./)`]`(>/)`(</)`(=/)
> NB. packet parser++, takes packet y, returns value
> pppp =: {{
> NB. extract version/type
> 'ver typ'=. header y
> if. typ=4 do. NB. literals
>   NB. count length based on 5 bit fields (groups)
>   NB. #groups depends on the first 0 encountered, which indicates the last
>   len=. 6+5*>:0 i.~ _5{.\ 6}.y
>   val=.x: literal 6}.y
> else. NB. operator packets
>   NB. Array of operands
>   aoo =. 0$0
>   NB. base : pointer to start of first sub-packet
>   NB. 6b header;12 for length id (lid)+length+ (if lid=0) 4 extra bits.
>   base =. 6+12+4*-.lid=.6{y
>   NB. stopping condition, length in bits or packets, stored overwriting
> default _
>   stop =. (#.(11+4*-.lid) {. 7 }. y) lid} _ _
>   NB. nbp is number of bits and packets processed
>   nbp=.0 0
>   while. *./ nbp < stop do.
>     NB. recurse on remaining packet, find value and length
>     'vv ll'=. pppp (base+{.nbp)}.y
>     aoo =. aoo , vv NB. add value to operands
>     NB. next packet starts after header and length indication
>     nbp=. nbp + ll,1
>   end.
>   len=. base+{.nbp  NB. get final length
>   val=. ger@.typ aoo NB. apply appropriate verb.
> end.
> val, len
> }}
> b16=:{.@pppp@bfh
> (a16;b16)i16
>
> Jan-Pieter
>
>
> On Wed, Jan 12, 2022, 15:25 Raul Miller <rauldmil...@gmail.com> wrote:
>
> > I think you could use X ;: bits where bits is a sequence of '0' and
> > '1' characters, if you used ;: opcode 6 (stop) on reaching the payload
> > part of the packet.
> >
> > An example implementation would then interpret the first word of the
> > result as the puzzle opcode. If the opcode was 4, it would interpret
> > the remainder as a number. Otherwise, it would interpret the remainder
> > as a length and after skipping over a number of characters represented
> > by that ;: result, it would extract that length from the stream and
> > call itself recursively on that part and on the part which followed
> > that part.
> >
> > But, yes... the puzzles seem to have a strong influence from the lisp
> > community (specifically the compiler implementation part of that
> > community).
> >
> > Thanks,
> >
> > --
> > Raul
> >
> > On Wed, Jan 12, 2022 at 9:02 AM Stefan Baumann <ste...@bstr.at> wrote:
> > >
> > > I didn't get a grip on this problem at the beginning and skipped it.
> > > But inspired by Raul's solution it appeared that the problem input looks
> > > like an encoded LISP expression.
> > > So I tried to parse the data into a LISP-like J expression and was
> > > wondering if I could then apply ". on it.
> > > The parsing verb ps takes the first position of the packet as y and
> > returns
> > > r, the position right after the packet.
> > > Global nouns V and E store the version numbers and the mentioned J
> > > expression, resp..
> > > J session follows, I hope it's comprehensible - I wanted to keep it very
> > > compact and therefore didn't write any comments.
> > >
> > >    rd=: [: ,/@#: '0123456789ABCDEF'&i.
> > >    $d=: rd 'C0015000016115A2E0802F182340'
> > > 112
> > >    o=: <;._1 ' +/ */ <./ >./ 0: >/ </ =/'
> > >    ps=: 3 : 0
> > > y=. y+6 [ E=: E,',' [ V=: V,{. 'v t'=. #.{&d y+i.2 3
> > > if. t=4 do. z=. (-~ +&5^:({&d)^:_) y
> > >   E=: E, ": #.{&d ,|: (>:y+i.4) +/ i.@>:&.(%&5) z
> > >   r=. y+z+5
> > > else. E=: E,'(', t{::o
> > >   if. {&d <: y=. >:y do. n=. #.{&d y+i.11
> > >     r=. ps^:n y+11
> > >   else. l=. y+15 + #.{&d y+i.15
> > >     r=. ps^:(<&l)^:_ y+15
> > >   end. E=: E,')'
> > > end. r
> > > )
> > >    {{ ps y [ E=: V=: '' }} 0
> > > 106
> > >    +/ V NB. (*)
> > > 23
> > >    ". E NB. (**)
> > > 46
> > >    E
> > > ,(+/,(+/,10,11),(+/,12,13))
> > >
> > > Although ps is defined recursively, it actually just parses from left to
> > > right.
> > > Therefore I'm still wondering if this could be a use case for sequential
> > > machine ;: which I was actually thinking of at the beginning.
> > > Thanks. Stefan.
> > > ----------------------------------------------------------------------
> > > For information about J forums see http://www.jsoftware.com/forums.htm
> > ----------------------------------------------------------------------
> > For information about J forums see http://www.jsoftware.com/forums.htm
> >
> ----------------------------------------------------------------------
> For information about J forums see http://www.jsoftware.com/forums.htm
----------------------------------------------------------------------
For information about J forums see http://www.jsoftware.com/forums.htm

Reply via email to