Very nice read Raul!

This time I took a different approach: I used the 1 and 7 characters to
find the top segment and the two possible right segments, and bruteforced
the remaining combinations. I used the standard segment ordering (
https://en.m.wikipedia.org/wiki/Seven-segment_display) rather than the one
of the AoC page, because that way I did not have to figure out the hex
representation myself.

NB. Day 08: broken 7-segment displays
NB. input: Nx2 boxes with cols being signal, output
NB. each box has boxed sequences
i08=:(<@(<;._1@(' '&,));._2@,&'|')@rplc&(' | ';'|') ;._2 freads'08.txt'
NB. part A: count how many 1,4,7 or 8 in output, i.e. having 2 4 3 or 7
segments
a08=: [: +/@, [: (2 3 4 7 e.~ #&>)@> {:"1

NB. part B: from signals known, decode output
NB. segment names (different from AoC page)
NB.  aa
NB. f  b
NB. f  b
NB.  gg
NB. e  c
NB. e  c
NB.  dd
segs=: #: _2 dfh\ '7E306D79335B5F707F7B'

NB. Practical approach: limit # perms by:
NB. 1 (2 segs) can match to two possible segments
NB. 7 (3 segs) has one certain segment, the top
NB. perm from stats/base, only monadic case
perm=:{{
z=. i.1 0
for. i.y do. z=. ,/ (0 ,. 1 + z) {"2 1 \:"1 = i. 1 + {: $z end.
}}
NB. construct all 48=2*!4 possible permutations (given 3 segments), rather
than 5040=!7 permutations
NB.  top  ,  2x right  ,   remaining segs
per =: 0,.,/(1 2,:2 1),"1/3+perm 4

NB. decode outputs based on all signals; x is all signals(boxed), y is
signal to decode(boxed)
dec=:{{
  NB. segments of 1 ; will be 1 & 2
  one=. ;(#~2=#&>)x
  NB. top segment ; will be 0
  top=. one -.~ ;(#~3=#&>)x
  NB. all sigs, starting with top and one
  sigs=. (top,one)([ , -.~) ~.;x
  NB. Find correct perm index such that all signals   map to existing
numbers, ap being all permutations of all signals
  pri =. 1 i.~ *./ segs e.~ x e.&>~ (<ap=.per{sigs)
  NB. find signals in correct perm and lookup numbers, converting to base 10
  (4#10) #. segs i. y e.&>~ <pri{ap
}}
b08=: [: +/ dec&>/"1
(a08;b08)i08


On Wed, Dec 29, 2021, 07:32 Raul Miller <[email protected]> wrote:

> https://adventofcode.com/2021/day/8
>
> For day 8, the puzzle declared that we had a seven segment display
> (displaying four digits) that was on the fritz.
>
> Our sample data represented the ten different values being displayed
> during observation, followed by a '|' character, followed by the four
> values representing the four digits being displayed for that
> observation. Something like this:
>
> sample=:{{)n
> be cfbegad cbdgef fgaecd cgeb fdcge agebfd fecdb fabcd edb |
> fdgacbe cefdb cefbgd gcbe
> edbfga begcd cbg gc gcadebf fbgde acbgfd abcde gfcbed gfec |
> fcgedb cgb dgebacf gc
> fgaebd cg bdaec gdafb agbcfd gdcbef bgcad gfac gcb cdgabef |
> cg cg fdcagb cbg
> }}
>
> The actual puzzle sample has more entries than this, but you can go
> look that up yourself. Also, the puzzle samples are pre-wrapped -- the
> code I am posting here expects that they the lines ending in | have
> had their immediately following lines attached.  Like this, though
> email might wrap it some place...
>
> sample1=: {{)n
> acedgfb cdfbe gcdfa fbcad dab cefabd cdfgeb eafb cagedb ab | cdfeb
> fcadb cdfeb cdbaf
> }}
>
> The puzzle page has some detailed explanation of the letter code, but
> the starting point was an ascii based representation of seven segment
> display structure:
>
>  aaaa
> b    c
> b    c
>  dddd
> e    f
> e    f
>  gggg
>
> (Looks better monospaced.)
>
> Anyways, for the first part of the puzzle, we were supposed to
> identify the "easy digits" in the output part (the last four digits --
> those after the '|'). These are the digits with a unique segment
> count: 1 (two segments lit), 4 (four segments lit), 7 (three segments
> lit) and 8 (seven segments lit). The first part wanted us to count how
> many times these digits appeared in a sample.
>
> So, for the first part, I threw together a simple parser.
>
> First, I wanted to split the lines, selecting the part before the |
> from the part after. (Later, I realized that I could have selected the
> first 10 tokens and separated them from the last four.):
>
> split=:{{
>   k=. y i. '|'
>
>   ((k{.y);k}.y)-.L:0 '|'
> }}
>
> Then, I threw in a routine to split each line:
>
> parse0=:{{
>   pairs=. split;._2 y
> }}
>
> And, I also decided that I wanted to know how many lit segments each digit
> had:
>
> lens=: 6 2 5 5 4 5 6 3 7 6
>
> So, for the first part, I tokenized the output part, and used the
> length (in characters) of each token checked which were element of (1
> 4 7 8{lens) and counted the members:
>
> aoc8a=:{{
>   dat=. parse0 y
>   out=.{:"1 dat
>   +/(1 4 7 8 { lens) e.~ ;#@>@;:L:0 out
> }}
>
> For the second part, we are supposed to completely analyze each line
> so that we know what each digit in the output represents, then we
> total each of the four digit numbers represented in the output part of
> each represented display.
>
> Here, I decided I wanted to work with tokens instead of characters, so
> I added another parsing stage.  Sorting the characters in each token
> was probably not necessary, but it made me feel better...
>
> parse1=: {{
>   /:~L:0 ;:each parse0 y
> }}
>
> Once I had this, I built a straightforward inference procedure:
>
> analyze=: {{
>   txt=. ;parse1 y
>   simple=. (lens&(I.@e.)each L:0 ) #@> txt
>   samp=. txt{{
>       s=. ~.m #~ x&e.@> y
>       assert. 1=#s
>       ;s
>    }}
>    one=. 1 samp simple
>    four=. 4 samp simple
>    seven=. 7 samp simple
>    eight=. 8 samp simple
>    aaaa=. seven -. one
>    bbdddd=. four -. one
>    d069=. ~.(6=#@>txt)#txt assert.3=#d069
>    l069=. #@>d069 ([ -. -.)L:0 bbdddd
>    zero=. ;(1=l069)#d069
>    dddd=. bbdddd-.zero
>    bb=. bbdddd-.dddd
>    d235=. ~.(5=#@>txt)#txt assert.3=#d235
>    five=. ;(;bb&e.each d235)#d235
>    three=. ;(;*/@(one&e.)each d235)#d235
>    two=. ;d235-.three;five
>    ff=. three -. two
>    cc=. one -. ff
>    six=. ;(-.;cc&e.each d069)#d069
>    nine=. d069-.zero;six
>    /:~ each zero;one;two;three;four;five;six;seven;eight;nine
> }}
>
> Hopefully my variable naming is reasonably obvious. here, But a couple
> might be obscure:
>
> Names like aaaa or bb contain the letter representing the
> corresponding section(s) of the digits variable. (The values here are
> not repeated -- I just repeated the characters in the names to
> emphasize the distinction between horizontal and vertical segments.
> Staying oriented was helpful to me when writing this.) I never had a
> use for aaaa ... oh well...
>
> Names like zero, one, two contain the corresponding tokens from that
> line. (They do not necessarily have their characters in canonical
> order, I fix that up on the last line.)
>
> d069 is the three tokens which correspond to digits 0, 6 and 9
> l069 is the length of each of those tokens with a couple segments removed.
>
> In other words, it constructs a lookup table.  ((analyze input) i.
> output) gives the four digits of the output.
>
> I could have made this neater (by restructuring where I did my
> parsing, and/or by making parsing pass boxed values through
> unmodified), but my part b implementation looked like this:
>
> aoc8b=: {{
>   keys=. analyze;.2 y
>   +/10 #. keys i."1  /:~each ;@{:"1 parse1  y
> }}
>
> ----------------------
>
> After going through all that, the next day I decided I could have been
> a lot more concise in my implementation. Also, I didn't need to
> manually unwrap lines.
>
> Here's the rewrite:
>
> normalize=: {{
>    lines=.<;._2 y,(-.LF e.y)#LF
>    divs=. '|' e.&> lines
>    if. (#lines) < +/divs do.
>      lines=. (divs#lines),each (-.divs)#lines
>    end.
>    {{(10&{. ,&< _4&{.) /:~each ;:y}}@> lines
> }}
>
> infer=: {{
>   'inp out'=:,normalize y
>   'one seven four is235 is069 eight'=. ,(<^:(1<#)/.~ #@>) (/: #@>)inp
>   'bb ee ff'=. (~.{~ 6 4 9 i.~ #/.~) ;inp
>   'cc'=. one-.ff
>   'aaaa dddd'=. (seven;four)-.L:0 bb,cc,ff
>   'two three five'=. (/: (bb,ff) +/@e."1 >) is235
>   'zero six nine'=. (/: (dddd,cc) e."1 >) is069
>   10 #. (zero;one;two;three;four;five;six;seven;eight;nine) i. out
> }};._2
>
> Writing that wasn't really right for puzzle solving speed, but perhaps
> it's readable enough. The infer routine starts by counting token
> lengths (sorting tokens in ascending length order, then grouping by
> length and counting how many tokens of each length appear), then
> breaks things down based on segment structure of those digits and
> groups of digits..
>
> Leaving me with this cleaner implementation for the second part:
>
> aoc8b=: +/@infer
>
>  --
> Raul
> ----------------------------------------------------------------------
> 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