-
Notifications
You must be signed in to change notification settings - Fork 0
/
day10.pl
executable file
·129 lines (98 loc) · 2.84 KB
/
day10.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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
#!/usr/bin/perl
#
# $Id: pl.template,v 1.2 2014/07/18 15:01:38 caran Exp $
#
use strict;
use warnings;
use Data::Printer;
use Path::Tiny;
my $PI = 3.14159265358979;
{ package Asteroid;
sub new {
my ($class, $x, $y) = @_;
my $self = {
x => $x,
y => $y,
theta => {},
};
bless $self, $class;
return $self;
}
}
{ package Grid;
sub blast_asteroids {
my ($self, $station, $max) = @_;
my $count = 0;
while (1) {
for my $theta (sort { $a <=> $b } keys %{ $station->{ theta } }) {
my $target = shift @{ $station->{ theta }{ $theta } };
next unless $target;
$count++;
print "The $count target is at ($target->{ x }, $target->{ y })\n";
return $target if ($count == $max);
}
}
return;
}
sub calc_polar {
my ($self, $x, $y) = @_;
my $r = sqrt( $x ** 2 + $y ** 2 );
my $theta = atan2( $y, $x );
# Part 2 - Convert theta to degrees starting from 0 (N)
return( $r, 0 ) if ($y >= 0 && $x == 0);
return( $r, 180 ) if ($y < 0 && $x == 0);
$theta = ($theta / $PI) * 180;
$theta = (450 - $theta);
$theta -= 360 if ($theta > 360);
return( $r, $theta );
}
sub find_max {
my ($self) = @_;
my $max = 0;
my $max_rock;
for my $rock (@{ $self->{ rocks } }) {
my $count = scalar keys $rock->{ theta };
if ($count > $max) {
$max = $count;
$max_rock = $rock;
}
}
print "Best is $max_rock->{ x }, $max_rock->{ y } with $max other asteroids detected.\n";
return $max_rock;
}
sub find_targets {
my ($self) = @_;
for my $rock (@{ $self->{ rocks } }) {
for my $target (@{ $self->{ rocks } }) {
next if ($target == $rock);
# NOTE: Y-coord is opposite polarity
my ($r, $theta) = $self->calc_polar( $target->{ x } - $rock->{ x }, $rock->{ y } - $target->{ y } );
push @{ $rock->{ theta }{ $theta } }, { r => $r, x => $target->{ x }, y => $target->{ y } };
$rock->{ theta }{ $theta } = [ sort { $a->{ r } <=> $b->{ r } } @{ $rock->{ theta }{ $theta } } ];
}
}
}
sub new {
my ($class, $input_file) = @_;
my $self = {};
my $row = 0;
for my $line (Path::Tiny::path( $input_file )->lines_utf8( { chomp => 1 } )) {
my $pos = 0;
while ((my $col = index( $line, '#', $pos )) >= 0) {
push @{ $self->{ rocks } }, Asteroid->new( $col, $row );
$pos = $col + 1;
}
$row++;
}
$self->{ dim } = $row;
bless $self, $class;
return $self;
}
}
my $input_file = $ARGV[0] || 'input10.txt';
my $grid = Grid->new( $input_file );
$grid->find_targets();
my $station = $grid->find_max();
my $last_target = $grid->blast_asteroids( $station, $ARGV[1] || 200 );
print "The final target has a value of ", $last_target->{ x } * 100 + $last_target->{ y }, "\n";
exit;