about summary refs log tree commit diff
path: root/day09.pl
blob: d295b6a2bcb5a2831a1f48a185a4f553cd56569d (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
#!/usr/bin/perl -w
use v5.16;

say IntCode->new('day09')->run(1);  # 3063082071
say IntCode->new('day09')->run(2);  # 81348


package IntCode;

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

sub BUILDARGS {
    my $class = shift;
    return { input => [],
             output => [],
             code => [ split ",", read_text(shift) ],
             ip => 0,
             base => 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 run {
    my $self = shift;
    $self->{input} = [ @_ ];
    until ($self->done) {
        $self->step;
    }
    @{$self->output};
}

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 == 0 ? $self->code->[$self->code->[$self->ip + 1]]
           : $pm1 == 1 ? $self->code->[$self->ip + 1]
           : $pm1 == 2 ? $self->code->[$self->code->[$self->ip + 1] +
                                       $self->base]
           : undef;
    my $p2 = $pm2 == 0 ? $self->code->[$self->code->[$self->ip + 2]]
           : $pm2 == 1 ? $self->code->[$self->ip + 2]
           : $pm2 == 2 ? $self->code->[$self->code->[$self->ip + 2] +
                                       $self->base]
           : undef;
    my $p3 = $pm3 == 0 ? $self->code->[$self->code->[$self->ip + 3]]
           : $pm3 == 1 ? $self->code->[$self->ip + 3]
           : $pm3 == 2 ? $self->code->[$self->code->[$self->ip + 3] +
                                       $self->base]
           : undef;
    my $w3 = $self->code->[$self->ip+3] + ($pm3 == 2 ? $self->base : 0);
    if    ($op == 1) { $self->code->[$w3] = $p1 + $p2;      $self->{ip} += 4; }
    elsif ($op == 2) { $self->code->[$w3] = $p1 * $p2;      $self->{ip} += 4; }
    elsif ($op == 3) { return unless (@{$self->{input}});  # stall
                       $self->code->[$self->code->[$self->ip+1] +
                                     ($pm1 == 2 ? $self->base : 0)] =
                           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->[$w3] = $p1 < $p2;      $self->{ip} += 4; }
    elsif ($op == 8) { $self->code->[$w3] = $p1 == $p2;     $self->{ip} += 4; }
    elsif ($op == 9) { $self->{base} += $p1;                $self->{ip} += 2; }
    else { say "INVALID OP"; }

    $self;
}

1;