Advent of code 4; I never liked Bingo...
Tags: adventofcode, 42
Published: 2021-12-04 10:58:39

Here we are again,
I'm starting to get tired of this advent of code, I'm solving them, and 42 is not failing under me, but I'm not that motivated to write nice 42ish code.
Here the difficulty was that more then one can win at the same round, it was not very clear from the text. This also makes the order of the bingos as provided in the file very relevant...
The code below is interesting for someone learning 42 since it uses matrixes and lists of mutable elements.
Note the funky `\#add(right=_)`

```
Numbers = { class method mut I.List(S that)={
  for s in that.split(S.nl()) (
    return \()(for si in s.split(S",") \add(I(string=si)))
    )
  error X"unreachable: input has at least one nl"
  }}
Board = Data.AddList:Collection.matrix(I.List row=5I col=5I)
Boards = {
  class method mut Board.List(S that) = \()(
    for i in Range.endless(), b in that.split(S.nl()++S.nl()) (
      //two new lines between each board
      if i!=0I \#add(right=This(board=b))
      )
    )
  class method mut Board(S board) = (
    //sometimes they are padded
    s = board.replace(S.nl() with=S" ").replace(S"  " with=S" ")
    Board(\()(for si in s.split(S" ") \add(I(string=si))))
    //the board matrix factory takes an I.List 
    )
  }
Bingo = Data:{
  mut I.List ns
  mut Board.List bs
  mut method Void round()=(
    n = \ns.left()
    this.#ns().removeLeft()
    for mut b in this.#bs() This.round(b=b, n=n)
    )
  class method Void round(mut Board b, I n)=(
    for var ni in b.#vals() if ni==n ni:=I"-1"
    )
  read method I winner()={
    for i in Range(this.bs().size()), read bi in \bs (
      if This.win(b=bi) return i
      )
    return I"-1"
    }
  class method Bool win(read Board b) = {
    for i in Range(5I) (
      allRow = Match.All()(for j in Range(5I) \add(b.val(row=i,col=j)==I"-1"))
      if allRow return \.true()
      )
    for j in Range(5I) (
      allCol = Match.All()(for i in Range(5I) \add(b.val(row=i,col=j)==I"-1"))
      if allCol return \.true()
      )
    return \.false()
    }
  class method I points(read Board b) = (
    var res = 0I
    for ni in b if ni!=I"-1" ( res+=ni )
    res
    )
  }
MainPart1 = (
  fs = Fs.Real.#$of()
  input = fs.read(\"input")
  bingo = Bingo(ns=Numbers(input), bs=Boards(input))
  while Bool.true() (
    current = bingo.ns().left()
    bingo.round()
    res = bingo.winner()
    if res!=I"-1" (
      points = Bingo.points(b=bingo.bs().readVal(res))
      Debug(points*current)
      Break()
      )
    )
  )
MainPart2 = (
  fs = Fs.Real.#$of()
  input = fs.read(\"input")
  bingo = Bingo(ns=Numbers(input), bs=Boards(input))
  while Bool.true() (    
    current = bingo.ns().left()
    bingo.round()
    while Bool.true() (//more then one can win in a single round
      res = bingo.winner()
      if res==I"-1" ( Break() )
      bi = bingo.bs().readVal(res)
      points = Bingo.points(b=bi)
      Debug(points*current)//it is printing all the winning ones,
      //I can just see the last one,
      //it will then goes in error when finishes the numbers :P
      bingo.#bs().remove(res)
      )
    )
  )
```
Ultimately, this exercise gave me no good push into putting this giant piece of logic in a method as it should clearly be. Eventually, I just resorted to the trick of looking to the last printout before the program failed because of the end of the numbers.``