-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy path19.pl
83 lines (75 loc) · 1.97 KB
/
19.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
#!/usr/bin/perl -w
use strict;
use feature 'say';
use List::Util qw/sum min max reduce any all none notall first product uniq pairs mesh zip/;
use Storable qw(dclone);
my %H;
# Split a semi-open range [min,max) at value.
sub split_range {
my ($min, $max, $value) = @_;
if ($value <= $min) {
return (undef, [$min,$max]);
} elsif ($value >= $max) {
return ([$min,$max], undef);
}
return ([$min,$value], [$value,$max]);
}
# Follow the workflow tree and count accepted cases
sub scan {
my $w = shift; # Current workflow
my $cond = shift; # hash from key to [min,max) for that key
return 0 if ($w eq 'R');
return product(map {$_->[1]-$_->[0]} values(%$cond)) if ($w eq 'A');
my $res = 0;
for my $st (@{$H{$w}}) {
my ($c,$op,$n,$nw) = $st =~ /^(?:(.)(.)(\d+):)?(\w+)$/o or die;
# Unconditional jump
if (!defined($c)) {
$res += scan($nw,$cond);
last;
}
# Condition, correct for > not being >=
my ($lo,$hi) = split_range(@{$cond->{$c}}, $n + ($op eq '>'));
# Recurse when condition is true
my $ncond = dclone($cond);
$ncond->{$c} = ($op eq '<' ? $lo : $hi) or next;
$res += scan($nw, $ncond);
# Loop when condition is false
$cond->{$c} = ($op eq '<' ? $hi : $lo) or last;
}
return $res;
}
# Read workflows
while (<>) {
chomp;
last unless $_;
my ($n,$w) = m%(\w+)\{(.+)\}$% or die;
$H{$n} = [split(',',$w)];
}
# Solve part 1
my $sum=0;
while (<>) {
chomp;
last unless $_;
($_) = m%^{(.*)}$%;
my %v = map {split('=', $_)} split(',');
# Follow workflow, @w is remaining actions.
my @w = @{$H{'in'}};
while (@w) {
my $st = shift @w;
my ($c,$op,$n,$nw) = $st =~ /^(?:(.)(.)(\d+):)?(\w+)$/o or die;
if (!defined($c) || eval ($v{$c}." $op $n")) {
if ($nw eq 'A') {
$sum += sum(values %v);
last;
}
if ($nw eq 'R') {
last;
}
@w = @{$H{$nw}};
}
}
}
say $sum;
# Part 2 with initial map
say scan('in',{map {$_ => [1,4001]} qw/x m a s/});