## DEV Community is a community of 793,259 amazing developers

We're a place where coders share, stay up-to-date and grow their careers.

Marco Servetto

Posted on

# Advent of code day 5; finally a fun one!

I really enjoyed this one. It may also be because I was able to do it at a decent time in the day instead of near midnight...

This exercise allows me to show the advantages of 42 multiple 'for-in'; allowing to iterate on multiple collections at ones as if we where using a functional zip.

The core to the solution is to expand the line in a list of points.
I have found a couple of difficulties: at the start I did not understood that there was supposed to be diagonal lines, so my code originally looked like this:

``````method Point.List expand() = {
(x1,y1)=\p1 //extract coordinates from points
(x2,y2)=\p2
if x1==x2 return \()(
for y in Range(y1.min(y2) to=y2.max(y1)+1I) \add(\(x=x1,y=y)))
X[y1==y2] return \()(
for x in Range(x1.min(x2) to=x2.max(x1)+1I) \add(\(x=x,y=y1)))
}
``````

I was saved by my assertion! 'X[y1==y2]': checking that my assumption was right: lines are either vertical or horizontal.
This is not the case, there are other kinds of lines and we just have to ignore them.
So the code became

``````method Point.List expand() = {
(x1,y1)=\p1 //extract coordinates from points
(x2,y2)=\p2
if x1==x2 return \()(
for y in Range(y1.min(y2) to=y2.max(y1)+1I) \add(\(x=x1,y=y)))
if y1==y2 return \()(
for x in Range(x1.min(x2) to=x2.max(x1)+1I) \add(\(x=x,y=y1)))
return \()
}
``````

and this was passing part 1.
For part 2, I made a method to avoid repeating the Range-max pattern all over, and also to reverse the range on need to expand the diagonal lines in the right way; The final code is as follows:

``````reuse [L42.is/AdamsTowel]
Point = Data.AddList:Data:{I x, I y }
Point p1, Point p2
class method This (S that) = (
s = that.replace(S" -> " with=S",").split(S",")
ns = I.List()(for n in s \add(\(string=n)))
This(
p1=Point(x=ns.val(0I) y=ns.val(1I)),
p2=Point(x=ns.val(2I) y=ns.val(3I))
)
)
R = {class method I.List (I that, I to)=(
if that<to \()(for i in Range(that to=to+1I)\add(i))
else     \()(for i in Range(to to=that+1I).reverse() \add(i))
)}
method Point.List expand() = {
(x1,y1)=\p1
(x2,y2)=\p2
if x1==x2 return \()(for y in R(y1 to=y2) \add(\(x=x1,y=y)))
if y1==y2 return \()(for x in R(x1 to=x2) \add(\(x=x,y=y1)))
return \()(for x in R(x1,to=x2), y in R(y1,to=y2)
}
}
PMap = Collection.map(key=Point,val=I)
Main = (
fs = Fs.Real.#\$of()
lines = Line.List()(for s in input.split(S.nl()) \add(\(s)))
map = PMap()
for l in lines, for p in l.expand() (
opt = map.val(key=p)
if opt map.put(key=p, val=opt.val()+1I)
else map.put(key=p,val=1I)
)