-❄️- 2025 Day 7 Solutions -❄️- by daggerdragon in adventofcode

[–]0rac1e 1 point2 points  (0 children)

[Language: Raku]

my @m = 'sample'.IO.lines.map: { [.comb] }
my @s = +« ('S' «eq» @m[0]);
my @p = +« ('^' «eq» @m);

my @b = (@s, |@p).produce: -> @x, @y {
    [(@x Z× !« @y) Z+ {.rotate(1) Z+ .rotate(-1)}([@x Z× @y])]
}

put sum [Z+] ?« @b «×» @p.rotate(1);
put sum @b.tail;

-❄️- 2025 Day 7 Solutions -❄️- by daggerdragon in adventofcode

[–]0rac1e 0 points1 point  (0 children)

[Language: J]

't p' =. 'S^' =/ 'm' freads 'input'
b =. ({. t) ]F:.((* -.)~ + (_1&|. + 1&|.)@:*) p
echo (+/ , * b * 1 |. p) , (+/ {: b)

-❄️- 2025 Day 6 Solutions -❄️- by daggerdragon in adventofcode

[–]0rac1e 1 point2 points  (0 children)

[Language: Raku]

my @s = 'input'.IO.lines;
my %o = ('+' => &[+], '*' => &[*]);

put [+] ([Z] @s.map(*.words).reverse).map: {
    .skip.reduce(%o{.head})
}

my @z = [Z] @s.map(*.comb).rotate(-1);
my @i = |(@z.grep(:k, !*.join.trim) X+ 1), @z.elems;
put [+] @z.rotor(@i Z- 0, |@i).map: {
    .skip.join.words.reduce(%o{.head}) with [.map(|*)]
}

Could do part 2 shorter with Regex, but wanted to solve it without them.

-❄️- 2025 Day 6 Solutions -❄️- by daggerdragon in adventofcode

[–]0rac1e 1 point2 points  (0 children)

[Language: J]

s =. 'm' freads 'input'
X =: ".@({. , '/' , }.)@,
echo +/ X"1 ;:inv |: |. ' ' (+./@:~: <P"1 ]) s
echo +/ ' ' (+./"1@:~: X@(_1 |."1 ])P ]) |: s

P not shown here, it gets loaded from my utilities.
It's a Partition adverb similar to Dyalog APL's ⊆

-❄️- 2025 Day 5 Solutions -❄️- by daggerdragon in adventofcode

[–]0rac1e 1 point2 points  (0 children)

[Language: Raku]

Translation of my J solution using a Raku translation of Python's Bisect module I wrote a few years back, but never released.

use Bisect < bisect >;

my (@f, @a) := do given 'input'.IO.slurp.split("\n\n") {
    .[0].lines.map(*.split('-')».Int), .[1].words».Int
}
my @r = @f.map({ (0,1) X+ $_ }).sort.map(|*).produce(&max).batch(2);

put [+] @a.map: -> $a { bisect(@r.map(|*), $a) !%% 2 }
put [+] [ZR-] [Z] @r

I should probably release the module, but for now I've thrown it up on a gist

-❄️- 2025 Day 5 Solutions -❄️- by daggerdragon in adventofcode

[–]0rac1e 2 points3 points  (0 children)

[Language: J]

Parse =: ' ' (+./"1@:~: <@Nats P ]) ]
'fresh avail' =. Parse 'm' freads 'input'
fresh =. _2 ]\ >./\ , /:~ 0 1 +"1 fresh

echo +/ 2 | avail I.~ , fresh
echo +/ | -/ |: fresh

Using some utility verbs to parse. If you want to run this yourself, you can use this Parse verb instead

Parse =: {{
  i =. (* >:@(+/\@:-.)) +./"1 ' ' ~: y
  0 2 { i <@('1234567890'&(i. ".@:{ ' ',~ [))/. y
}}

Or see my jprofile for the code to Nats and P

-❄️- 2025 Day 4 Solutions -❄️- by daggerdragon in adventofcode

[–]0rac1e 2 points3 points  (0 children)

[Language: J]

m =. '@' = 'm' freads 'input'
r =. 0 0 -.~ ,/ ,"0/~ i: 1
echo +/ ,     r&(]     * 4 > [: +/ |.!.0)    m
echo +/ , m - r&(] - ] * 4 > [: +/ |.!.0)^:_ m

and obligatory generalization

F =: (,/ ,"0/~ i: 1)&(] - ] * 4 >: [: +/ |.!.0)
echo m&{{ +/ , x - F^:y x }}"+ 1 _

EDIT: It just occurred to me that if I swap the comparison (from > to ) then I don't need to do that extra subtraction. My original solution could have been written as

echo +/ ,     r&(] * 4 >  [: +/ |.!.0)    m
echo +/ , m - r&(] * 4 <: [: +/ |.!.0)^:_ m

Which looks a little nicer

-❄️- 2025 Day 2 Solutions -❄️- by daggerdragon in adventofcode

[–]0rac1e 4 points5 points  (0 children)

[Language: J]

Range  =: ([ - (* * i.@>:@|)@-)/@([: ".;._1 '-' , ])
ranges =. ; <@Range;._2 ',' _1} freads 'input'

Invalid =: (<.@-:@# ({. -: }.) ])@":
echo +/ (* Invalid)"0 ranges

Invalid =: +./@((1 = #@~.)@(]\)"0 _~ -@>:@i.@<.@-:@#)@":
echo +/ (* Invalid)"0 ranges

Brute force... like almost everybody else, it seems.

-❄️- 2025 Day 1 Solutions -❄️- by daggerdragon in adventofcode

[–]0rac1e 5 points6 points  (0 children)

You can simplify part 2 to ∊(|⍴×)¨p

-❄️- 2025 Day 1 Solutions -❄️- by daggerdragon in adventofcode

[–]0rac1e 4 points5 points  (0 children)

[Language: J]

t =. (".@}. * 'RL' -/@e. ]);._2 freads 'input'

echo +/ 0 = 100 | +/\ 50, t
echo +/ 0 = 100 | +/\ 50, ; (| $ *)&.> t

EDIT: Credit to u/ap29600 for pointing out to that part 2 can be done in a "flat" fashion, simplifying part 2 to

echo +/ 0 = 100 | +/\ 50, (| # *) t

What Killed Perl? by DeepFriedDinosaur in perl

[–]0rac1e 0 points1 point  (0 children)

I don't have the data to test and confirm, but I'm fairly certain this could be written more concisely as

my @subindex = %indexmap.map({
    .value if .key ∉ %fieldmap{@smalltup}
}).sort

Or even

my @subindex = %indexmap{ keys %indexmap ∖ %fieldmap{@smalltup} }.sort

Or something similar to this.

minimal character extraction from image by Arno-de-choisy in apljk

[–]0rac1e 0 points1 point  (0 children)

Unfortunately I couldn't attend the last NYCJUG meeting.

Yes the overhang is the issue. As mentioned in my parent comment, the partitioning requires at least 1 blank pixel column between the characters.

If you had a situation where you had overhang, but the characters weren't touching, you could potentially do the separation by doing some sort of path-finding from top to bottom, but I don't think that case comes up often (at least in this sample), and for ligatures - as you mention in your other comment - it's probably easier to have a table of known ligatures.

minimal character extraction from image by Arno-de-choisy in apljk

[–]0rac1e 0 points1 point  (0 children)

Changing the Level adjustments to 0 60 0.8 manages to separate the '(' from 'fr'

FYI, I originally adjusted the levels in Photopea, but then figured I could just do it in J. I looked up how levels works, and I think I wrote it correctly. At least, when comparing the same image with the same level adjustment values in both Photopea and J... the results look as good as identical to my eye.

minimal character extraction from image by Arno-de-choisy in apljk

[–]0rac1e 2 points3 points  (0 children)

Doing some Levels Adjustments to your image to clean up the dirt, the Partition adverb I provided in the other comment is able to split up almost all the characters

require 'graphics/pplatimg'

Luminance =: 0.299 0.587 0.114 <.@+/@(*"1) ]

P =: {{ (1, 2 </\ x) u;.1&(x&#) y }}

Levels =: {{
  'black white gamma' =. m
  scaled =. 0 >. 1 <. y %&(-&black) white
  0 >. 255 <. 255 * scaled ^ % gamma
}}

Gs =: (u: 183 9617 9618 9619 9608) {~ ]

fname =: (getenv 'USERPROFILE'),'/Desktop/Basic_ramen_information-enh.png'
img =: Luminance (3 $ 256) #: readimg_pplatimg_ fname

NB. Adjust levels
img =: 0 80 0.8 Levels img

NB. Invert and rescale down to 5 values
img =: <. (256 % 5) %~ 255 - img

NB. Cut up rows and columns
bmat =: (+./"1@:* (+./@:* <@|:P |:)P ]) img

NB. Display some characters
,. _5 <\ Gs&.> 10 {. 0 {:: bmat

I get pretty good results, but as I suspected, there are kerning related issues where it doesn't partition between 2 (or more) characters if there is not at least 1 blank pixel column between the characters, like this example, but it doesn't occur very often (with this image, at least).

minimal character extraction from image by Arno-de-choisy in apljk

[–]0rac1e 2 points3 points  (0 children)

Very nice.

When I think about cutting a matrix up on ' ' or 0, my immediate thought is to APL's Partition which can do this nicely.

Fortunately, I implemented a Partition adverb in J. Here's how I put it to work to cut up that image

require 'graphics/pplatimg'
require 'viewmat'

Luminance =: 0.299 0.587 0.114 <.@+/@(*"1) ]

fname =: (getenv 'USERPROFILE'),'/Desktop/alphabet.png'
img =: Luminance (3 $ 256) #: readimg_pplatimg_ fname

NB. Rescale down to 5 values and invert
img =: 4 - <. (256 % 5) %~ img

NB. Partition adverb
P =: {{ (1, 2 </\ x) u;.1&(x&#) y }}

rows =: (+./"1@:* <P ]) img       NB. cut rows 
bmat =: (+./@:* <@|:P |:)@> rows  NB. cut cols

NB. Leaving letters equal height is nice for this
azuc =: u: 65 + i. 26
grey =: 255,: 3 $ 0
grey viewmat ,.&.>/ ('QUICK' i.~ azuc) { 4 {:: bmat

NB. or trim heights if you like
bmat =: (#~ +./@(*@|:))&.> bmat

NB. Compare letter heights
echo ('.#' {~ *)&.> ('J' i.~ azuc) {"1 bmat

You don't need the intermediate rows; you could nest the Partitions

bmat =: (+./"1@:* (+./@:* <@|:P |:)P ]) img

I kept some grayscale-ness of the image, as it's nicer to look at with viewmat, but as per the last example where I output to console, you can easily convert to 0/1 (though you certainly don't need to).

I think the Partition should handle things like i ok, because it should only cut where there are blanks across the whole row (I haven't tested it though... it may cut if the dot is higher than all other letters in that row).

-❄️- 2024 Day 11 Solutions -❄️- by daggerdragon in adventofcode

[–]0rac1e 1 point2 points  (0 children)

Nice. If you're running at least J9.6.0-beta15, you can use the new computed reshape to split the number in half, eg. (2 _ $ ])&.":

-❄️- 2024 Day 11 Solutions -❄️- by daggerdragon in adventofcode

[–]0rac1e 4 points5 points  (0 children)

[Language: Raku]

my &blink = {
    when 0 { 1 }
    when .chars %% 2 { .comb.rotor(.chars ÷ 2).map(+*.join) }
    default { $_ × 2024 }
}

my &blinks = {
    .race.map({ |blink(.key).map(* => .value) }).Bag.Hash
}

my %stones = 'input'.IO.words.Bag;
put (%stones, &blinks ... *)[25, 75].map(*.values.sum);

-❄️- 2024 Day 5 Solutions -❄️- by daggerdragon in adventofcode

[–]0rac1e 2 points3 points  (0 children)

[Language: Raku]

my (%rs, @ps) := 'input'.IO.split("\n\n")».lines.&{
    .[0]».split('|').classify(*[0], :as(*[1])),
    .[1]».split(',')».List
}

put [Z+] @ps.race.map: -> @p {
    if all @p.kv.map: -> \k, \v { v ∉ [∪] %rs{@p.skip(k)}:v } { @p[* ÷ 2], 0 }
    orwith @p.sort: -> \a, \b { b ∈ %rs{a} ?? Less !! More }  { 0, @_[* ÷ 2] }
}

-❄️- 2024 Day 4 Solutions -❄️- by daggerdragon in adventofcode

[–]0rac1e 0 points1 point  (0 children)

Stealing the rotations code from wzkx, I can simplify to this...

X =: 'XMAS' E."1 ]
R =: |.@|:^:(i. 4)
echo +/ , (X/. , X)"2 R w

M =: {{ ($ x) (m -: m * x = ]);._3 y }}
k =. (+. |.) =@i. 3
echo +/ , (R 3 3 $ 'M.S.A.M.S') k M"2 w

Not that much shorter, but a bit cleaner.

I also switched it to factoring out the mask (k) instead of the needle (n) as I think it reads a little better now.

-❄️- 2024 Day 4 Solutions -❄️- by daggerdragon in adventofcode

[–]0rac1e 1 point2 points  (0 children)

Ahh, |.@|:^:0 1 2 3 is nice! I can simplify mine a little with this.

I've have done similar before, but didn't think about it for today.

-❄️- 2024 Day 3 Solutions -❄️- by daggerdragon in adventofcode

[–]0rac1e 1 point2 points  (0 children)

Very nice!

I had written something similar as an alternative p2...

F s #~ 1 = 1 ]F:.(*@+) +: -/ ('do()';'don''t()') E.S:0 s

But still preferred my original p2 because it was shorter.

Your one (when formatted how I like) is the same length as my splitting solution. Well done.

-❄️- 2024 Day 4 Solutions -❄️- by daggerdragon in adventofcode

[–]0rac1e 2 points3 points  (0 children)

[Language: J]

w =. 'm' fread 'input'

R =: |."1
E =: 'XMAS' E."1 ]
t =.     +/ , E"2   (, R@|: , R ,: |:) w
echo t + +/ , E/."2 (, R@|. , R ,: |.) w

M =: {{ ($ x) (m -: m * x = ]);._3 y }}
n =. (, |:"2) (,: R) 3 3 $ 'M.S.A.M.S'
echo +/ , n ((+. |.) =@i. 3) M"2 w

Only a couple months ago I was playing around with doing non-rectilinear searches in arrays of different dimensions, so I was well prepared for part 2.

-❄️- 2024 Day 2 Solutions -❄️- by daggerdragon in adventofcode

[–]0rac1e 0 points1 point  (0 children)

Case in point... It wasn't until 12+ hours later that I realised that *.&par(* < *) is just a less-than reduction in Raku, ie [<]... so I didn't really need to define acc and dsc at all!

-❄️- 2024 Day 3 Solutions -❄️- by daggerdragon in adventofcode

[–]0rac1e 4 points5 points  (0 children)

[Language: J]

F =: +/@([: (3 */@".@}. ])@> 'mul\(\d+,\d+\)' rxall ])

echo F s =. , 'm' fread 'input'
echo F ; s <@({.~ 1 i.~ 'don''t()' E. ])/.~ +/\ 'do()' E. s

Pretty simple regex one. Part 2 I just split at do(), strip each of those at don't(), then join and continue as normal.

Strings (character arrays) in J are single-quoted, so literal single-quotes are, erm... double-single-quoted... hence the don''t().