DEV Community

Discussion on: Advent of Code 2019 Solution Megathread - Day 1: The Tyranny of the Rocket Equation

Collapse
 
neilgall profile image
Neil Gall

Yay, Advent of Code is back. I'm not going to stick to one programming language this year, in fact I'm going to try to use lots, even some I've not used before. I'm not quite hardcore enough to do the different-language-every-day challenge however. Not this year anyway.

Day 1 in Haskell:

import Test.Hspec

load :: String -> [Int]
load = map read . lines

moduleFuel :: Int -> Int
moduleFuel mass = (mass `div` 3) - 2

fuelFuel :: Int -> Int
fuelFuel fuel = fuel + fuel' (moduleFuel fuel)
  where
    fuel' f = if f <= 0 then 0 else fuelFuel f 

part1 :: [Int] -> Int
part1 = sum . map moduleFuel

part2 :: [Int] -> Int
part2 = sum . map (fuelFuel . moduleFuel)

testModuleFuel = do
  moduleFuel 12 `shouldBe` 2
  moduleFuel 14 `shouldBe` 2
  moduleFuel 1969 `shouldBe` 654
  moduleFuel 100756 `shouldBe` 33583

testFuelFuel = do
  fuelFuel 2 `shouldBe` 2
  fuelFuel 654 `shouldBe` 966
  fuelFuel 33583 `shouldBe` 50346

test = do
  testModuleFuel
  testFuelFuel

main = do
  test
  input <- fmap load $ readFile "input.txt"
  putStrLn $ "Part 1 : " ++ (show $ part1 input)
  putStrLn $ "Part 2 : " ++ (show $ part2 input)

Once it was solved I did it again in Python just for fun:

from typing import Sequence

def load(file):
    with open(file, "rt") as f:
        return list(int(line) for line in f.readlines())

def moduleFuel(mass: int) -> int:
    return (mass // 3) - 2

def fuelFuel(mass: int) -> int:
    f = moduleFuel(mass)
    return mass + (0 if f <= 0 else fuelFuel(f))

def testModuleFuel():
    assert(moduleFuel(12) == 2)
    assert(moduleFuel(14) == 2)
    assert(moduleFuel(1969) == 654)
    assert(moduleFuel(100756) == 33583)

def testFuelFuel():
    assert(fuelFuel(2) == 2)
    assert(fuelFuel(654) == 966)
    assert(fuelFuel(33583) == 50346)


def part1(modules: Sequence[int]) -> int:
    return sum(moduleFuel(f) for f in modules)

def part2(modules: Sequence[int]) -> int:
    return sum(fuelFuel(moduleFuel(f)) for f in modules)

if __name__ == "__main__":
    testModuleFuel()
    testFuelFuel()
    input = load("input.txt")
    print(f"Part 1 : {part1(input)}")
    print(f"Part 2 : {part2(input)}")

And in the spirit of what I wrote at the top, I did it once more in Julia, my first ever code in that language. First impressions very positive and interestingly it came out shortest. I love the built-in unit testing.

using Test

load(file::AbstractString) = [parse(Int, line) for line in readlines(file)]

moduleFuel(mass::Int) = div(mass, 3) - 2

function fuelFuel(mass::Int)
  f = moduleFuel(mass)
  mass + if f <= 0 0 else fuelFuel(f) end
end

@testset "ModuleFuel" begin
  @test moduleFuel(12) == 2
  @test moduleFuel(14) == 2
  @test moduleFuel(1969) == 654
  @test moduleFuel(100756) == 33583
end

@testset "FuelFuel" begin
  @test fuelFuel(2) == 2
  @test fuelFuel(654) == 966
  @test fuelFuel(33583) == 50346
end

part1(modules) = sum(moduleFuel(m) for m in modules)

part2(modules) = sum(fuelFuel(moduleFuel(m)) for m in modules)

input = load("input.txt")
println("Part 1 : $(part1(input))")
println("Part 2 : $(part2(input))")