Hi, my take on day 10 followed the same idea as Mike, removing all paired
brackets (for brevity, I use the term bracket for any of (){}[]<>), noting
that corrupt lines have remaining closing brackets, while incomplete lines
have only remaining opening brackets. I managed to make this one tacit
again... I hope it's readable.
NB. Day 10: Matching braces
i10=: ];._2 in 10 NB. lines of char
NB. Score lookup for corrupted pairs
score_cor=: 3 57 1197 25137 0 {~ ')]}>' i. ]
NB. Remove all empty bracket pairs until none left; shift to remove both
opening and closing bracket.
rempairs=: (] #~ _1 (]+:|.!.0) (_2]\'()[]{}<>') +./@:(E."1) ])^:_ "1
NB. Remaining closing brackets are corrupt (hence -.&'({[<') and the first
is kept for scoring.
a10=:([: +/@score_cor {.@-.&'({[<'@rempairs)
NB. Part B: complete strings with right sequence, and score sequence
NB. All pairs removed, if any closing characters are left, it is a
corrupted line, to be removed.
corrupted=: +./@e.&')}]>'"1
NB. score: remove 5 from lookup result caused by padding resulting from
applying rempairs at rank 1; no reverse is needed: completion is the
reverse of the closing brackets corresponding to the remaining opening
brackets, but needs reversing for making insert (/) work appropriately.
score_comp=: ([: (+5&*)/ 5 -.~ '([{<' x:@>:@i. ])"1
NB. (select ranks where mid) of scores of (select non-corrupt)
remainders
b10=: ({~ /:@/: i. <.@-:@#) @: score_comp @ (#~ -.@corrupted) @: rempairs
(a10;b10)i10
On Fri, Dec 31, 2021, 17:48 'Michael Day' via Programming <
[email protected]> wrote:
> Sorry - always forget something - bkts ???
>
> bkts =: 4 2 $'()[]{}<>'
>
> I hope the rest is self-contained, but apologies for the ungraceful
> character non-alignment. I'd avoided graphic boxing characters and
> had sent in fixed-width font where it mattered!
>
> Mike
>
>
>
> On 31/12/2021 15:58, 'Michael Day' via Programming wrote:
> > I _think_ I used a somewhat different approach. I'll only deal with
> > part 1 as
> > part 2 doesn't add much complexity.
> >
> > This approach is simple - remove adjacent pairs of opening and closing
> > brackets of the same kind until there are none. The function is called
> > reduce:
> >
> > I've added echo lines only for this email.
> >
> > reduce =: 3 : 0
> > a =. 1 _1 ,2 _2,3 _3,:4 _4
> > nums =. +/+/"2 a *"2 3 bkts =/ y -.' '
> > NB. this would have been much better! :
> > NB. nums =. (,a){~ (,bkts) i.' '-.~{.ex
> > while. +/ msk =. +/(E.& nums)"1 a do.
> > msk =. -. msk + 0, }: msk NB. matching adjacent pair gives 0 0
> > nums=. msk#nums
> > end.
> > if. 0 > <./ nums do. NB. "corrupted"
> > r =. +/ 3 57 1197 25137 {~ <: |{.(#~ <&0 ) nums
> > echo 'corrupted'; r
> > else. NB. "incomplete"
> > echo 'ignore'; ,|.(}."1 bkts){~<: nums
> > r =. 0
> > end.
> > r
> > )
> >
> > We know if a line is corrupted if we can't reduce it any more AND it
> > still contains
> > some close brackets.
> >
> > I called the example data "ex" - I held it as a 2-d character array.
> >
> > Here it goes, with the echo's firing:
> >
> > +/reduce"1 ex
> > +------+--------+
> > |ignore|}}]])})]|
> > +------+--------+
> > +------+------+
> > |ignore|)}>]})|
> > +------+------+
> > +---------+----+
> > |corrupted|1197|
> > +---------+----+
> > +------+---------+
> > |ignore|}}>}>))))|
> > +------+---------+
> > +---------+-+
> > |corrupted|3|
> > +---------+-+
> > +---------+--+
> > |corrupted|57|
> > +---------+--+
> > +------+---------+
> > |ignore|]]}}]}]}>|
> > +------+---------+
> > +---------+-+
> > |corrupted|3|
> > +---------+-+
> > +---------+-----+
> > |corrupted|25137|
> > +---------+-----+
> > +------+----+
> > |ignore|])}>|
> > +------+----+
> > 26397
> >
> > Cheers,
> >
> > Mike
> >
> >
> >
> > On 31/12/2021 02:41, Raul Miller wrote:
> >> https://adventofcode.com/2021/day/10
> >>
> >> For day 10's puzzle, the first part was determining whether
> >> collections of braces and brackets were properly formed. The
> >> allowable pairs were '()', '[]', '{}', and '<>', and the sample data
> >> looked like this:
> >>
> >> sample=:{{)n
> >> [({(<(())[]>[[{[]{<()<>>
> >> [(()[<>])]({[<{<<[]>>(
> >> {([(<{}[<>[]}>{[]{[(<()>
> >> (((({<>}<{<{<>}{[]{[]{}
> >> [[<[([]))<([[{}[[()]]]
> >> [{[{({}]{}}([{[{{{}}([]
> >> {<[[]]>}<{[{[{[]{()[[[]
> >> [<(<(<(<{}))><([]([]()
> >> <{([([[(<>()){}]>(<<{{
> >> <{([{{}}[<[[[<>{}]]]>[]]
> >> }}
> >>
> >> Specifically, for the first part, we were to find the first illegal
> >> character on each line, each of which were assigned a score, and sum
> >> those scores.
> >>
> >> So the result line for that part would look something like this:
> >>
> >> +/ 3 57 1197 25137 {~ ')]}>' i. bad
> >>
> >> So I built a brute force lexical analyzer which returned empty for
> >> legal lines and the first bad character and its index for illegal
> >> lines:
> >>
> >> scanline=:{{
> >> next=.''
> >> for_ch. y do.
> >> select. ch
> >> case.'(' do. next=. next,')'
> >> case.'[' do. next=. next,']'
> >> case.'{' do. next=. next,'}'
> >> case.'<' do. next=. next,'>'
> >> case.')';']';'}';'>' do.
> >> if. ch={: next do.
> >> next=.}: next
> >> else.
> >> ch;ch_index return.
> >> end.
> >> case. do. echo 'unexpected';ch;ch_index throw.
> >> end.
> >> end.
> >> ''
> >> }}
> >>
> >> The basic approach here is to have an intermediate result which is a
> >> stack of the expected terminating characters and to report on failed
> >> matches.
> >>
> >> I left the character index in the result to help me debug my code if I
> >> had done something horribly wrong.
> >>
> >> Since I was returning boxed characters from that routine for the error
> >> cases, I decided my lookup should normalize both the left and right
> >> arguments to i. to be boxed strings:
> >>
> >> aoc10a=:{{
> >> err=. {."1>(<@scanline;._2 y)-.a:
> >> +/((;:')]}>')i.&:(,each) err){3 57 1197 25137
> >> }}
> >>
> >> For part b, we instead were to report on the lines without illegal
> >> characters and score based on the missing terminating
> >> brackets/braces/...
> >>
> >> Here, the scoring was 1 + the index into ')]}>', multiplied by 5 ^
> >> index into that particular string.
> >>
> >> So I took the above code and tweaked it to return the unfinished
> >> stacks on "good lines":
> >>
> >> scan2=:{{
> >> next=.''
> >> for_ch. y do.
> >> select. ch
> >> case.'(' do. next=. next,')'
> >> case.'[' do. next=. next,']'
> >> case.'{' do. next=. next,'}'
> >> case.'<' do. next=. next,'>'
> >> case.')';']';'}';'>' do.
> >> if. ch={: next do.
> >> next=.}: next
> >> else.
> >> '' return.
> >> end.
> >> case. do. echo 'unexpected';ch;ch_index throw.
> >> end.
> >> end.
> >> |.next
> >> }}
> >>
> >> My initial implementation of the scoring mechanism was a bit messy,
> >> but there's no point burdening you with that. Instead:
> >>
> >> score=:5 #. 1 + ')]}>' i. ]
> >>
> >> Though I could have used
> >>
> >> score=:5 p.~ 1 + ')]}>' i. |.
> >>
> >> To actually complete the second part, we needed to find the median
> >> score:
> >>
> >> aoc10b=:{{
> >> compl=. (<@scan2;._2 y)-.a:
> >> ({~ <.@-:@#)/:~ score every compl
> >> }}
> >>
> >> And that was it for day 10.
> >>
> >
> >
>
>
> --
> This email has been checked for viruses by Avast antivirus software.
> https://www.avast.com/antivirus
>
> ----------------------------------------------------------------------
> For information about J forums see http://www.jsoftware.com/forums.htm
>
----------------------------------------------------------------------
For information about J forums see http://www.jsoftware.com/forums.htm