uku.dev

Advent of Languages: Day 2 - SCSS

05 December, 2019

3 minute read

This is a part of my ongoing challenge of solving every Advent of Code puzzle in a different language.

The challenge we're tackling today is available here.

1202 Program Alarm

The plot this time talks about a computer whose magic smoke has left it. We are to create a new one, to the old one’s specifications.

The input this time is a long tape of numbers. Some of these (1, 2 and 99) correspond to operations that we can do with other things on the tape.

The Language

After the first challenge, which I decided to do in x86 assembly, I’d like something that would be a cakewalk, but still interesting.

I decided to go with SCSS (or SASS, its sister variant, which is identical but uses significant whitespace instead of brackets). SCSS is a CSS pre-processor that I have some experience with. It’s used to build CSS that we ship to websites. Back in the day, CSS didn’t have features like variables integrated, and it still doesn’t have functions. SCSS was great for keeping your design system consistent. It’s not normally meant to do actual computation on, so this might be interesting.

The Solution: Part 1

Let’s dig in.

$input: 1, 0, 0, 3, 1, 1, 2, 3, 1, 3, 4, 3, 1, 5, 0, 3, 2, 1, 13, 19, 1, 9, 19, 23, 2, 13, 23, 27, 2,
  27, 13, 31, 2, 31, 10, 35, 1, 6, 35, 39, 1, 5, 39, 43, 1, 10, 43, 47, 1, 5, 47, 51, 1, 13, 51, 55,
  2, 55, 9, 59, 1, 6, 59, 63, 1, 13, 63, 67, 1, 6, 67, 71, 1, 71, 10, 75, 2, 13, 75, 79, 1, 5, 79,
  83, 2, 83, 6, 87, 1, 6, 87, 91, 1, 91, 13, 95, 1, 95, 13, 99, 2, 99, 13, 103, 1, 103, 5, 107, 2,
  107, 10, 111, 1, 5, 111, 115, 1, 2, 115, 119, 1, 119, 6, 0, 99, 2, 0, 14, 0;

$ADD: 1;
$MULTIPLY: 2;
$HALT: 99;

@function set-n($list, $index, $value) {
  @return set-nth($list, $index + 1, $value);
}

@function n($list, $index) {
  @return nth($list, $index + 1);
}

@function run($tape, $noun, $verb) {
  $state: set-n(set-n($tape, 1, $noun), 2, $verb);

  $index: 0;
  @while true {
    $operation: n($state, $index);

    @if $operation == $ADD {
      $arg-1: n($state, n($state, $index + 1));
      $arg-2: n($state, n($state, $index + 2));
      $value-position: n($state, $index + 3);

      $state: set-n($state, $value-position, $arg-1 + $arg-2);
    } @else if $operation == $MULTIPLY {
      $arg-1: n($state, n($state, $index + 1));
      $arg-2: n($state, n($state, $index + 2));
      $value-position: n($state, $index + 3);

      $state: set-n($state, $value-position, $arg-1 * $arg-2);
    } @else if $operation == $HALT {
      @return n($state, 0);
    } @else {
      @debug $operation;
      @error "unknown operation";
    }

    $index: $index + 4;
  }
}

#answer-1 {
  margin: run($input, 12, 2);
}

To start with, I looked around but didn’t yet find a way for SCSS to read a text file. After all, it’s not meant for this kind of thing. We’ll work around this by just sticking my input into a variable. Variables are declared in SCSS similarly to normal c-based languages but with a : instead of =. They also have the dreaded PHP dollar, though.

After the $input is declared, I set up a couple of constants we’ll need later in the software. Next up: SCSS is 1-indexed, which I don’t want to deal with right now, as the input expects a 0-indexed tape. To make this easier for myself, I set up a couple of functions. One to set the element of a list at a certain index, but I add 1 internally to the index to compensate for the 1-indexing. It’s worth noting that lists are immutable in SCSS, which means the setter just returns a new list. The other function I set up here is just to get the value of an element of a list at an index, but again I add 1 internally to compensate. The functions these use internally are built into SCSS.

Next, we get to the run function, which is the meat of the problem. It does two main things. As specified in the task, it switches a couple of elements at certain indexes to the ones provided in the arguments. Then it implements the computer itself and finally returns the state of the tape at the first element.


In the main loop, we do a couple of things. First, we read the value at the current index in the tape to know which operation to run. Then, depending on the operation code, we run the corresponding operation and change the state of the tape with the result. Finally, we increment the index by 4 and jump to the next operation.

This loop runs until it hits a HALT instruction (operation code 99) or dies because we’ve run out of tape.

Finally, as I’d like to output valid CSS, we call our function within a CSS element, setting it to a margin, because margins are great.

When we run sass solution.scss, we get this:

#answer-1 {
  margin: 3790689;
}

Where 3790689 is the answer to part 1.

The Solution: Part 2

Now we’re tasked to find a couple magical numbers, that when placed in the tape at certain spots, result in a certain output, provided by the task. In the last part, we were provided these numbers, they were 12 and 1. We’re also told both of these numbers are in the range of 0..99.

$input: 1, 0, 0, 3, 1, 1, 2, 3, 1, 3, 4, 3, 1, 5, 0, 3, 2, 1, 13, 19, 1, 9, 19, 23, 2, 13, 23, 27, 2,
  27, 13, 31, 2, 31, 10, 35, 1, 6, 35, 39, 1, 5, 39, 43, 1, 10, 43, 47, 1, 5, 47, 51, 1, 13, 51, 55,
  2, 55, 9, 59, 1, 6, 59, 63, 1, 13, 63, 67, 1, 6, 67, 71, 1, 71, 10, 75, 2, 13, 75, 79, 1, 5, 79,
  83, 2, 83, 6, 87, 1, 6, 87, 91, 1, 91, 13, 95, 1, 95, 13, 99, 2, 99, 13, 103, 1, 103, 5, 107, 2,
  107, 10, 111, 1, 5, 111, 115, 1, 2, 115, 119, 1, 119, 6, 0, 99, 2, 0, 14, 0;

$ADD: 1;
$MULTIPLY: 2;
$HALT: 99;

@function set-n($list, $index, $value) {
  @return set-nth($list, $index + 1, $value);
}

@function n($list, $index) {
  @return nth($list, $index + 1);
}

@function run($tape, $noun, $verb) {
  $state: set-n(set-n($tape, 1, $noun), 2, $verb);

  $index: 0;
  @while true {
    $operation: n($state, $index);

    @if $operation == $ADD {
      $arg-1: n($state, n($state, $index + 1));
      $arg-2: n($state, n($state, $index + 2));
      $value-position: n($state, $index + 3);

      $state: set-n($state, $value-position, $arg-1 + $arg-2);
    } @else if $operation == $MULTIPLY {
      $arg-1: n($state, n($state, $index + 1));
      $arg-2: n($state, n($state, $index + 2));
      $value-position: n($state, $index + 3);

      $state: set-n($state, $value-position, $arg-1 * $arg-2);
    } @else if $operation == $HALT {
      @return n($state, 0);
    } @else {
      @debug $operation;
      @error "unknown operation";
    }

    $index: $index + 4;
  }
}

@function find-noun-verb($tape, $value) {
  @for $i from 0 to 100 {
    @for $j from 0 to 100 {
      $result: run($tape, $i, $j);
      @if $result == $value {
        @return 100 * $i + $j;
      }
    }
  }
}

#answer-2 {
  margin: find-noun-verb($input, 19690720);
}

I went with a very simple brute force approach, where I try every possible combination of these two numbers until I find the result we’re expecting. For this, we have a new function, find-noun-verb, which does just that. It also returns the numbers in a format expected by the task.

After running this, we end up with:

#answer-2 {
  margin: 6533;
}

Which, indeed, is the right answer.

Retro

This was exactly what I wanted after the x86 task. Something different, but easy. Although I’ve used a fair bit of SCSS and LESS, I’ve never used them in this way. Good to know that they’re powerful and easy to use.

If you want to look at the code in full, I’m putting all of the Advent of Code solutions on GitHub.