DEV Community

Discussion on: AoC Day 1: Chronal Calibration

Collapse
 
ryanwilldev profile image
Ryan Will

Thanks for making this post and sharing your solutions!

Here are my solutions in Elixir and JavaScript.

To start a couple functions to parse the input.

def parse(input) do
  input
  |> String.split("\n")
  |> Enum.map(&(String.trim(&1)
    |> String.to_integer())
  )
end
function parse() {
  return input()
    .split('\n')
    .map(Number);
}

Part one's solutions.

def part_1 do
  input() 
  |> parse() 
  |> Enum.sum()
end
function partOne() {
  return parse()
    .reduce((total, current) => total + current, 0);
}

Part two's solutions.

This solution takes advantage of Elixir's recursion, pattern matching, and multiple function clauses.

def part_2 do
 input() 
 |> parse() 
 |> part_2(0, %{})
end

def part_2([current | rest] = _frequencies, total, record) do
  total = current + total
  record = Map.update(record, total, 1, &(&1 + 1))

  case record[total] do
    n when n > 1 ->
      total

    _ ->
      part_2(rest, total, record)
  end
end

def part_2([], total, record) do
  input()
  |> parse()
  |> part_2(total, record)
end

I made two solutions to part two in JavaScript the first uses a more imperative approach, and the second was meant to mimic the Elixir solution using recursion. The issue with that is JavaScript not being tail call optimized. In order to get around that I used a trampoline function and a while loop. Though, that approach is insanely slow.

function partTwoImperative() {
  let record = {};
  let frequency = 0;
  let index = 0;
  let frequencyList = parse();
  let totalLoops = 0;

  const found = (record, frequency) => 
    (record[frequency] || 0) > 1;
  const getFrequencyRecordValue = (record, frequency) =>
    (record[frequency] || 0) + 1;

  while (!found(record, frequency)) {
    if (index === frequencyList.length) index = 0;

    frequency += frequencyList[index];
    record[frequency] = getFrequencyRecordValue(record, frequency);
    index += 1;
    totalLoops += 1;
  }

  return [frequency, totalLoops];
}

function partTwoTrampoline() {
  const found = (record, frequency) => (record[frequency] || 0) > 1;

  const getFrequencyRecordValue = (record, frequency) =>
    (record[frequency] || 0) + 1;

  const partTwoRecursive = ([current, ...rest], total, record) => {
    const newTotal = total + current;

    const newRecord = {
      ...record,
      [newTotal]: getFrequencyRecordValue(record, newTotal)
    };

    return !found(newRecord, newTotal)
      ? () =>
          partTwoRecursive(
            rest.length ? rest : [3, 3, 4, -2, -4],
            newTotal,
            newRecord
          )
      : newTotal;
  };

  let ret = partTwoRecursive([3, 3, 4, -2, -4], 0, {});

  while (typeof ret === 'function') {
    ret = ret();
  }

  return ret;
}
Collapse
 
am_myrick profile image
Andre Myrick

Wow, this is really cool! I completed day one too, but my code is nowhere near that clean. Could you recommend any resources that helped you get into Elixir?

Collapse
 
ryanwilldev profile image
Ryan Will

Thanks! This sounds like a cop-out answer but the Elixir docs are a great resource. elixir-lang.org/

I'd also be happy to answer any questions you have.