DEV Community

Cover image for AdventOfCode in 42
Marco Servetto
Marco Servetto

Posted on

AdventOfCode in 42

Hi, I'm trying to complete all the tasks on advent of code (https://adventofcode.com/) with 42 (https://L42.is)

The first challenge is solved as follows:

reuse [L42.is/AdamsTowel]
Fs = Load:{reuse[L42.is/FileSystem]}
Main = (
  fs = Fs.Real.#$of()
  input = fs.read(\"input")
  var last = Math.maxI()
  res = Match.Count()(for s in input.split(S.nl()) (
    e = I(string=s)
    \add(e>last)
    last:=e 
    ))
  Debug(res)
  )
Enter fullscreen mode Exit fullscreen mode

The same code, with line by line comments:

//you should always know where your towel is
reuse [L42.is/AdamsTowel]

//importing the file system library; based on object capabilities
Fs = Load:{reuse[L42.is/FileSystem]}

Main = (
  //creating an object connected with the real file system
  fs = Fs.Real.#$of()

  //read the file as a string  
  input = fs.read(\"input")

  //we need to check when the dept grows, but not count
  //the first reading as growing from no-info
  var last = Math.maxI()

  //Here we use a string spliterator and Count
  //we split the input on newlines
  res = Match.Count()(for s in input.split(S.nl()) (
    e = I(string=s)//convert string->int32
    \add(e>last)//if e>last, it counts!
    last:=e //update last
    ))
  Debug(res)//the result!
  )
Enter fullscreen mode Exit fullscreen mode

I noticed later, we have a part two. I think the solution for part 2 is much more interesting:

LessNoise = Data:{
  var Num a=0\
  var Num b=0\
  var Num c=0\
  read method Num tot() = \a+\b+\c
  mut method Void push(Num that) = ( \a(\b), \b(\c), \c(that) )
  }
Main = (
  fs = Fs.Real.#$of()
  input = fs.read(\"input")
  readings = LessNoise()
  res = Match.Count()(
    for r in Range.endless(), s in input.split(S.nl()) {
      if r<3I ( readings.push(Num(string=s)) return void )
      (tot0) = readings
      readings.push(Num(string=s))
      (tot1) = readings
      return \add(tot1>tot0)      
      }
    )
  Debug(res)
  )
Enter fullscreen mode Exit fullscreen mode

Commenting the new interesting parts below:

LessNoise = Data:{//A class to store the last 3 recordings
  var Num a=0\ //using Num is better then using I, so that
  var Num b=0\ //even if the reading is larger then Math.maxI
  var Num c=0\ //we would still get the right result!
  read method Num tot() = \a+\b+\c
  mut method Void push(Num that) = ( \a(\b), \b(\c), \c(that) )
  //push allows us to simply add a new one.
  //the core idea is that push moves from one window to
  //the next one, so we do not need to store a list of windows
  }
Main = (
  fs = Fs.Real.#$of()
  input = fs.read(\"input")
  readings = LessNoise() //starting point
  res = Match.Count()( 
    //range+return avoids checking the first 3 readings
    for r in Range.endless(), s in input.split(S.nl()) {
      if r<3I ( readings.push(Num(string=s)) return void )
      (tot0) = readings //old window total 
      readings.push(Num(string=s))
      (tot1) = readings //new window total
      return \add(tot1>tot0)
      }
    )
  Debug(res)
  )
Enter fullscreen mode Exit fullscreen mode

The second challenge is solved as Follows (I'm showing part 2 directly):

reuse [L42.is/AdamsTowel]
Fs = Load:{reuse[L42.is/FileSystem]}
ProcessTrait = Trait:Data.Relax:{
  Num val
  class method S name() //the only difference between commands!
  class method Bool fits(S that) = that.startsWith(this.name())  
  class method Num extract(S that) = 
    \(string=that.subString(this.name().size()+1I to=\size))
  class method This (S that) = \(val=\extract(that))
  }
Forward = Class:ProcessTrait:{class method S name() = S"forward" }
Down    = Class:ProcessTrait:{class method S name() = S"down" }
Up      = Class:ProcessTrait:{class method S name() = S"up" }
//as you can see, in 42 it is easy to declare many similar
//data types. This is different from inheritance, since there
//is no subtyping relation between Forward Down and Up.
Submarine = Data:{
  var Num aim =0\
  var Num depth = 0\
  var Num forward = 0\
  mut method Void process(S that) = (
    if Down.fits(that)    ( \aim(\aim+Down(that).val()) )
    if Up.fits(that)      ( \aim(\aim-Up(that).val()) )
    if Forward.fits(that) ( 
      \forward(\forward+Forward(that).val())
      \depth(\depth+(\aim*Forward(that).val()))
      )
    )
  }
Main = (
  fs = Fs.Real.#$of()
  input = fs.read(\"input")
  submarine = Submarine()
  for s in input.split(S.nl()) ( submarine.process(s) )
  Debug(submarine.depth()*submarine.forward())
  )
Enter fullscreen mode Exit fullscreen mode

As you can see, I'm using traits to make a 'template implementation' for the commands, and then I just switch on the commands in Submarine.process

Discussion (0)