Skip to content

Commit 492fe52

Browse files
authored
Merge branch 'main' into day7
2 parents 3169831 + f631be4 commit 492fe52

File tree

5 files changed

+171
-5
lines changed

5 files changed

+171
-5
lines changed

days/day-07/solutions/.keep

Whitespace-only changes.

days/day-07/solutions/day07.mjs

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
import { readFileSync } from "fs";
2+
import { resolve } from "path";
3+
4+
const STANDARD_IN = 0
5+
const input = readFileSync(STANDARD_IN)
6+
.toString();
7+
8+
// (light red) bags contain (1) (bright white) bag, (2) muted yellow bags.
9+
// /^([\w]+ [\w]+) bags contain (.*)[.]$/g
10+
11+
const bags = [
12+
...input.matchAll(/([\w]+ [\w]+) bags contain (\d (.*)[.]|no other bags)/g)
13+
].map(([,color, rest]) => {
14+
15+
const bags_inside = ([
16+
...rest.matchAll(/(\d) ([\w]+ [\w]+)/g)
17+
])
18+
.map(([,count, color]) => ({count, color}))
19+
20+
return ({color, bags_inside})
21+
})
22+
23+
const COLOR_SHINY_GOLD = "shiny gold";
24+
25+
26+
27+
// --- Part 1 ----
28+
// Recursively find shiny golden bags
29+
function findShinyGoldenBag(bag_refs) {
30+
if (bag_refs.length === 0) {
31+
return 0;
32+
}
33+
34+
const resolved_bags = bag_refs.map(bag => bags.find(({color}) => color === bag.color))
35+
36+
for (const { color, bags_inside } of resolved_bags) {
37+
if (color === COLOR_SHINY_GOLD) {
38+
return 1;
39+
} else {
40+
const found = findShinyGoldenBag(bags_inside);
41+
if (found) {
42+
return 1;
43+
} else {
44+
continue;
45+
}
46+
}
47+
}
48+
return 0;
49+
}
50+
51+
const bagContainingShinyGoldeBagCount = bags
52+
.reduce((count, bag) => count + findShinyGoldenBag(bag.bags_inside), 0);
53+
54+
55+
// --- Part 2 ---
56+
// Recursively count bags inside
57+
function countBagsInside(bag_refs) {
58+
if (bag_refs.length === 0) {
59+
return 1;
60+
}
61+
62+
const resolved_bags = bag_refs
63+
.map(bag => [bag.count, bags.find(({color}) => color === bag.color)])
64+
65+
66+
const count = resolved_bags
67+
.reduce((acc, [bag_count, bag]) => acc + bag_count * countBagsInside(bag.bags_inside), 1)
68+
69+
return count;
70+
}
71+
72+
const shinyGoldenBag = bags.find(({color}) => color === COLOR_SHINY_GOLD);
73+
74+
75+
const shinyGoldBagInsideCount = countBagsInside(shinyGoldenBag.bags_inside) - 1;
76+
77+
78+
console.log(bagContainingShinyGoldeBagCount)
79+
console.log(shinyGoldBagInsideCount)
80+
81+
82+
83+

days/day-07/solutions/day07.sml

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
use "../../../util.sml";
2+
3+
local
4+
structure SS = StringSet
5+
structure SM = StringMap
6+
in
7+
8+
fun toDigit c = Char.ord c - Char.ord #"0"
9+
fun toRule s =
10+
let
11+
val (parent, rawChildClauses) =
12+
case String.substring (s, 0, String.size s - 1)
13+
>> String.fields (fn c => c = #" ")
14+
>> splitWith (fn x => x = "contain") of
15+
[a, b] => (String.concatWith " " a, String.concatWith " " b)
16+
| _ => raise Fail $ "bad input: " ^ s
17+
(* sigh *)
18+
fun clause 0 (#" " :: rest) = clause 0 rest
19+
| clause 1 (#" " :: name) = SOME (1, (String.implode name) ^ "s")
20+
| clause n (#" " :: name) = SOME (n, String.implode name)
21+
| clause n (#"n" :: _) = NONE
22+
| clause n (x :: rest) = clause (n*10 + toDigit x) rest
23+
| clause _ _ = NONE
24+
25+
val childClauses = String.fields (fn c => c = #",") rawChildClauses
26+
>> List.mapPartial (clause 0 o String.explode)
27+
in
28+
(parent, childClauses)
29+
end
30+
31+
fun solve1 clauses =
32+
let fun consRule s p c = SM.updateWithDefault [] (fn xs => p :: xs) c s
33+
fun invertRules ((p, cs), s) = List.foldl (fn ((_, c), s) => consRule s p c) s cs
34+
val rules = List.foldl invertRules SM.empty clauses
35+
fun dfs n seen [] = n
36+
| dfs n seen (x :: xs) =
37+
if SS.contains x seen then
38+
dfs n seen xs
39+
else
40+
let val children = getOpt (SM.lookup x rules, [])
41+
in
42+
dfs (n + 1) (SS.insert x seen) (children @ xs)
43+
end
44+
in
45+
dfs ~1 SS.empty ["shiny gold bags"]
46+
end
47+
48+
fun solve2 clauses =
49+
let val rules = SM.fromList clauses
50+
fun sum ((count, name), acc) = acc + count + count * dfs name
51+
and dfs k = List.foldl sum 0 $ valOf $ SM.lookup k rules
52+
in
53+
dfs "shiny gold bags"
54+
end
55+
56+
fun main () =
57+
let val input = TextIO.inputAll TextIO.stdIn
58+
>> String.tokens (fn c => c = #"\n")
59+
>> List.map toRule
60+
in
61+
println $ Int.toString $ solve1 input;
62+
println $ Int.toString $ solve2 input
63+
end
64+
end

days/day-07/test.sh

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ D=$(dirname $(realpath $0))
66

77
echo ""
88
echo "--- Day 7: Handy Haversacks ---"
9-
$D/../../languages/python.sh $D/input.txt $D/output.txt $D/solutions/day07.stektpotet.py
9+
$D/../../languages/sml.sh $D/input.txt $D/output.txt $D/solutions/day07.sml
1010
$D/../../languages/go.sh $D/input.txt $D/output.txt $D/solutions/tholok97.go
11+
$D/../../languages/python.sh $D/input.txt $D/output.txt $D/solutions/day07.stektpotet.py
12+
$D/../../languages/node.sh $D/input.txt $D/output.txt $D/solutions/day07.mjs
1113
echo ""

util.sml

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,14 @@ fun println x = print $ x ^ "\n"
66
fun splitWith pred list =
77
let
88
fun acc done [] [] = done
9-
| acc done last [] = last :: done
9+
| acc done last [] = List.rev last :: done
1010
| acc done last (x :: xs) =
1111
if pred x then
12-
acc (last :: done) [] xs
12+
acc (List.rev last :: done) [] xs
1313
else
1414
acc done (x :: last) xs
1515
in
16-
acc [] [] list
16+
List.rev $ acc [] [] list
1717
end
1818

1919
fun foldl' f (x :: xs) = List.foldl f x xs
@@ -22,6 +22,7 @@ fun foldl' f (x :: xs) = List.foldl f x xs
2222
val listSum = List.foldl (op +) 0
2323
val listProduct = List.foldl (op *) 1
2424

25+
2526
signature ORD =
2627
sig
2728
type t
@@ -37,6 +38,8 @@ sig
3738
val empty : 'a Coll
3839
val lookup : K -> 'a Coll -> 'a option
3940
val insert : K -> 'a -> 'a Coll -> 'a Coll
41+
val update : ('a option -> 'a) -> K -> 'a Coll -> 'a Coll
42+
val updateWithDefault : 'a -> ('a -> 'a) -> K -> 'a Coll -> 'a Coll
4043
val foldl : (K * 'a * 'b -> 'b) -> 'b -> 'a Coll -> 'b
4144
val size : 'a Coll -> int
4245
val fromList : (K * 'a) list -> 'a Coll
@@ -83,6 +86,13 @@ fun insert k v s =
8386
T (B, a, y, b)
8487
end
8588

89+
fun update f k coll =
90+
insert k (f $ lookup k coll) coll
91+
92+
fun updateWithDefault default f k coll =
93+
update (fn v => f $ getOpt (v, default)) k coll
94+
95+
8696
fun foldl f acc E = acc
8797
| foldl f acc (T(_, a, (k, v), b)) =
8898
let
@@ -97,7 +107,6 @@ fun size coll = foldl (fn (_, _, n) => n + 1) 0 coll
97107
fun fromList list = List.foldl (fn ((k, v), s) => insert k v s) empty list
98108
end
99109

100-
101110
signature SET =
102111
sig
103112
type V
@@ -136,3 +145,11 @@ structure CharMap = Map(
136145
end)
137146

138147
structure CharSet = Set(CharMap)
148+
149+
structure StringMap = Map(
150+
struct
151+
type t = string
152+
val cmp = String.compare
153+
end)
154+
155+
structure StringSet = Set(StringMap)

0 commit comments

Comments
 (0)