Skip to content

Instantly share code, notes, and snippets.

@tildekarthik
Created December 14, 2022 03:17
Show Gist options
  • Save tildekarthik/f6886462a38b9dd77e873b563b274dc1 to your computer and use it in GitHub Desktop.
Save tildekarthik/f6886462a38b9dd77e873b563b274dc1 to your computer and use it in GitHub Desktop.
Advent of Code F# Learning 2022 Day 7
open System.IO
let testTxt = """$ cd /
$ ls
dir a
14848514 b.txt
8504156 c.dat
dir d
$ cd a
$ ls
dir e
29116 f
2557 g
62596 h.lst
$ cd e
$ ls
584 i
$ cd ..
$ cd ..
$ cd d
$ ls
4060174 j
8033020 d.log
5626152 d.ext
7214296 k"""
type LineType =
| CommandLine of string
| OutputFileLine of string
| OutputDirLine of string
type DirectoryItem = { name:string;parent:string;}
type FileItem = { name:string;parent:string;size:int;}
type ContentItem =
| Dir of DirectoryItem
| File of FileItem
let parseLineType (line:string) =
if (line.StartsWith("$")) then
CommandLine line
elif (line.StartsWith("dir")) then
OutputDirLine line
else
OutputFileLine line
let parseDirLine (line:string) (currDirName:string) =
let name = currDirName+"/"+line.Substring(4)
{name=name;parent=currDirName}
let parseFileLine (line:string) (currDirName:string) =
let parts = line.Split(' ')
let size = int(parts.[0])
let name = parts.[1]
{name=name;parent=currDirName;size=size}
let changeDirectory (cdCommandLine:string) (currDir:DirectoryItem) (allThings: ContentItem[]) =
let dirName = cdCommandLine.Split("cd ").[1]
match dirName with
|"/" -> {name="/";parent=""},allThings
|".." ->
let parentDir = allThings |> Array.filter (fun x -> match x with |Dir d -> d.name = currDir.parent |_-> false) |> Array.item 0
match parentDir with
|Dir d -> d,allThings
|_-> failwith "parentDir is not a directory"
|_ ->
let newDir = allThings |> Array.filter (fun x -> match x with |Dir d -> d.name = (currDir.name+"/"+dirName) |_-> false) |> Array.item 0
match newDir with
|Dir d -> d,allThings
|_-> failwith "newDir is not a directory"
let parseCommandLine (line:string) (currDir:DirectoryItem) (allThings: ContentItem[]) =
let cmd = line.Split(' ').[1]
if (cmd = "cd") then
changeDirectory line currDir allThings
else
(currDir, allThings)
let parseLine (line:string) (currDir:DirectoryItem) (allThings: ContentItem[]) =
match parseLineType line with
|CommandLine cmd -> parseCommandLine cmd currDir allThings
|OutputDirLine dirLine ->
let newDir = parseDirLine dirLine currDir.name
let newAllThings = allThings |> Array.append [|Dir newDir|]
(currDir, newAllThings)
|OutputFileLine fileLine ->
let newFile = parseFileLine fileLine currDir.name
let newAllThings = allThings |> Array.append [|File newFile|]
(currDir, newAllThings)
let compileTree (lines:string[]) =
let mutable currDir = {name="/";parent=""}
let mutable allThings:ContentItem[] = [|Dir currDir|]
for line in lines do
let (newCurrDir, newAllThings) = parseLine line currDir allThings
currDir <- newCurrDir
allThings <- newAllThings
allThings
let rec getDirectorySize (currDir:DirectoryItem) (allThings:ContentItem[]) =
let files = allThings |> Array.filter (fun x -> match x with |File f -> f.parent = currDir.name |_-> false)
let dirs = allThings |> Array.filter (fun x -> match x with |Dir d -> d.parent = currDir.name |_-> false)
let fileSizes = files |> Array.map (fun x -> match x with |File f -> f.size |_-> 0)|> Array.sum
let dirSizes = dirs |> Array.map (fun x -> match x with |Dir d -> getDirectorySize d allThings |_-> 0) |> Array.sum
fileSizes + dirSizes
let mainPart1 (lines:string[]) =
let allThings = compileTree lines
let directories = allThings |> Array.filter (fun x -> match x with |Dir d -> true |_-> false)|> Array.map (fun x -> match x with |Dir d -> d |_-> failwith "not a directory")
let dirSizes = directories |> Array.map (fun x -> getDirectorySize x allThings)
dirSizes |> Array.filter (fun x -> x < 100000) |> Array.sum
let mainPart2 (lines:string[]) =
let MAX_SPACE = 70000000
let SPACE_REQUIRED = 30000000
let allThings = compileTree lines
let directories = allThings |> Array.filter (fun x -> match x with |Dir d -> true |_-> false)|> Array.map (fun x -> match x with |Dir d -> d |_-> failwith "not a directory")
let dirSizes = directories |> Array.map (fun x -> getDirectorySize x allThings)
let space_used = dirSizes |> Array.max
let space_to_free = SPACE_REQUIRED - (MAX_SPACE - space_used)
dirSizes |> Array.filter (fun x -> x > space_to_free) |> Array.min
printfn "%d" (mainPart1 (File.ReadAllLines("inp7.txt")))
printfn "%d" (mainPart2 (File.ReadAllLines("inp7.txt")))
// printfn "%d" (mainPart1 (testTxt.Split('\n')))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment