about summary refs log tree commit diff
path: root/day07.pl
blob: 9bd3b6bd9d6916f24b8d640dbd241f3468c4d522 (plain) (blame)
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
109
110
111
112
113
114
115
116
117
118
119
120
121
#!/usr/bin/perl -w
use v5.16;

use File::Slurper 'read_text';
use List::Util qw'all max reduce';

# https://stackoverflow.com/a/637914
sub permute (&@) {
    my $code = shift;
    my @idx = 0..$#_;
    while ( $code->(@_[@idx]) ) {
        my $p = $#idx;
        --$p while $idx[$p-1] > $idx[$p];
        my $q = $p or return;
        push @idx, reverse splice @idx, $p;
        ++$q while $idx[$p-1] > $idx[$q];
        @idx[$p-1,$q]=@idx[$q,$p-1];
    }
}

sub permutemap (&@) {
  my $code = shift;
  my @a;
  permute { push @a, $code->(@_) } @_;
  @a;
}


say max permutemap {
    reduce {
        my $c = IntCode->new('day07');
        $c->input([$b, $a]);
        until ($c->done) {
            $c->step;
        }
        $c->output->[-1];
    } 0, @_;
} (0..4);

say max permutemap {
    my @cs = map { IntCode->new('day07')->push($_) } @_;
    
    $cs[$_]->pipe($cs[$_+1])  for (0..$#cs - 1);
    $cs[-1]->pipe($cs[0]);

    $cs[0]->push(0);

    until (all { $_->done } @cs) {
        $_->step  for @cs;
    }

    $cs[-1]->output->[-1];
} (5..9);


package IntCode;

use Class::Tiny qw( input output code ip );
use File::Slurper 'read_text';

sub BUILDARGS {
    my $class = shift;
    return { input => [],
             output => [],
             code => [ split ",", read_text(shift) ],
             ip => 0 };
};

sub done {
    my $self = shift;
    $self->code->[$self->ip] == 99;
}

sub pipe {
    my ($self, $other) = @_;
    $self->{output} = $other->{input};
    $self;
}

sub push {
    my $self = shift;
    push @{$self->{input}}, @_;
    $self;
}

sub step {
    my $self = shift;

    no warnings 'uninitialized';
 
    my ($pm3, $pm2, $pm1, $op1, $op2) =
        split '', sprintf("%05d", $self->code->[$self->ip]);
    my $op = $op1 . $op2;
    my $p1 = $pm1 ? $self->code->[$self->ip + 1] :
        $self->code->[$self->code->[$self->ip + 1]];
    my $p2 = $pm2 ? $self->code->[$self->ip+2] :
        $self->code->[$self->code->[$self->ip + 2]];
    my $p3 = $pm3 ? $self->code->[$self->ip+3] :
        $self->code->[$self->code->[$self->ip + 3]];

    if    ($op == 1) { $self->code->[$self->code->[$self->ip+3]] = $p1 + $p2;
                       $self->{ip} += 4; }
    elsif ($op == 2) { $self->code->[$self->code->[$self->ip+3]] = $p1 * $p2;
                       $self->{ip} += 4; }
    elsif ($op == 3) { return unless (@{$self->{input}});  # stall
                       $self->code->[$self->code->[$self->ip+1]] =
                           shift @{$self->{input}};
                       $self->{ip} += 2; }
    elsif ($op == 4) { CORE::push @{$self->{output}}, $p1;
                       $self->{ip} += 2; }
    elsif ($op == 5) { $self->{ip} =  $p1 ? $p2 : $self->ip +  3; }
    elsif ($op == 6) { $self->{ip} = !$p1 ? $p2 : $self->ip +  3; }
    elsif ($op == 7) { $self->code->[$self->code->[$self->ip+3]] = $p1 < $p2;
                       $self->{ip} += 4; }
    elsif ($op == 8) { $self->code->[$self->code->[$self->ip+3]] = $p1 == $p2;
                       $self->{ip} += 4; }

    $self;
}

1;