re: AoC Day 1: Chronal Calibration VIEW POST

FULL DISCUSSION
 

Is it normal that part 2 is killing my CPU :D ? It's been running for minutes in Elixir but nada.

Anyhow, I've tried day 1 with all three languages which is not a great idea!

I just googled the parts of the various languages I needed

Clojure

part 1

(def numbers-as-strings (clojure.string/split (slurp "input.txt") #"\n"))
(def numbers (map read-string numbers-as-strings))
(defn sum [coll] (reduce + coll))
(println (sum numbers))

I kind of hated it, I still don't have syntax highlighting nor formatting for some reason in VSCode and the REPL is quite slow to start (I didn't try with ClojureScript)

part 2

(def repeated-numbers (cycle numbers))

(loop
    [known-totals (set nil), total 0]
    (if (contains? known-totals total)
        (println total)
        (recur (conj known-totals total) (+ total (first (take 1 repeated-numbers))))))

I'm not sure it's correct, I had to kill it because it was hogging the CPU

Elixir

part 1

numbers_as_strings = String.split(String.trim(File.read!("input.txt")), "\n")
numbers = Enum.map(numbers_as_strings, fn x -> String.to_integer(x) end)
IO.puts(Enum.sum(numbers))

Well, this was the easiest one

part 2

defmodule Part2 do
    def find_total(repeated_numbers, totals, sum) do
        unless MapSet.member?(totals, sum) do
            MapSet.put(totals, sum)
            sum = sum + hd(Enum.take(repeated_numbers, 1))
            find_total(repeated_numbers, totals, sum)
        end

        IO.puts sum
    end
end

Part2.find_total(Stream.cycle(numbers), MapSet.new, 0)

Again, I'm not sure it's correct, it just kills my computer

Rust

part 1

use std::fs;

fn main() {
    let data = fs::read_to_string("input.txt").expect("Unable to read file");
    let numbers_as_strings = data.split("\n").collect::<Vec<&str>>();
    let numbers = numbers_as_strings.iter().filter_map(|n| n.parse::<i32>().ok()).collect::<Vec<i32>>();
    let sum: i32 = numbers.iter().sum();
    println!("{}", sum);
}

There's a bit of fiddling with types and syntax but the compiler it's quite helpful when you type stuff that doesn't make sense. It can get in the way of me doing the excercises :D

part 2

Well, this ran for half a second a produced the correct answer

use std::fs;
use std::collections::HashSet;

fn main() {
    // part 1
    let data = fs::read_to_string("input.txt").expect("Unable to read file");
    let numbers_as_strings = data.split("\n").collect::<Vec<&str>>();
    let numbers = numbers_as_strings.iter().filter_map(|n| n.parse::<i32>().ok()).collect::<Vec<i32>>();
    let sum: i32 = numbers.iter().sum();
    println!("{}", sum);

    // part 2
    let mut totals: HashSet<i32> = HashSet::new();
    let repeated_numbers = numbers.iter().cycle();
    let mut repeated_sum: i32 = 0;
    for num in repeated_numbers {
        if totals.contains(&repeated_sum) {
            println!("{}", repeated_sum);
            break;
        }
        totals.insert(repeated_sum);
        repeated_sum += num
    }
}

What am I doing wrong with Clojure and Elixir :D ?

I've put Day 1 on Github: github.com/rhymes/aoc2018/tree/mas...

 

I totally thought my elixir one was dead at first too, so I kept killing it. Only about a 15 second run time though I'm just impatient. lemme look at yours!

 

Please do, I found a solution at the end, using reduce_while, instead of recursion:

repeated_numbers = Stream.cycle(numbers)
repeated_sum = Enum.reduce_while(repeated_numbers, {0, MapSet.new([0])}, fn i, {current, totals} ->
  sum = current + i

  if MapSet.member?(totals, sum) do
    {:halt, sum}
  else
    {:cont, {sum, MapSet.put(totals, sum)}}
  end
end)
IO.puts(repeated_sum)

I feel like I should get through the tutorial at least :D

 

At a glance, in the Elixir part two solution it looks like the list of numbers is just being passed through as is. So, it is never moving on to the rest of the numbers and instead the sum is just adding the first number in the list over and over.

Because repeated_numbers is never reassigned the recursive call find_total(repeated_numbers, totals, sum) is passing the unchanged list of all the numbers through to the next iteration.

 

At a glance, in the Elixir part two solution it looks like the list of numbers is just being passed through as is. So, it is never moving on to the rest of the numbers and instead the sum is just adding the first number in the list over and over.

That's probably it, I thought that:

hd(Enum.take(repeated_numbers, 1))

would take 1 number (and hence move the cursor).

It does, but because Elixir is immutable it returns a new list with the first element from repeated_numbers instead of mutating (changing in place) repeating_numbers

Also, this line hd(Enum.take(repeated_numbers, 1)) could be rewritten as hd(repeated_numbers) to get the same functionality. The more "Elixir way to write that would be to use pattern matching. Something like [head | tail] = repeated_numbers Here is some more info on pattern matching, if you're interested. I think it is super cool!

Thank you! :-)

I have to get used again to immutability and transformation instead of mutability and assignment :D

 

On the Clojure pt 2, you're effectively running an endless loop. You always take the first element from the cycled number collection, so you'll never hit the exit condition.
To avoid this while using the approach you chose, add a third numbers binding to the loop, and pass (rest numbers) when recuring, while computing total using (first numbers).

 
code of conduct - report abuse