~turminal/aoc2022

29a65b8e9f3148fd87f4f39e8115621a0ab2e0d2 — Bor Grošelj Simić 1 year, 9 months ago 2b8438c
day 7
3 files changed, 129 insertions(+), 0 deletions(-)

A 7/lex.mll
A 7/t1.ml
A 7/t2.ml
A 7/lex.mll => 7/lex.mll +15 -0
@@ 0,0 1,15 @@
{
type token =
	| Cd of string
  | File of int * string
  | Cdup | Ls | Dir of string | Eof

let i = int_of_string
}

rule token = parse
	| "$ cd " ([^'\n']+ as d) '\n' { if d = ".." then Cdup else Cd d }
  | "$ ls\n" { Ls }
  | "dir " ([^'\n']+ as d) '\n' { Dir d }
  | (['0'-'9']+ as sz) ' ' ([^'\n']+ as f) '\n' { File (i sz, f) }
	| eof { Eof }

A 7/t1.ml => 7/t1.ml +56 -0
@@ 0,0 1,56 @@
open Lex

module StrMap = Map.Make(String)

type thing =
	| Dir of string
	| File of int

let joinpath l = List.fold_left (^) "" l

let rec f lexbuf path (map: (thing list) StrMap.t) =
	match Lex.token lexbuf with
	| Eof -> map
	| Cd dir -> f lexbuf (dir :: path) map
	| Cdup -> f lexbuf (List.tl path) map
	| Ls -> f lexbuf path map
	| _ as tok ->
		let map, update =
			match tok with
			| Dir d ->
					let update e =
						e |> Option.get |> List.cons (Dir d) |> Option.some
					in
					(StrMap.add (joinpath (d :: path)) [] map, update)
			| File (sz, _) ->
					let update e =
						e |> Option.get |> List.cons (File sz) |> Option.some
					in
					(map, update)
			| _ -> failwith "no way"
		in
		map |> StrMap.update (joinpath path) update |> f lexbuf path

let mem = ref StrMap.empty

let rec solve e map =
	match StrMap.find_opt e !mem with
	| Some v -> v
	| None ->
		let rec aux = function
			| File sz :: l -> sz + aux l
			| Dir d :: l -> solve (d ^ e) map + aux l
			| [] -> 0
		in
		let res = StrMap.find e map |> aux in
		mem := StrMap.add e res !mem;
		res

let sub_sum _ a = (+) (if a <= 100000 then a else 0)

let () =
	let map = StrMap.singleton "/" [] in
	f (Lexing.from_channel stdin) [] map |>  solve "/" |> ignore;
	StrMap.fold sub_sum !mem 0
		|> Printf.printf "%d\n"


A 7/t2.ml => 7/t2.ml +58 -0
@@ 0,0 1,58 @@
open Lex

module StrMap = Map.Make(String)

type thing =
	| Dir of string
	| File of int

let joinpath l = List.fold_left (^) "" l

let rec f lexbuf path (map: (thing list) StrMap.t) =
	match Lex.token lexbuf with
	| Eof -> map
	| Cd dir -> f lexbuf (dir :: path) map
	| Cdup -> f lexbuf (List.tl path) map
	| Ls -> f lexbuf path map
	| _ as tok ->
		let map, update =
			match tok with
			| Dir d ->
					let update e =
						e |> Option.get |> List.cons (Dir d) |> Option.some
					in
					(StrMap.add (joinpath (d :: path)) [] map, update)
			| File (sz, _) ->
					let update e =
						e |> Option.get |> List.cons (File sz) |> Option.some
					in
					(map, update)
			| _ -> failwith "no way"
		in
		map |> StrMap.update (joinpath path) update |> f lexbuf path

let mem = ref StrMap.empty

let rec solve e map =
	match StrMap.find_opt e !mem with
	| Some v -> v
	| None ->
		let rec aux = function
			| File sz :: l -> sz + aux l
			| Dir d :: l -> solve (d ^ e) map + aux l
			| [] -> 0
		in
		let res = StrMap.find e map |> aux in
		mem := StrMap.add e res !mem;
		res

let find_optimal total _ cand curr =
	if cand < curr && total - cand < 70_000_000 - 30_000_000 then cand
	else curr

let () =
	let map = StrMap.singleton "/" [] in
	let total = f (Lexing.from_channel stdin) [] map |>  solve "/" in
	StrMap.fold (find_optimal total) !mem 70_000_000
		|> Printf.printf "%d\n"