Powered by AppSignal & Oban Pro
Would you like to see your link here? Contact us

Day 7 - No Space Left On Device

day07.livemd

Day 7 - No Space Left On Device

Mix.install([{:kino, "~> 0.8.0"}, {:kino_bumblebee, "~> 0.1.0"}, {:exla, "~> 0.4.1"}],
  config: [nx: [default_backend: EXLA.Backend]]
)
:ok

Input

input = Kino.Input.textarea("Please insert your input")
cmd_history =
  input
  |> Kino.Input.read()
  |> String.split("\n", trim: true)
["$ cd /", "$ ls", "dir bqc", "dir mwmlf", "dir ngn", "143562 nrwjb", "78449 qqvdcclf", "dir qrnm",
 "dir smfzmmhc", "116085 tvrms", "dir vrdrsj", "$ cd bqc", "$ ls", "5693 qqvdcclf", "$ cd ..",
 "$ cd mwmlf", "$ ls", "dir cmfphpc", "dir lqqshq", "dir mwmlf", "dir rlf", "dir smfzmmhc",
 "$ cd cmfphpc", "$ ls", "235620 tprth.gjn", "82743 vrdrsj.fbl", "$ cd ..", "$ cd lqqshq", "$ ls",
 "94188 crswqlvd.nsj", "dir dttthls", "60078 lbsfsspm", "dir lqp", "74624 nrwjb",
 "247709 tjhcqw.wrq", "267693 tvrms", "dir zshrcgfn", "$ cd dttthls", "$ ls", "109072 nrwjb",
 "31512 qqvdcclf", "$ cd ..", "$ cd lqp", "$ ls", "237917 nrwjb", "45489 vrdrsj.ntw", "$ cd ..",
 "$ cd zshrcgfn", "$ ls", "185533 smfzmmhc.zzd", ...]

Part 1

Let’s first build the tree

defmodule TreeBuilder do
  def parse_history(hist), do: _parse_history(hist, [], %{})

  defp _parse_history([], _, tree), do: tree

  defp _parse_history(["$ cd .." | rest], [_ | dirs], tree) do
    _parse_history(rest, dirs, tree)
  end

  defp _parse_history(["$ cd " <> dir | rest], dirs, tree) do
    _parse_history(rest, [dir] ++ dirs, tree)
  end

  defp _parse_history(["$ ls" | rest], dirs, tree) do
    # we need to get from rest the result of the ls
    {ls_result, hist} = parse_ls(rest)

    path = Path.join(dirs |> Enum.reverse())
    tree = Map.put(tree, path, ls_result)

    _parse_history(hist, dirs, tree)
  end

  @doc """
  gets the results of an ls command from the stdout history

  ## Examples

      iex> TreeBuilder.parse_ls(["dir a", "14848514 b.txt", "8504156 c.dat", "dir d", "$ cd a", "$ ls"])
      {["dir a", "14848514 b.txt", "8504156 c.dat", "dir d"], ["$ cd a", "$ ls"]}

      iex> TreeBuilder.parse_ls(["$ cd a", "$ ls"])
      {[], ["$ cd a", "$ ls"]}

  """
  def parse_ls(hist) do
    hist
    |> Enum.split_while(fn
      "$" <> _ -> false
      _ -> true
    end)
  end
end
2 doctests, 0 failures
{:module, TreeBuilder, <<70, 79, 82, 49, 0, 0, 11, ...>>, {:parse_ls, 1}}
defmodule CalcSize do
  @doc """
  recursevely calculate folder size

  ## Examples

      iex> CalcSize.size(%{ "/a/e" => ["584 i"]}, "/a/e")
      584

      iex> CalcSize.size(%{"/d" => ["4060174 j", "8033020 d.log", "5626152 d.ext", "7214296 k"]}, "/d")
      24933642

      iex> CalcSize.size(%{"/a" => ["dir e", "29116 f", "2557 g", "62596 h.lst"], "/a/e" => ["584 i"]}, "/a")
      94853

      iex> CalcSize.size(%{"/" => ["dir a", "14848514 b.txt", "8504156 c.dat", "dir d"], "/a" => ["dir e", "29116 f", "2557 g", "62596 h.lst"], "/a/e" => ["584 i"], "/d" => ["4060174 j", "8033020 d.log", "5626152 d.ext", "7214296 k"]}, "/")
      48381165

  """
  def size(tree, name) do
    fds = Map.get(tree, name)

    fds
    |> Enum.reduce(0, fn
      "dir " <> dir, sz -> sz + CalcSize.size(tree, Path.join(name, dir))
      fd, sz -> (String.split(fd, " ") |> Enum.at(0) |> String.to_integer()) + sz
    end)
  end
end
4 doctests, 0 failures
{:module, CalcSize, <<70, 79, 82, 49, 0, 0, 9, ...>>, {:size, 2}}
folders = TreeBuilder.parse_history(cmd_history)
%{
  "/ngn/fqbph/lzjf" => ["40821 lfgh.jwg", "dir rplfgb"],
  "/mwmlf/mwmlf/mwmlf" => ["dir wnn"],
  "/mwmlf/rlf/qpgmrj/pbc" => ["150816 tprth.gjn"],
  "/smfzmmhc/mwmlf" => ["263186 mwmlf.fqd"],
  "/vrdrsj/pnds/jwcjpt/scljqqq" => ["228515 hrvlgmjb.nhn", "246019 mwmlf", "9535 mwmlf.nvm"],
  "/smfzmmhc/vrdrsj" => ["dir mwwr", "dir rlf"],
  "/vrdrsj/pnds/jwcjpt/rfh" => ["29828 hgwh.tnl", "dir rchll", "dir smfzmmhc"],
  "/vrdrsj" => ["dir bfgbvlcd", "131293 fgh.djg", "125876 lcwjtdf.sbl", "dir pnds", "263022 tvrms"],
  "/ngn/fqbph/bgtbmzj/jmvzv/smfzmmhc/gqms/rlf/hvtn/zzsfgzc" => ["116544 vrdrsj"],
  "/ngn/fqbph/bgtbmzj/jmvzv/hfmtzbhf/ldt/zbcfv/vrdrsj" => ["220800 zwdbh"],
  "/ngn/mwmlf/fvjtnl" => ["62568 sllvfsf", "286839 tjhcqw.wrq", "241004 zvqrg.bsg"],
  "/smfzmmhc/pvnbj/cfmn/sfvd/qpzbffd" => ["264911 mwmlf.rvg", "dir rlf", "32109 svhwhw.fdp",
   "155713 tjhcqw.wrq", "dir vrdrsj"],
  "/smfzmmhc/vrdrsj/mwwr/lhz/ssz" => ["107472 hcnsgjhj"],
  "/mwmlf/rlf/ncrlvggp/nnqgqqj" => ["dir fvbhh"],
  "/vrdrsj/pnds/jwcjpt/dcmcgc/fhdvgvtz/lrsjg/jgfpvdc/mwmlf/grqng" => ["216391 tvrms"],
  "/ngn/mwmlf" => ["dir dqvhgnj", "dir fvjtnl", "dir jfsgp", "230725 tjhcqw.wrq", "2872 tvrms",
   "dir zszcsbl"],
  "/smfzmmhc/pvnbj/cfmn/sfvd/wscsr/vrdrsj/vvtl" => ["118913 qqvdcclf", "291087 tjhcqw.wrq"],
  "/mwmlf/cmfphpc" => ["235620 tprth.gjn", "82743 vrdrsj.fbl"],
  "/mwmlf/mwmlf/mwmlf/wnn/thd" => ["36125 lgt"],
  "/mwmlf/rlf/ncrlvggp" => ["81450 fqtrpm.mqr", "146399 jtbr", "dir nnqgqqj", "288302 qqvdcclf"],
  "/ngn/fqbph/rlf" => ["37853 qst.zgc"],
  "/vrdrsj/pnds/jwcjpt/rfh/rchll" => ["240042 rdj.wrv"],
  "/vrdrsj/pnds/pvnbz/hrvlgmjb" => ["dir vggpr"],
  "/vrdrsj/pnds/jwcjpt/rfh/smfzmmhc/vrdrsj" => ["302512 phmvhpvb.fwh", "dir tjrpwhc"],
  "/ngn/fqbph/bgtbmzj/jmvzv/smfzmmhc/mwmlf/hmpvn" => ["55892 qqvdcclf"],
  "/vrdrsj/pnds/jwcjpt/dcmcgc/hrvlgmjb/vds" => ["247595 gnclhrw.mwt", "303125 pcdnbq.zbs",
   "38092 tprth.gjn", "dir vrdrsj"],
  "/ngn/fqbph/bgtbmzj/szp" => ["37741 qqvdcclf", "dir vrdrsj"],
  "/ngn/fqbph/bgtbmzj/jmvzv/smfzmmhc" => ["dir gqms", "dir mwmlf", "21587 nrwjb", "184621 zvq.lvr"],
  "/vrdrsj/pnds/jwcjpt/dcmcgc/fhdvgvtz/lrsjg/jgfpvdc" => ["265563 chlgpdsp.hrv", "dir dsc",
   "dir gvrg", "dir mwmlf", "dir qrqvl", "100762 rlf", "300872 sjvgwmdg.qhg", "164004 tzqmh",
   "300736 zhgmdcl.bfq"],
  "/ngn/fqbph/bgtbmzj/jmvzv/smfzmmhc/mwmlf" => ["dir hmpvn", "dir shlnfcpz"],
  "/smfzmmhc/sjqwr/vrdrsj/vrdrsj" => ["250310 hrvlgmjb.bbf", "130543 mwmlf.lbq"],
  "/mwmlf/mwmlf/mwmlf/wnn" => ["dir thd"],
  "/vrdrsj/pnds/jwcjpt/dcmcgc/rlf/vrdrsj/jtnqr" => ["dir bct", "202702 grstm.ltj", "dir mwmlf",
   "258253 tvrms"],
  "/vrdrsj/pnds/jwcjpt/dcmcgc/hrvlgmjb" => ["dir fjnp", "70585 hrvlgmjb", "dir qsrgzrdf",
   "43606 rmjzzgrs", "dir vds", "dir vrdrsj", "35098 wthtcg.wgd"],
  "/smfzmmhc/pvnbj/czmw/gdsgw" => ["298839 dbwsmwnb.svt", "170672 tprth.gjn"],
  "/smfzmmhc/ncgjsjj" => ["204801 nrwjb", "116293 rdrmctwg.nqc", "36548 tjhcqw.wrq"],
  "/smfzmmhc/pvnbj/cnhmcjp" => ["263233 tjhcqw.wrq"],
  "/vrdrsj/bfgbvlcd" => ["276134 vrdrsj"],
  "/smfzmmhc/vwfnglr/mtvgvvcr/smfzmmhc/jjslqwn" => ["98708 mwmlf.qtq"],
  "/vrdrsj/pnds/jwcjpt/dcmcgc/hrvlgmjb/fjnp" => ["19740 qqvdcclf", "dir smfzmmhc"],
  "/smfzmmhc/pvnbj/cfmn/sfvd/wscsr" => ["132663 dnbvw.zwd", "dir ffthd", "293463 hrvlgmjb.fwh",
   "dir lhjvfdh", "194357 nrwjb", "dir smj", "56668 tprth.gjn", "303099 tvrms", "dir vrdrsj"],
  "/vrdrsj/pnds/jwcjpt/dcmcgc/fhdvgvtz/lrsjg/jgfpvdc/dsc" => ["284520 rtt.qps", "263890 smfzmmhc"],
  "/smfzmmhc/pvnbj/drfzgwtz" => ["257122 tprth.gjn"],
  "/ngn/fqbph/pdsdttz" => ["294779 tprth.gjn"],
  "/smfzmmhc/pvnbj/czmw/gfd" => ["193212 tld"],
  "/ngn/fqbph/bgtbmzj/jmvzv" => ["dir hfmtzbhf", "61556 jzbvmc", "dir scjpjp", "237487 sgh", ...],
  "/smfzmmhc/vrdrsj/mwwr" => ["dir lhz"],
  "/mwmlf" => ["dir cmfphpc", "dir lqqshq", ...],
  "/vrdrsj/pnds/jwcjpt/dcmcgc/hrvlgmjb/vds/vrdrsj" => ["dir tnjg"],
  "/smfzmmhc/vrdrsj/mwwr/lhz/vrdrsj" => [...],
  ...
}
folders
|> Enum.map(fn {k, _} -> CalcSize.size(folders, k) end)
|> Enum.filter(fn sz -> sz <= 100_000 end)
|> Enum.sum()
1325919

Part 2

total_disk_size = 70_000_000

used_disk_size = CalcSize.size(folders, "/")

unused_disk_size = total_disk_size - used_disk_size

update_disk_size = 30_000_000

needed_disk_size = update_disk_size - unused_disk_size
2036703
folders
|> Enum.map(fn {folder, _} -> CalcSize.size(folders, folder) end)
|> Enum.sort()
|> Enum.find(fn size -> size >= needed_disk_size end)
2050735