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