No Space Left On Device
Description: https://adventofcode.com/2022/day/7
open System.IO
open System
open System.Text.RegularExpressions
open System.Collections.Generic
exception Error of string
let (|Regex|_|) pattern input =
let m = Regex.Match(input, pattern)
if m.Success then
Some(List.tail [ for g in m.Groups -> g.Value ])
else
None
type Command =
| CdInit
| Ls
| Directory of string
| File of int
| CdIn of string
| CdOut
type Tree() =
let storageSize: int = 70_000_000
let updateSize: int = 30_000_000
let dirs = new Dictionary<string, int>()
let mutable usedStorage: int = 0
let mutable currentPath: string[] = Array.empty
let mutable currentPathString = ""
let addSize (size: int) : unit =
if dirs.ContainsKey currentPathString then
let dirSize = dirs[currentPathString]
let newSize = dirSize + size
dirs[currentPathString] <- newSize
let addPath (name: string) : unit =
currentPath <- Array.append [| name |] currentPath
currentPathString <- String.Join(":", currentPath)
let removePath () : string =
let headPath = currentPathString
currentPath <- Array.tail currentPath
currentPathString <- String.Join(":", currentPath)
headPath
member _.Result(part) : int =
if part = 1 then
Seq.filter (fun x -> x <= 100_000) dirs.Values |> Seq.sum
else
let missingStorage = updateSize - (storageSize - usedStorage)
Seq.filter (fun x -> x >= missingStorage) dirs.Values |> Seq.min
member _.Execute(command: Command) : unit =
match command with
| CdInit
| Ls
| Directory _ -> ()
| File size ->
addSize size
usedStorage <- usedStorage + size
| CdIn name ->
addPath name
dirs.Add(currentPathString, 0)
| CdOut ->
let headPath = removePath ()
if (currentPath.Length <> 0) then
dirs[currentPathString] <- dirs[currentPathString] + dirs[headPath]
member _.Parse(line: string) : Command =
match line with
| Regex "\$ cd \/" [] -> CdInit
| Regex "\$ ls" [] -> Ls
| Regex "dir (.+)" [ name: string ] -> Directory name
| Regex "(\d+) .+" [ size: string ] -> File(size |> int)
| Regex "\$ cd (\w+)" [ name: string ] -> CdIn name
| Regex "\$ cd \.\." [] -> CdOut
| x -> raise (Error($"Unknown command: {x}"))
type Input() =
member _.Compute(part: int) =
use stream = new StreamReader "./input.txt"
let mutable endOfFile = false
let tree = new Tree()
while (not endOfFile) do
let line = stream.ReadLine()
if (line = null) then
endOfFile <- true
else
tree.Parse line |> tree.Execute
tree.Result(part)
let input = Input()
let part = (Environment.GetCommandLineArgs()[1]) |> int
printfn "%d" (input.Compute(part))