-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathday14.pl
executable file
·108 lines (85 loc) · 2.26 KB
/
day14.pl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
#!/usr/bin/env perl
#
use strict;
use warnings;
use utf8;
use Path::Tiny;
use POSIX qw( ceil );
{ package Reaction;
sub new {
my ($class, $input) = @_;
my $self = {
out => {},
in => {},
};
my ($i, $q, $o) = ($input =~ /^(.*?)\s*=>\s*(\d+)\s(.*)$/);
for my $chem (split /,\s*/, $i) {
$chem =~ /^(\d+)\s(.*)$/;
$self->{ in }{ $2 } = $1;
}
$self->{ out } = $o;
$self->{ quant } = $q;
bless $self, $class;
return $self;
}
}
{ package Nanofactory;
sub make {
my ($self, $need) = @_;
my $done = 1;
for my $chem (keys %{ $need }) {
next if ($chem eq 'ORE');
next if ($need->{ $chem } <= 0);
$done = 0;
my $react = $self->{ react }[$self->{ out }{ $chem }];
my $num_react = POSIX::ceil( $need->{ $chem } / $react->{ quant } );
$need->{ $chem } -= $react->{ quant } * $num_react;
for my $inp (keys %{ $react->{ in } }) {
$need->{ $inp } += $react->{ in }{ $inp } * $num_react;
}
}
return $done ? $need : $self->make( $need );
}
sub new {
my ($class, $input_file) = @_;
my $self = {
react => [],
out => {},
};
for (Path::Tiny::path( $input_file )->lines_utf8( { chomp => 1 } )) {
my $react = Reaction->new( $_ );
my $out = $react->{ out };
die "Multiple reactions create $out" if ($self->{ out }{ $out });
$self->{ out }{ $out } = @{ $self->{ react } };
push @{ $self->{ react } }, $react;
}
bless $self, $class;
return $self;
}
}
my $input_file = $ARGV[0] || 'input14.txt';
my $fact = Nanofactory->new( $input_file );
my $amount = $ARGV[1] || 1;
my $make = $fact->make( { FUEL => 1 } );
if ($amount == 1) {
# Part A
my $make = $fact->make( { FUEL => $amount } );
print "It takes ", $make->{ ORE }, " ORE to make fuel\n";
}
else {
# Part B
my $one_fuel = $make->{ ORE };
my $fuel = int( $amount / $one_fuel );
my $ore;
do {
$make = $fact->make( { FUEL => $fuel } );
$ore = $amount - $make->{ ORE };
$fuel += int( $ore / $one_fuel );
} while ($ore >= $one_fuel);
# We are within one fuel unit - keep trying
while ($fact->make( { FUEL => $fuel + 1 } )->{ ORE } < $amount) {
$fuel++;
}
print "You can make $fuel with $amount ORE\n";
}
exit;