1
+ import * as fs from "fs"
2
+
3
+ const input = fs . readFileSync ( "input-day14.txt" , "utf8" )
4
+ const lines = input . trim ( ) . split ( "\n" )
5
+ const recipes = lines
6
+ . map ( line => {
7
+ const [ i , o ] = line . split ( "=>" )
8
+ return [ i . split ( "," ) . map ( s => s . trim ( ) ) . map ( parse ) , parse ( o . trim ( ) ) ] as const
9
+ } )
10
+ . reduce ( ( a , v ) => {
11
+ a . set ( v [ 1 ] [ 1 ] , v )
12
+ return a
13
+ } , new Map < Element , Recipe > ( ) )
14
+
15
+ function parse ( ingredient : string ) : Ingredient {
16
+ const [ c , n ] = ingredient . split ( " " )
17
+ return [ Number ( c ) , n ]
18
+ }
19
+
20
+ function print ( recipe : Recipe ) {
21
+ console . log ( recipe [ 0 ] . map ( i => `${ i [ 0 ] } ${ i [ 1 ] } ` ) . join ( ", " ) , " => " , recipe [ 1 ] [ 0 ] , recipe [ 1 ] [ 1 ] )
22
+ }
23
+
24
+ type Quantity = number
25
+ type Element = string
26
+ type Ingredient = readonly [ Quantity , Element ]
27
+ type Recipe = readonly [ Ingredient [ ] , Ingredient ]
28
+
29
+ class Bag {
30
+ private readonly bag = new Map < Element , Quantity > ( )
31
+ get ( e : Element ) {
32
+ return this . bag . get ( e ) ?? 0
33
+ }
34
+ add ( e : Element , q : Quantity ) {
35
+ this . bag . set ( e , Math . max ( 0 , q + this . get ( e ) ) )
36
+ }
37
+ remove ( e : Element , q : Quantity ) {
38
+ this . add ( e , - q )
39
+ }
40
+ delete ( e : Element ) {
41
+ this . bag . delete ( e )
42
+ }
43
+ entries ( ) {
44
+ return this . bag . entries ( )
45
+ }
46
+ get size ( ) {
47
+ return this . bag . size
48
+ }
49
+ }
50
+
51
+
52
+ function oreForFuel ( quantity : Quantity ) {
53
+ const need = new Bag ( )
54
+ need . add ( "FUEL" , quantity )
55
+
56
+ const spares = new Bag ( )
57
+
58
+ do {
59
+ const [ e , q ] = Array . from ( need . entries ( ) ) . filter ( ( [ e , ] ) => e !== "ORE" ) [ 0 ]
60
+ need . delete ( e )
61
+
62
+ const needs = ingredients ( recipes . get ( e ) , q , spares )
63
+ needs . forEach ( ( [ q , e ] ) => {
64
+ need . add ( e , q )
65
+ } )
66
+ } while ( need . size > 1 )
67
+ return need . get ( "ORE" )
68
+ }
69
+
70
+ function ingredients ( recipe : Recipe , quantity : Quantity , spares : Bag ) : Ingredient [ ] {
71
+ const e = recipe [ 1 ] [ 1 ]
72
+
73
+ const spare = spares . get ( e )
74
+ quantity = Math . max ( 0 , quantity - spare )
75
+ spares . remove ( e , quantity )
76
+ if ( quantity === 0 ) {
77
+ return [ ]
78
+ }
79
+
80
+ const factor = Math . ceil ( quantity / recipe [ 1 ] [ 0 ] )
81
+ const producing = recipe [ 1 ] [ 0 ] * factor
82
+ spares . add ( e , producing - quantity )
83
+ return recipe [ 0 ] . map ( r => ( [ r [ 0 ] * factor , r [ 1 ] ] ) )
84
+ }
85
+
86
+ const maxOre = 1000000000000
87
+ let fuelL = 1
88
+ let fuelU = 1000000000000
89
+
90
+ do {
91
+ let fuel = fuelL + Math . floor ( ( fuelU - fuelL ) / 2 )
92
+ let ore = oreForFuel ( fuel )
93
+ if ( ore < maxOre && oreForFuel ( fuel + 1 ) > maxOre ) {
94
+ console . log ( fuel )
95
+ break
96
+ }
97
+ if ( ore > maxOre ) {
98
+ fuelU = fuel - 1
99
+ } else if ( ore < maxOre ) {
100
+ fuelL = fuel + 1
101
+ }
102
+ } while ( true )
0 commit comments