|  line  | 
 stmt  | 
 bran  | 
 cond  | 
 sub  | 
 pod  | 
 time  | 
 code  | 
| 
1
 | 
  
 
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # -*- Perl -*-  | 
| 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 #  | 
| 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # Dijkstra Map path finding. run perldoc(1) on this file for additional  | 
| 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # documentation  | 
| 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 package Game::DijkstraMap;  | 
| 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
8
 | 
2
 | 
 
 | 
 
 | 
  
2
  
 | 
 
 | 
181349
 | 
 use 5.24.0;  | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
17
 | 
    | 
| 
9
 | 
2
 | 
 
 | 
 
 | 
  
2
  
 | 
 
 | 
12
 | 
 use warnings;  | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4
 | 
    | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
60
 | 
    | 
| 
10
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
11
 | 
2
 | 
 
 | 
 
 | 
  
2
  
 | 
 
 | 
10
 | 
 use Carp qw(croak);  | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4
 | 
    | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
137
 | 
    | 
| 
12
 | 
2
 | 
 
 | 
 
 | 
  
2
  
 | 
 
 | 
14
 | 
 use List::Util 1.26 qw(shuffle sum0);  | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
37
 | 
    | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
197
 | 
    | 
| 
13
 | 
2
 | 
 
 | 
 
 | 
  
2
  
 | 
 
 | 
1133
 | 
 use Moo;  | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
22242
 | 
    | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
10
 | 
    | 
| 
14
 | 
2
 | 
 
 | 
 
 | 
  
2
  
 | 
 
 | 
3975
 | 
 use namespace::clean;  | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
22286
 | 
    | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
15
 | 
    | 
| 
15
 | 
2
 | 
 
 | 
 
 | 
  
2
  
 | 
 
 | 
629
 | 
 use Scalar::Util qw(looks_like_number);  | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
5
 | 
    | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
141
 | 
    | 
| 
16
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
17
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 our $VERSION = '1.02';  | 
| 
18
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
19
 | 
2
 | 
 
 | 
 
 | 
  
2
  
 | 
 
 | 
14
 | 
 use constant SQRT2 => sqrt(2);  | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
5
 | 
    | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
7495
 | 
    | 
| 
20
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 has bad_cost => ( is => 'rw', default => sub { -2147483648 } );  | 
| 
22
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 has min_cost => ( is => 'rw', default => sub { 0 } );  | 
| 
23
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 has max_cost => ( is => 'rw', default => sub { 2147483647 } );  | 
| 
24
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
25
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 has costfn => (  | 
| 
26
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     is      => 'rw',  | 
| 
27
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     default => sub {  | 
| 
28
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         return sub {  | 
| 
29
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             my ( $self, $c ) = @_;  | 
| 
30
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             if ( $c eq '#' ) { return $self->bad_cost }  | 
| 
31
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             if ( $c eq 'x' ) { return $self->min_cost }  | 
| 
32
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             return $self->max_cost;  | 
| 
33
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         };  | 
| 
34
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
35
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 );  | 
| 
36
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 has dimap  => ( is => 'rw' );  | 
| 
37
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 has iters  => ( is => 'rwp', default => sub { 0 } );  | 
| 
38
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 has next_m => ( is => 'rw', default => sub { 'next' } );  | 
| 
39
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 has normfn => ( is => 'rw', default => sub { \&norm_4way } );  | 
| 
40
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
41
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub BUILD {  | 
| 
42
 | 
9
 | 
 
 | 
 
 | 
  
9
  
 | 
  
0
  
 | 
44
 | 
     my ( $self, $param ) = @_;  | 
| 
43
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     croak "cannot have both map and str2map arguments"  | 
| 
44
 | 
9
 | 
  
 50
  
 | 
  
 66
  
 | 
 
 | 
 
 | 
47
 | 
       if exists $param->{'map'} and exists $param->{'str2map'};  | 
| 
45
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     $self->map( $param->{'map'} )  | 
| 
46
 | 
8
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
20
 | 
       if exists $param->{'map'};  | 
| 
47
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     $self->map( $self->str2map( $param->{'str2map'} ) )  | 
| 
48
 | 
8
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
39
 | 
       if exists $param->{'str2map'};  | 
| 
49
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
50
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
51
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub adjacent_values {  | 
| 
52
 | 
5
 | 
 
 | 
 
 | 
  
5
  
 | 
  
1
  
 | 
4834
 | 
     my ( $dimap, $r, $c, $maxrow, $maxcol ) = @_;  | 
| 
53
 | 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
10
 | 
     my @values;  | 
| 
54
 | 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
10
 | 
     for my $i ( -1, 1 ) {  | 
| 
55
 | 
10
 | 
 
 | 
 
 | 
 
 | 
 
 | 
15
 | 
         my $x = $c + $i;  | 
| 
56
 | 
10
 | 
  
100
  
 | 
  
100
  
 | 
 
 | 
 
 | 
41
 | 
         push @values, $dimap->[$r][$x] if $x >= 0 and $x <= $maxcol;  | 
| 
57
 | 
10
 | 
 
 | 
 
 | 
 
 | 
 
 | 
19
 | 
         for my $j ( -1 .. 1 ) {  | 
| 
58
 | 
30
 | 
 
 | 
 
 | 
 
 | 
 
 | 
42
 | 
             $x = $r + $i;  | 
| 
59
 | 
30
 | 
 
 | 
 
 | 
 
 | 
 
 | 
38
 | 
             my $y = $c + $j;  | 
| 
60
 | 
30
 | 
  
100
  
 | 
  
100
  
 | 
 
 | 
 
 | 
119
 | 
             push @values, $dimap->[$x][$y]  | 
| 
 
 | 
 
 | 
 
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
 
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
61
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
               if $x >= 0  | 
| 
62
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
               and $x <= $maxrow  | 
| 
63
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
               and $y >= 0  | 
| 
64
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
               and $y <= $maxcol;  | 
| 
65
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
66
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
67
 | 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
21
 | 
     return @values;  | 
| 
68
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
69
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
70
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub adjacent_values_diag {  | 
| 
71
 | 
50
 | 
 
 | 
 
 | 
  
50
  
 | 
  
1
  
 | 
1997
 | 
     my ( $dimap, $r, $c, $maxrow, $maxcol ) = @_;  | 
| 
72
 | 
50
 | 
 
 | 
 
 | 
 
 | 
 
 | 
58
 | 
     my @values;  | 
| 
73
 | 
50
 | 
  
100
  
 | 
  
100
  
 | 
 
 | 
 
 | 
149
 | 
     push @values, $dimap->[ $r - 1 ][ $c - 1 ] if $r > 0       and $c > 0;  | 
| 
74
 | 
50
 | 
  
100
  
 | 
  
100
  
 | 
 
 | 
 
 | 
130
 | 
     push @values, $dimap->[ $r - 1 ][ $c + 1 ] if $r > 0       and $c < $maxcol;  | 
| 
75
 | 
50
 | 
  
100
  
 | 
  
100
  
 | 
 
 | 
 
 | 
138
 | 
     push @values, $dimap->[ $r + 1 ][ $c - 1 ] if $r < $maxrow and $c > 0;  | 
| 
76
 | 
50
 | 
  
100
  
 | 
  
100
  
 | 
 
 | 
 
 | 
137
 | 
     push @values, $dimap->[ $r + 1 ][ $c + 1 ] if $r < $maxrow and $c < $maxcol;  | 
| 
77
 | 
50
 | 
 
 | 
 
 | 
 
 | 
 
 | 
186
 | 
     return @values;  | 
| 
78
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
79
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
80
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub adjacent_values_sq {  | 
| 
81
 | 
230
 | 
 
 | 
 
 | 
  
230
  
 | 
  
1
  
 | 
2151
 | 
     my ( $dimap, $r, $c, $maxrow, $maxcol ) = @_;  | 
| 
82
 | 
230
 | 
 
 | 
 
 | 
 
 | 
 
 | 
286
 | 
     my @values;  | 
| 
83
 | 
230
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
416
 | 
     push @values, $dimap->[$r][ $c - 1 ] if $c > 0;  | 
| 
84
 | 
230
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
438
 | 
     push @values, $dimap->[$r][ $c + 1 ] if $c < $maxcol;  | 
| 
85
 | 
230
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
402
 | 
     push @values, $dimap->[ $r - 1 ][$c] if $r > 0;  | 
| 
86
 | 
230
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
408
 | 
     push @values, $dimap->[ $r + 1 ][$c] if $r < $maxrow;  | 
| 
87
 | 
230
 | 
 
 | 
 
 | 
 
 | 
 
 | 
498
 | 
     return @values;  | 
| 
88
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
89
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
90
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub dimap_with {  | 
| 
91
 | 
2
 | 
 
 | 
 
 | 
  
2
  
 | 
  
1
  
 | 
54
 | 
     my ( $self, $param ) = @_;  | 
| 
92
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
8
 | 
     my $dimap = $self->dimap;  | 
| 
93
 | 
2
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
15
 | 
     croak "cannot make new dimap from unset map" if !defined $dimap;  | 
| 
94
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3
 | 
     my $new_dimap;  | 
| 
95
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3
 | 
     my $badcost = $self->bad_cost;  | 
| 
96
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4
 | 
     my $cols    = $dimap->[0]->$#*;  | 
| 
97
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
5
 | 
     for my $r ( 0 .. $dimap->$#* ) {  | 
| 
98
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
8
 | 
       COL: for my $c ( 0 .. $cols ) {  | 
| 
99
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
13
 | 
             my $value = $dimap->[$r][$c];  | 
| 
100
 | 
9
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
18
 | 
             if ( $value == $badcost ) {  | 
| 
101
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
                 $new_dimap->[$r][$c] = $badcost;  | 
| 
102
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
                 next COL;  | 
| 
103
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             }  | 
| 
104
 | 
9
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
19
 | 
             $value *= $param->{my_weight} // 1;  | 
| 
105
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
25
 | 
             my @here = map $_->values( [ $r, $c ] )->[0], $param->{objs}->@*;  | 
| 
106
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
18
 | 
             for my $h ( 0 .. $#here ) {  | 
| 
107
 | 
17
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
34
 | 
                 if ( $here[$h] == $badcost ) {  | 
| 
108
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3
 | 
                     $new_dimap->[$r][$c] = $badcost;  | 
| 
109
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4
 | 
                     next COL;  | 
| 
110
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 }  | 
| 
111
 | 
16
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
45
 | 
                 $value += $here[$h] * ( $param->{weights}->[$h] // 0 );  | 
| 
112
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             }  | 
| 
113
 | 
8
 | 
 
 | 
 
 | 
 
 | 
 
 | 
16
 | 
             $new_dimap->[$r][$c] = $value;  | 
| 
114
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
115
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
116
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
36
 | 
     return $new_dimap;  | 
| 
117
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
118
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
119
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub map {  | 
| 
120
 | 
8
 | 
 
 | 
 
 | 
  
8
  
 | 
  
1
  
 | 
8841
 | 
     my ( $self, $map ) = @_;  | 
| 
121
 | 
8
 | 
 
 | 
 
 | 
 
 | 
 
 | 
16
 | 
     my $dimap = [];  | 
| 
122
 | 
8
 | 
  
 50
  
 | 
  
 66
  
 | 
 
 | 
 
 | 
84
 | 
     croak "no valid map supplied"  | 
| 
 
 | 
 
 | 
 
 | 
  
 66
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
 
 | 
  
 66
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
123
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       if !defined $map  | 
| 
124
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       or ref $map ne 'ARRAY'  | 
| 
125
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       or !defined $map->[0]  | 
| 
126
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       or ref $map->[0] ne 'ARRAY';  | 
| 
127
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
17
 | 
     my $cols = $map->[0]->@*;  | 
| 
128
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
25
 | 
     for my $r ( 0 .. $map->$#* ) {  | 
| 
129
 | 
21
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
46
 | 
         croak "unexpected column count at row $r" if $map->[$r]->@* != $cols;  | 
| 
130
 | 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
36
 | 
         for my $c ( 0 .. $cols - 1 ) {  | 
| 
131
 | 
81
 | 
 
 | 
 
 | 
 
 | 
 
 | 
162
 | 
             $dimap->[$r][$c] = $self->costfn->( $self, $map->[$r][$c] );  | 
| 
132
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
133
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
134
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     $self->_set_iters(  | 
| 
135
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
32
 | 
         $self->normfn->( $dimap, $self->min_cost, $self->max_cost ) );  | 
| 
136
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
24
 | 
     $self->dimap($dimap);  | 
| 
137
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
77
 | 
     return $self;  | 
| 
138
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
139
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
140
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub next {  | 
| 
141
 | 
16
 | 
 
 | 
 
 | 
  
16
  
 | 
  
1
  
 | 
7233
 | 
     my ( $self, $r, $c, $value ) = @_;  | 
| 
142
 | 
16
 | 
 
 | 
 
 | 
 
 | 
 
 | 
35
 | 
     my $dimap = $self->dimap;  | 
| 
143
 | 
16
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
63
 | 
     croak "cannot pathfind on unset map" if !defined $dimap;  | 
| 
144
 | 
13
 | 
 
 | 
 
 | 
 
 | 
 
 | 
20
 | 
     my $maxrow = $dimap->$#*;  | 
| 
145
 | 
13
 | 
 
 | 
 
 | 
 
 | 
 
 | 
26
 | 
     my $maxcol = $dimap->[0]->$#*;  | 
| 
146
 | 
13
 | 
  
 50
  
 | 
  
 33
  
 | 
 
 | 
 
 | 
57
 | 
     croak "row $r out of bounds" if $r > $maxrow or $r < 0;  | 
| 
147
 | 
13
 | 
  
 50
  
 | 
  
 33
  
 | 
 
 | 
 
 | 
49
 | 
     croak "col $c out of bounds" if $c > $maxcol or $c < 0;  | 
| 
148
 | 
13
 | 
 
 | 
 
 | 
 
 | 
 
 | 
21
 | 
     my @adj;  | 
| 
149
 | 
13
 | 
 
 | 
  
100
  
 | 
 
 | 
 
 | 
50
 | 
     $value //= $dimap->[$r][$c];  | 
| 
150
 | 
13
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
36
 | 
     return \@adj if $value <= $self->min_cost;  | 
| 
151
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
152
 | 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
25
 | 
     for my $i ( -1, 1 ) {  | 
| 
153
 | 
24
 | 
 
 | 
 
 | 
 
 | 
 
 | 
35
 | 
         my $x = $c + $i;  | 
| 
154
 | 
24
 | 
  
100
  
 | 
  
 66
  
 | 
 
 | 
 
 | 
93
 | 
         push @adj, [ [ $r, $x ], $dimap->[$r][$x] ] if $x >= 0 and $x <= $maxcol;  | 
| 
155
 | 
24
 | 
 
 | 
 
 | 
 
 | 
 
 | 
41
 | 
         for my $j ( -1 .. 1 ) {  | 
| 
156
 | 
72
 | 
 
 | 
 
 | 
 
 | 
 
 | 
97
 | 
             $x = $r + $i;  | 
| 
157
 | 
72
 | 
 
 | 
 
 | 
 
 | 
 
 | 
91
 | 
             my $y = $c + $j;  | 
| 
158
 | 
72
 | 
  
100
  
 | 
  
 66
  
 | 
 
 | 
 
 | 
331
 | 
             push @adj, [ [ $x, $y ], $dimap->[$x][$y] ]  | 
| 
 
 | 
 
 | 
 
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
 
 | 
  
 66
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
159
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
               if $x >= 0  | 
| 
160
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
               and $x <= $maxrow  | 
| 
161
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
               and $y >= 0  | 
| 
162
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
               and $y <= $maxcol;  | 
| 
163
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
164
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
165
 | 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
25
 | 
     my $badcost = $self->bad_cost;  | 
| 
166
 | 
12
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
23
 | 
     return [ grep { $_->[1] < $value and $_->[1] != $badcost } @adj ];  | 
| 
 
 | 
76
 | 
 
 | 
 
 | 
 
 | 
 
 | 
307
 | 
    | 
| 
167
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
168
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
169
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub next_best {  | 
| 
170
 | 
15
 | 
 
 | 
 
 | 
  
15
  
 | 
  
1
  
 | 
683
 | 
     my ( $self, $r, $c ) = @_;  | 
| 
171
 | 
15
 | 
 
 | 
 
 | 
 
 | 
 
 | 
33
 | 
     my $method = $self->next_m;  | 
| 
172
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     my @ret =  | 
| 
173
 | 
15
 | 
 
 | 
 
 | 
 
 | 
 
 | 
41
 | 
       sort { $a->[1] <=> $b->[1] } shuffle $self->$method( $r, $c )->@*;  | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
7
 | 
    | 
| 
174
 | 
13
 | 
 
 | 
 
 | 
 
 | 
 
 | 
88
 | 
     return $ret[0]->[0];  | 
| 
175
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
176
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
177
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # next() but only in square directions or "orthogonal" (but diagonals  | 
| 
178
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # are orthogonal to one another) or in the "cardinal directions" (NSEW)  | 
| 
179
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # but that term also seems unsatisfactory. "4-way" is also used for this  | 
| 
180
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # with the assumption of cardinal directions  | 
| 
181
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub next_sq {  | 
| 
182
 | 
7
 | 
 
 | 
 
 | 
  
7
  
 | 
  
1
  
 | 
748
 | 
     my ( $self, $r, $c, $value ) = @_;  | 
| 
183
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
14
 | 
     my $dimap = $self->dimap;  | 
| 
184
 | 
7
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
25
 | 
     croak "cannot pathfind on unset map" if !defined $dimap;  | 
| 
185
 | 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
9
 | 
     my $maxrow = $dimap->$#*;  | 
| 
186
 | 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
11
 | 
     my $maxcol = $dimap->[0]->$#*;  | 
| 
187
 | 
6
 | 
  
 50
  
 | 
  
 33
  
 | 
 
 | 
 
 | 
24
 | 
     croak "row $r out of bounds" if $r > $maxrow or $r < 0;  | 
| 
188
 | 
6
 | 
  
 50
  
 | 
  
 33
  
 | 
 
 | 
 
 | 
18
 | 
     croak "col $c out of bounds" if $c > $maxcol or $c < 0;  | 
| 
189
 | 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
11
 | 
     my @adj;  | 
| 
190
 | 
6
 | 
 
 | 
  
 66
  
 | 
 
 | 
 
 | 
21
 | 
     $value //= $dimap->[$r][$c];  | 
| 
191
 | 
6
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
19
 | 
     return \@adj if $value <= $self->min_cost;  | 
| 
192
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
193
 | 
5
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
12
 | 
     if ( $c > 0 ) {  | 
| 
194
 | 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
15
 | 
         push @adj, [ [ $r, $c - 1 ], $dimap->[$r][ $c - 1 ] ];  | 
| 
195
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
196
 | 
5
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
10
 | 
     if ( $c < $maxcol ) {  | 
| 
197
 | 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
12
 | 
         push @adj, [ [ $r, $c + 1 ], $dimap->[$r][ $c + 1 ] ];  | 
| 
198
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
199
 | 
5
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
12
 | 
     if ( $r > 0 ) {  | 
| 
200
 | 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
12
 | 
         push @adj, [ [ $r - 1, $c ], $dimap->[ $r - 1 ][$c] ];  | 
| 
201
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
202
 | 
5
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
10
 | 
     if ( $r < $maxrow ) {  | 
| 
203
 | 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
12
 | 
         push @adj, [ [ $r + 1, $c ], $dimap->[ $r + 1 ][$c] ];  | 
| 
204
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
205
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
206
 | 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
11
 | 
     my $badcost = $self->bad_cost;  | 
| 
207
 | 
5
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
9
 | 
     return [ grep { $_->[1] < $value and $_->[1] != $badcost } @adj ];  | 
| 
 
 | 
20
 | 
 
 | 
 
 | 
 
 | 
 
 | 
71
 | 
    | 
| 
208
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
209
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
210
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub next_with {  | 
| 
211
 | 
1
 | 
 
 | 
 
 | 
  
1
  
 | 
  
1
  
 | 
4
 | 
     my ( $self, $r, $c, $param ) = @_;  | 
| 
212
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4
 | 
     my $dimap = $self->dimap;  | 
| 
213
 | 
1
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
5
 | 
     croak "cannot pathfind on unset map" if !defined $dimap;  | 
| 
214
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
215
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3
 | 
     my $badcost = $self->bad_cost;  | 
| 
216
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
217
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3
 | 
     my $curcost = $dimap->[$r][$c];  | 
| 
218
 | 
1
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
5
 | 
     return undef if $curcost <= $self->min_cost;  | 
| 
219
 | 
1
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
4
 | 
     $curcost *= $param->{my_weight} // 1;  | 
| 
220
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
7
 | 
     my @here = map $_->values( [ $r, $c ] )->[0], $param->{objs}->@*;  | 
| 
221
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
5
 | 
     for my $h ( 0 .. $#here ) {  | 
| 
222
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # this may cause problems if something is standing on a cell  | 
| 
223
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # they can no longer move into but where it is still legal for  | 
| 
224
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # them to leave that cell  | 
| 
225
 | 
2
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
6
 | 
         return undef if $here[$h] == $badcost;  | 
| 
226
 | 
2
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
6
 | 
         $curcost += $here[$h] * ( $param->{weights}->[$h] // 0 );  | 
| 
227
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
228
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
229
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
14
 | 
     my $method = $self->next_m;  | 
| 
230
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
7
 | 
     my $coords = $self->$method( $r, $c, $self->max_cost );  | 
| 
231
 | 
1
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
4
 | 
     return undef unless $coords->@*;  | 
| 
232
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
8
 | 
     my @costs = map $_->values( map $_->[0], $coords->@* ), $param->{objs}->@*;  | 
| 
233
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2
 | 
     my @ret;  | 
| 
234
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4
 | 
   COORD: for my $p ( 0 .. $coords->$#* ) {  | 
| 
235
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
7
 | 
         my @weights;  | 
| 
236
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
7
 | 
         for my $k ( 0 .. $#costs ) {  | 
| 
237
 | 
5
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
13
 | 
             next COORD if $costs[$k][$p] == $badcost;  | 
| 
238
 | 
4
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
12
 | 
             push @weights, $costs[$k][$p] * ( $param->{weights}->[$k] // 0 );  | 
| 
239
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
240
 | 
2
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
11
 | 
         my $newcost = sum0 $coords->[$p][1] * ( $param->{my_weight} // 1 ), @weights;  | 
| 
241
 | 
2
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
8
 | 
         push @ret, [ $coords->[$p][0], $newcost ] if $newcost < $curcost;  | 
| 
242
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
243
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
244
 | 
1
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
4
 | 
     return undef unless @ret;  | 
| 
245
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
6
 | 
     @ret = sort { $a->[1] <=> $b->[1] } shuffle @ret;  | 
| 
 
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
246
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
7
 | 
     return $ret[0]->[0];  | 
| 
247
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
248
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
249
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # 4-way "square" normalization as seen in the Brogue article (was called  | 
| 
250
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # normalize_costs and used to be a method). one could possibly also  | 
| 
251
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # normalize only in the diagonal directions...  | 
| 
252
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub norm_4way {  | 
| 
253
 | 
7
 | 
 
 | 
 
 | 
  
7
  
 | 
  
1
  
 | 
17
 | 
     my ( $dimap, $mincost, $maxcost, $avfn ) = @_;  | 
| 
254
 | 
7
 | 
 
 | 
  
100
  
 | 
 
 | 
 
 | 
36
 | 
     $avfn //= \&adjacent_values_sq;  | 
| 
255
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
13
 | 
     my $iters  = 0;  | 
| 
256
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
13
 | 
     my $maxrow = $dimap->$#*;  | 
| 
257
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
13
 | 
     my $maxcol = $dimap->[0]->$#*;  | 
| 
258
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
10
 | 
     my $stable;  | 
| 
259
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
10
 | 
     while (1) {  | 
| 
260
 | 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
37
 | 
         $stable = 1;  | 
| 
261
 | 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
30
 | 
         $iters++;  | 
| 
262
 | 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
35
 | 
         for my $r ( 0 .. $maxrow ) {  | 
| 
263
 | 
77
 | 
 
 | 
 
 | 
 
 | 
 
 | 
115
 | 
             for my $c ( 0 .. $maxcol ) {  | 
| 
264
 | 
403
 | 
 
 | 
 
 | 
 
 | 
 
 | 
516
 | 
                 my $value = $dimap->[$r][$c];  | 
| 
265
 | 
403
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
673
 | 
                 next if $value <= $mincost;  | 
| 
266
 | 
182
 | 
 
 | 
 
 | 
 
 | 
 
 | 
214
 | 
                 my $best = $maxcost;  | 
| 
267
 | 
182
 | 
 
 | 
 
 | 
 
 | 
 
 | 
284
 | 
                 for my $nv ( $avfn->( $dimap, $r, $c, $maxrow, $maxcol ) ) {  | 
| 
268
 | 
532
 | 
  
100
  
 | 
  
100
  
 | 
 
 | 
 
 | 
1255
 | 
                     $best = $nv if $nv < $best and $nv >= $mincost;  | 
| 
269
 | 
532
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
927
 | 
                     last if $best == $mincost;  | 
| 
270
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 }  | 
| 
271
 | 
182
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
350
 | 
                 if ( $value >= $best + 2 ) {  | 
| 
272
 | 
34
 | 
 
 | 
 
 | 
 
 | 
 
 | 
50
 | 
                     $dimap->[$r][$c] = $best + 1;  | 
| 
273
 | 
34
 | 
 
 | 
 
 | 
 
 | 
 
 | 
49
 | 
                     $stable = 0;  | 
| 
274
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 }  | 
| 
275
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             }  | 
| 
276
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
277
 | 
21
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
40
 | 
         last if $stable;  | 
| 
278
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
279
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
26
 | 
     return $iters;  | 
| 
280
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
281
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
282
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # 8-way normalization could either be done with small integers where  | 
| 
283
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # diagonals cost the same as square motion (this is non-Euclidean though  | 
| 
284
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # traditional in roguelikes) ...  | 
| 
285
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub norm_8way {  | 
| 
286
 | 
1
 | 
 
 | 
 
 | 
  
1
  
 | 
  
1
  
 | 
5
 | 
     push @_, \&adjacent_values;  | 
| 
287
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
11
 | 
     &norm_4way;    # perldoc perlsub explains this calling form  | 
| 
288
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
289
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
290
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # ... or one could instead use floating point values to better  | 
| 
291
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # approximate diagonals costing sqrt(2) but this is more complicated,  | 
| 
292
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # which is perhaps why many roguelikes use 4-way or non-Euclidean 8-way  | 
| 
293
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub norm_8way_euclid {  | 
| 
294
 | 
2
 | 
 
 | 
 
 | 
  
2
  
 | 
  
1
  
 | 
4
 | 
     my ( $dimap, $mincost, $maxcost ) = @_;  | 
| 
295
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
5
 | 
     my $iters  = 0;  | 
| 
296
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4
 | 
     my $maxrow = $dimap->$#*;  | 
| 
297
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4
 | 
     my $maxcol = $dimap->[0]->$#*;  | 
| 
298
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4
 | 
     my $stable;  | 
| 
299
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4
 | 
     while (1) {  | 
| 
300
 | 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
6
 | 
         $stable = 1;  | 
| 
301
 | 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
6
 | 
         $iters++;  | 
| 
302
 | 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
10
 | 
         for my $r ( 0 .. $maxrow ) {  | 
| 
303
 | 
16
 | 
 
 | 
 
 | 
 
 | 
 
 | 
25
 | 
             for my $c ( 0 .. $maxcol ) {  | 
| 
304
 | 
56
 | 
 
 | 
 
 | 
 
 | 
 
 | 
80
 | 
                 my $value = $dimap->[$r][$c];  | 
| 
305
 | 
56
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
95
 | 
                 next if $value <= $mincost;  | 
| 
306
 | 
47
 | 
 
 | 
 
 | 
 
 | 
 
 | 
73
 | 
                 my $best = [ $maxcost, 0 ];  | 
| 
307
 | 
47
 | 
 
 | 
 
 | 
 
 | 
 
 | 
80
 | 
                 for my $nr (  | 
| 
308
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     map( [ $_, 1 ], adjacent_values_sq( $dimap, $r, $c, $maxrow, $maxcol ) ),  | 
| 
309
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     map( [ $_, SQRT2 ], adjacent_values_diag( $dimap, $r, $c, $maxrow, $maxcol ) )  | 
| 
310
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 ) {  | 
| 
311
 | 
186
 | 
  
100
  
 | 
  
100
  
 | 
 
 | 
 
 | 
516
 | 
                     $best = $nr if $nr->[0] < $best->[0] and $nr->[0] >= $mincost;  | 
| 
312
 | 
186
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
319
 | 
                     last if $best->[0] == $mincost;  | 
| 
313
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 }  | 
| 
314
 | 
47
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
137
 | 
                 if ( $value > $best->[0] + SQRT2 ) {  | 
| 
315
 | 
17
 | 
 
 | 
 
 | 
 
 | 
 
 | 
31
 | 
                     $dimap->[$r][$c] = $best->[0] + $best->[1];  | 
| 
316
 | 
17
 | 
 
 | 
 
 | 
 
 | 
 
 | 
29
 | 
                     $stable = 0;  | 
| 
317
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 }  | 
| 
318
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             }  | 
| 
319
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
320
 | 
5
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
13
 | 
         last if $stable;  | 
| 
321
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
322
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
8
 | 
     return $iters;  | 
| 
323
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
324
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
325
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub path_best {  | 
| 
326
 | 
3
 | 
 
 | 
 
 | 
  
3
  
 | 
  
1
  
 | 
659
 | 
     my ( $self, $r, $c, $method ) = @_;  | 
| 
327
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
6
 | 
     my @path;  | 
| 
328
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
10
 | 
     while ( my $next = $self->next_best( $r, $c, $method ) ) {  | 
| 
329
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
11
 | 
         push @path, $next;  | 
| 
330
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
18
 | 
         ( $r, $c ) = @$next;  | 
| 
331
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
332
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
14
 | 
     return \@path;  | 
| 
333
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
334
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
335
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub recalc {  | 
| 
336
 | 
3
 | 
 
 | 
 
 | 
  
3
  
 | 
  
1
  
 | 
2531
 | 
     my ($self) = @_;  | 
| 
337
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
10
 | 
     my $dimap = $self->dimap;  | 
| 
338
 | 
3
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
19
 | 
     croak "cannot recalc unset map" if !defined $dimap;  | 
| 
339
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
7
 | 
     my $maxcost = $self->max_cost;  | 
| 
340
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
5
 | 
     my $mincost = $self->min_cost;  | 
| 
341
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4
 | 
     my $maxcol  = $dimap->[0]->$#*;  | 
| 
342
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
7
 | 
     for my $r ( 0 .. $dimap->$#* ) {  | 
| 
343
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
14
 | 
         for my $c ( 0 .. $maxcol ) {  | 
| 
344
 | 
39
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
68
 | 
             $dimap->[$r][$c] = $maxcost if $dimap->[$r][$c] > $mincost;  | 
| 
345
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
346
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
347
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
10
 | 
     $self->_set_iters( $self->normfn->( $dimap, $mincost, $maxcost ) );  | 
| 
348
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
6
 | 
     $self->dimap($dimap);  | 
| 
349
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
7
 | 
     return $self;  | 
| 
350
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
351
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
352
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub str2map {  | 
| 
353
 | 
6
 | 
 
 | 
 
 | 
  
6
  
 | 
  
1
  
 | 
1148
 | 
     my ( $self_or_class, $str, $lf ) = @_;  | 
| 
354
 | 
6
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
16
 | 
     croak "no string given" if !defined $str;  | 
| 
355
 | 
6
 | 
 
 | 
  
 33
  
 | 
 
 | 
 
 | 
35
 | 
     $lf //= $/;  | 
| 
356
 | 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
9
 | 
     my @map;  | 
| 
357
 | 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
94
 | 
     for my $line ( split $lf, $str ) {  | 
| 
358
 | 
18
 | 
 
 | 
 
 | 
 
 | 
 
 | 
79
 | 
         push @map, [ split //, $line ];  | 
| 
359
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
360
 | 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
39
 | 
     return \@map;  | 
| 
361
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
362
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
363
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub to_tsv {  | 
| 
364
 | 
3
 | 
 
 | 
 
 | 
  
3
  
 | 
  
1
  
 | 
1512
 | 
     my ( $self, $ref ) = @_;  | 
| 
365
 | 
3
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
12
 | 
     if ( !defined $ref ) {  | 
| 
366
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
6
 | 
         $ref = $self->dimap;  | 
| 
367
 | 
2
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
15
 | 
         croak "cannot use an unset map" if !defined $ref;  | 
| 
368
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
369
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
5
 | 
     my $s    = '';  | 
| 
370
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4
 | 
     my $cols = $ref->[0]->$#*;  | 
| 
371
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
7
 | 
     for my $r ( 0 .. $ref->$#* ) {  | 
| 
372
 | 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
10
 | 
         my $d = "\t";  | 
| 
373
 | 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
7
 | 
         for my $c ( 0 .. $cols ) {  | 
| 
374
 | 
13
 | 
 
 | 
 
 | 
 
 | 
 
 | 
31
 | 
             $s .= $ref->[$r][$c] . $d;  | 
| 
375
 | 
13
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
31
 | 
             $d = '' if $c == $cols - 1;  | 
| 
376
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
377
 | 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
11
 | 
         $s .= $/;  | 
| 
378
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
379
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
46
 | 
     return $s;  | 
| 
380
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
381
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
382
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub unconnected {  | 
| 
383
 | 
3
 | 
 
 | 
 
 | 
  
3
  
 | 
  
1
  
 | 
974
 | 
     my ($self) = @_;  | 
| 
384
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
11
 | 
     my $dimap = $self->dimap;  | 
| 
385
 | 
3
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
19
 | 
     croak "nothing unconnected on unset map" if !defined $dimap;  | 
| 
386
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
5
 | 
     my @points;  | 
| 
387
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
7
 | 
     my $maxcost = $self->max_cost;  | 
| 
388
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
6
 | 
     my $maxcol  = $dimap->[0]->$#*;  | 
| 
389
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
8
 | 
     for my $r ( 0 .. $dimap->$#* ) {  | 
| 
390
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
14
 | 
         for my $c ( 0 .. $maxcol ) {  | 
| 
391
 | 
39
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
102
 | 
             push @points, [ $r, $c ] if $dimap->[$r][$c] == $maxcost;  | 
| 
392
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
393
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
394
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
16
 | 
     return \@points;  | 
| 
395
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
396
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
397
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub update {  | 
| 
398
 | 
2
 | 
 
 | 
 
 | 
  
2
  
 | 
  
1
  
 | 
687
 | 
     my $self  = shift;  | 
| 
399
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
8
 | 
     my $dimap = $self->dimap;  | 
| 
400
 | 
2
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
16
 | 
     croak "cannot update unset map" if !defined $dimap;  | 
| 
401
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2
 | 
     my $maxrow = $dimap->$#*;  | 
| 
402
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4
 | 
     my $maxcol = $dimap->[0]->$#*;  | 
| 
403
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4
 | 
     for my $ref (@_) {  | 
| 
404
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3
 | 
         my ( $r, $c ) = ( $ref->[0], $ref->[1] );  | 
| 
405
 | 
1
 | 
  
 50
  
 | 
  
 33
  
 | 
 
 | 
 
 | 
8
 | 
         croak "row $r out of bounds" if $r > $maxrow or $r < 0;  | 
| 
406
 | 
1
 | 
  
 50
  
 | 
  
 33
  
 | 
 
 | 
 
 | 
8
 | 
         croak "col $c out of bounds" if $c > $maxcol or $c < 0;  | 
| 
407
 | 
1
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
23
 | 
         croak "value must be a number" unless looks_like_number $ref->[2];  | 
| 
408
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
6
 | 
         $dimap->[$r][$c] = int $ref->[2];  | 
| 
409
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
410
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
6
 | 
     $self->dimap($dimap);  | 
| 
411
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3
 | 
     return $self;  | 
| 
412
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
413
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
414
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub values {  | 
| 
415
 | 
24
 | 
 
 | 
 
 | 
  
24
  
 | 
  
1
  
 | 
688
 | 
     my $self  = shift;  | 
| 
416
 | 
24
 | 
 
 | 
 
 | 
 
 | 
 
 | 
40
 | 
     my $dimap = $self->dimap;  | 
| 
417
 | 
24
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
56
 | 
     croak "cannot get values from unset map" if !defined $dimap;  | 
| 
418
 | 
23
 | 
 
 | 
 
 | 
 
 | 
 
 | 
31
 | 
     my @values;  | 
| 
419
 | 
23
 | 
 
 | 
 
 | 
 
 | 
 
 | 
30
 | 
     my $maxrow = $dimap->$#*;  | 
| 
420
 | 
23
 | 
 
 | 
 
 | 
 
 | 
 
 | 
39
 | 
     my $maxcol = $dimap->[0]->$#*;  | 
| 
421
 | 
23
 | 
 
 | 
 
 | 
 
 | 
 
 | 
39
 | 
     for my $point (@_) {  | 
| 
422
 | 
29
 | 
 
 | 
 
 | 
 
 | 
 
 | 
50
 | 
         my ( $r, $c ) = ( $point->[0], $point->[1] );  | 
| 
423
 | 
29
 | 
  
 50
  
 | 
  
 33
  
 | 
 
 | 
 
 | 
85
 | 
         croak "row $r out of bounds" if $r > $maxrow or $r < 0;  | 
| 
424
 | 
29
 | 
  
 50
  
 | 
  
 33
  
 | 
 
 | 
 
 | 
107
 | 
         croak "col $c out of bounds" if $c > $maxcol or $c < 0;  | 
| 
425
 | 
29
 | 
 
 | 
 
 | 
 
 | 
 
 | 
77
 | 
         push @values, $dimap->[$r][$c];  | 
| 
426
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
427
 | 
23
 | 
 
 | 
 
 | 
 
 | 
 
 | 
104
 | 
     return \@values;  | 
| 
428
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
429
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
430
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 1;  | 
| 
431
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 __END__  |