DEV Community

Cover image for AdventOfCode in 42
Marco Servetto
Marco Servetto

Posted on

2 2

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

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more

Top comments (0)

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs