Advent of code day 14: A puzzle too good for me.
Tags: adventofcode, adventofcode2021, programming, 42
Published: 2021-12-14 09:41:50

Ok, this was very challenging.
On the other side, I feel like we are moving into puzzles territory and OUTSIDE of programming skill territory.
I just wanted some nice programming exercises, not deep logical puzzles...
It is similar to an older puzzle, where we are given a simple algorithm that would be exponentially inefficient to run directly.
Part 1 works well over that algorithm, part 2 needed more brain.
Part one here:
```
reuse [L42.is/AdamsTowel]
Fs = Load:{reuse[L42.is/FileSystem]}
SNMap = Collection.map(key=S val=Num)
Part1 = {
  Lab = Data:{
    var S.List product
    S.Map map
    read method S map(S that)=(
      o = \map.val(key=that)
      if o o.val() else S""
      )
    class method mut This (S string)= (
      top = string.split(S.nl()++S.nl())
      imm product = S.List()(for s in top().split() \add(s))
      imm map = S.Map()(for ss in top().split(S.nl())(
        vals = ss.split(S" -> ")
        \put(key=vals(),val=vals())
        ))
      This(product=product,map=map)
      )
    mut method Void doStep() =\product(\step)
    read method S.List step() = \()((
      (product) = this
      for a in product.vals(0I to=\size-1I)
          b in product.vals(1I to=\size) (
        c = this.map(a++b)
        \add(a)
        if c!=S"" \add(c)
        )
      \add(product.right())
      ))
    }
  Main=(
    lab = Lab(string=Fs.Real.#$of().read(\"input"))
    for i in Range(10I) lab.doStep()
    map = SNMap()(for e in lab.product() (
      o = \val(key=e)
      if o \put(key=e,val=o.val()+1Num)
      else \put(key=e,val=1Num)
      ))
    Debug(map)//3092-717=2375
    )
  }
```


Part 2 is below; here I'm showing that in 42 you can just group classes so that you do not clash by declaring the same class names again. In my experience this is very useful when doing automated testing.

I tried many different solutions.
The main idea is that we can keep a map of chemical pairs into their current 'amount'.
But... at the end we have to count how many we have of the individual chemicals, not the chemical pairs.
I naively just spitted all pairs and.. that does not work: some elements are shared between pairs.
But the map is losing all the information on what order the various pairs are.

I was getting pretty desperate, when eventually I figured out:
Just keep a count when you add the elements.
So I added a 'tot' map and that did the trick.
However, in order to make the strict aliasing and immutability type system of 42 happy I had to use 'lent': a way to mutate data while creating immutable stuff.
```
Part2={
    Lab = Data:{
    mut SNMap tot
    var SNMap product
    S.Map map
    read method S map(S that)=(
      o = \map.val(key=that)
      if o o.val() else S""
      )
    class method mut This (S string)= (
      top = string.split(S.nl()++S.nl())
      imm product = S.List()(for s in top().split() \add(s))
      imm map = S.Map()(for ss in top().split(S.nl())(
        vals = ss.split(S" -> ")
        \put(key=vals(),val=vals())
        ))
      imm mP = SNMap()(
        for a in product.vals(0I to=\size-1I)
            b in product.vals(1I to=\size) (
          o = \val(key=a++b)
          if o \put(key=a++b,val=o.val()+1Num)
          else \put(key=a++b,val=1Num)
          )
        )
      tot = SNMap()(for e in product (
        o = \val(key=e)
        if o \put(key=e,val=o.val()+1Num)
        else \put(key=e,val=1Num)
        ))      
      This(tot=tot,product=mP,map=map)
      )
    mut method Void doStep() =\product(\step(tot=this.#tot()))
    read method SNMap step(lent SNMap tot) = (
      mut res=SNMap()
      for (key,val) in this.product() {
        imm c = this.map().val(key=key).val()
        imm totVal=tot.val(key=c)
        if totVal tot.put(key=c, val=totVal.val()+val)
        else tot.put(key=c, val=val)
        p1 = key.subString(0I to=1I)++c
        p2 = c++key.subString(1I to=2I)
        val1 = res.val(key=p1)
        val2 = res.val(key=p2)
        if val1 res.put(key=p1,val=val1.val()+val)
        else    res.put(key=p1,val=val)
        if val2 res.put(key=p2,val=val2.val()+val)
        else    res.put(key=p2,val=val)
        return void
        }
      res
      )
    }
  Main=(
    lab = Lab(string=Fs.Real.#$of().read(\"input"))
    for i in Range(40I) ( lab.doStep() )
    Debug(lab.tot())
    )
  }
```