| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
# Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 Kevin Ryde |
|
2
|
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
# This file is part of Math-PlanePath. |
|
4
|
|
|
|
|
|
|
# |
|
5
|
|
|
|
|
|
|
# Math-PlanePath is free software; you can redistribute it and/or modify it |
|
6
|
|
|
|
|
|
|
# under the terms of the GNU General Public License as published by the Free |
|
7
|
|
|
|
|
|
|
# Software Foundation; either version 3, or (at your option) any later |
|
8
|
|
|
|
|
|
|
# version. |
|
9
|
|
|
|
|
|
|
# |
|
10
|
|
|
|
|
|
|
# Math-PlanePath is distributed in the hope that it will be useful, but |
|
11
|
|
|
|
|
|
|
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
|
12
|
|
|
|
|
|
|
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
13
|
|
|
|
|
|
|
# for more details. |
|
14
|
|
|
|
|
|
|
# |
|
15
|
|
|
|
|
|
|
# You should have received a copy of the GNU General Public License along |
|
16
|
|
|
|
|
|
|
# with Math-PlanePath. If not, see . |
|
17
|
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
# math-image --path=FlowsnakeCentres --lines --scale=10 |
|
20
|
|
|
|
|
|
|
# |
|
21
|
|
|
|
|
|
|
# http://80386.nl/projects/flowsnake/ |
|
22
|
|
|
|
|
|
|
# |
|
23
|
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
package Math::PlanePath::FlowsnakeCentres; |
|
26
|
2
|
|
|
2
|
|
1404
|
use 5.004; |
|
|
2
|
|
|
|
|
7
|
|
|
27
|
2
|
|
|
2
|
|
12
|
use strict; |
|
|
2
|
|
|
|
|
4
|
|
|
|
2
|
|
|
|
|
43
|
|
|
28
|
2
|
|
|
2
|
|
949
|
use POSIX 'ceil'; |
|
|
2
|
|
|
|
|
14385
|
|
|
|
2
|
|
|
|
|
11
|
|
|
29
|
2
|
|
|
2
|
|
2909
|
use List::Util 'min'; # 'max' |
|
|
2
|
|
|
|
|
5
|
|
|
|
2
|
|
|
|
|
240
|
|
|
30
|
|
|
|
|
|
|
*max = \&Math::PlanePath::_max; |
|
31
|
|
|
|
|
|
|
|
|
32
|
2
|
|
|
2
|
|
15
|
use vars '$VERSION', '@ISA'; |
|
|
2
|
|
|
|
|
5
|
|
|
|
2
|
|
|
|
|
145
|
|
|
33
|
|
|
|
|
|
|
$VERSION = 127; |
|
34
|
2
|
|
|
2
|
|
1524
|
use Math::PlanePath; |
|
|
2
|
|
|
|
|
6
|
|
|
|
2
|
|
|
|
|
103
|
|
|
35
|
|
|
|
|
|
|
@ISA = ('Math::PlanePath'); |
|
36
|
|
|
|
|
|
|
*_divrem_mutate = \&Math::PlanePath::_divrem_mutate; |
|
37
|
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
use Math::PlanePath::Base::Generic |
|
39
|
2
|
|
|
|
|
100
|
'is_infinite', |
|
40
|
|
|
|
|
|
|
'round_nearest', |
|
41
|
2
|
|
|
2
|
|
13
|
'xy_is_even'; |
|
|
2
|
|
|
|
|
3
|
|
|
42
|
|
|
|
|
|
|
use Math::PlanePath::Base::Digits |
|
43
|
2
|
|
|
|
|
118
|
'digit_split_lowtohigh', |
|
44
|
2
|
|
|
2
|
|
1020
|
'round_up_pow'; |
|
|
2
|
|
|
|
|
6
|
|
|
45
|
|
|
|
|
|
|
|
|
46
|
2
|
|
|
2
|
|
1010
|
use Math::PlanePath::SacksSpiral; |
|
|
2
|
|
|
|
|
7
|
|
|
|
2
|
|
|
|
|
107
|
|
|
47
|
|
|
|
|
|
|
*_rect_to_radius_range = \&Math::PlanePath::SacksSpiral::_rect_to_radius_range; |
|
48
|
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
# uncomment this to run the ### lines |
|
50
|
|
|
|
|
|
|
#use Devel::Comments; |
|
51
|
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
|
|
53
|
2
|
|
|
2
|
|
14
|
use constant n_start => 0; |
|
|
2
|
|
|
|
|
5
|
|
|
|
2
|
|
|
|
|
150
|
|
|
54
|
|
|
|
|
|
|
|
|
55
|
2
|
|
|
|
|
327
|
use constant parameter_info_array => [ { name => 'arms', |
|
56
|
|
|
|
|
|
|
share_key => 'arms_3', |
|
57
|
|
|
|
|
|
|
display => 'Arms', |
|
58
|
|
|
|
|
|
|
type => 'integer', |
|
59
|
|
|
|
|
|
|
minimum => 1, |
|
60
|
|
|
|
|
|
|
maximum => 3, |
|
61
|
|
|
|
|
|
|
default => 1, |
|
62
|
|
|
|
|
|
|
width => 1, |
|
63
|
|
|
|
|
|
|
description => 'Arms', |
|
64
|
2
|
|
|
2
|
|
13
|
} ]; |
|
|
2
|
|
|
|
|
4
|
|
|
65
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
{ |
|
67
|
|
|
|
|
|
|
my @x_negative_at_n = (undef, 3, 1, 1); |
|
68
|
|
|
|
|
|
|
sub x_negative_at_n { |
|
69
|
0
|
|
|
0
|
1
|
0
|
my ($self) = @_; |
|
70
|
0
|
|
|
|
|
0
|
return $x_negative_at_n[$self->{'arms'}]; |
|
71
|
|
|
|
|
|
|
} |
|
72
|
|
|
|
|
|
|
} |
|
73
|
|
|
|
|
|
|
{ |
|
74
|
|
|
|
|
|
|
my @y_negative_at_n = (undef, 8597, 7, 2); |
|
75
|
|
|
|
|
|
|
sub y_negative_at_n { |
|
76
|
0
|
|
|
0
|
1
|
0
|
my ($self) = @_; |
|
77
|
0
|
|
|
|
|
0
|
return $y_negative_at_n[$self->{'arms'}]; |
|
78
|
|
|
|
|
|
|
} |
|
79
|
|
|
|
|
|
|
} |
|
80
|
|
|
|
|
|
|
|
|
81
|
2
|
|
|
2
|
|
15
|
use constant dx_minimum => -2; |
|
|
2
|
|
|
|
|
5
|
|
|
|
2
|
|
|
|
|
107
|
|
|
82
|
2
|
|
|
2
|
|
12
|
use constant dx_maximum => 2; |
|
|
2
|
|
|
|
|
4
|
|
|
|
2
|
|
|
|
|
105
|
|
|
83
|
2
|
|
|
2
|
|
13
|
use constant dy_minimum => -1; |
|
|
2
|
|
|
|
|
12
|
|
|
|
2
|
|
|
|
|
115
|
|
|
84
|
2
|
|
|
2
|
|
14
|
use constant dy_maximum => 1; |
|
|
2
|
|
|
|
|
5
|
|
|
|
2
|
|
|
|
|
261
|
|
|
85
|
|
|
|
|
|
|
*_UNDOCUMENTED__dxdy_list = \&Math::PlanePath::_UNDOCUMENTED__dxdy_list_six; |
|
86
|
|
|
|
|
|
|
{ |
|
87
|
|
|
|
|
|
|
my @_UNDOCUMENTED__dxdy_list_at_n = (undef, 10, 6, 8); |
|
88
|
|
|
|
|
|
|
sub _UNDOCUMENTED__dxdy_list_at_n { |
|
89
|
0
|
|
|
0
|
|
0
|
my ($self) = @_; |
|
90
|
0
|
|
|
|
|
0
|
return $_UNDOCUMENTED__dxdy_list_at_n[$self->{'arms'}]; |
|
91
|
|
|
|
|
|
|
} |
|
92
|
|
|
|
|
|
|
} |
|
93
|
2
|
|
|
2
|
|
13
|
use constant absdx_minimum => 1; |
|
|
2
|
|
|
|
|
5
|
|
|
|
2
|
|
|
|
|
110
|
|
|
94
|
2
|
|
|
2
|
|
12
|
use constant dsumxy_minimum => -2; # diagonals |
|
|
2
|
|
|
|
|
4
|
|
|
|
2
|
|
|
|
|
119
|
|
|
95
|
2
|
|
|
2
|
|
13
|
use constant dsumxy_maximum => 2; |
|
|
2
|
|
|
|
|
5
|
|
|
|
2
|
|
|
|
|
116
|
|
|
96
|
2
|
|
|
2
|
|
13
|
use constant ddiffxy_minimum => -2; |
|
|
2
|
|
|
|
|
4
|
|
|
|
2
|
|
|
|
|
121
|
|
|
97
|
2
|
|
|
2
|
|
13
|
use constant ddiffxy_maximum => 2; |
|
|
2
|
|
|
|
|
3
|
|
|
|
2
|
|
|
|
|
119
|
|
|
98
|
2
|
|
|
2
|
|
13
|
use constant dir_maximum_dxdy => (1,-1); # South-East |
|
|
2
|
|
|
|
|
4
|
|
|
|
2
|
|
|
|
|
3964
|
|
|
99
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
#------------------------------------------------------------------------------ |
|
103
|
|
|
|
|
|
|
# * |
|
104
|
|
|
|
|
|
|
# / \ |
|
105
|
|
|
|
|
|
|
# / \ |
|
106
|
|
|
|
|
|
|
# *-----* |
|
107
|
|
|
|
|
|
|
# |
|
108
|
|
|
|
|
|
|
# (b/2)^2 + h^2 = s |
|
109
|
|
|
|
|
|
|
# (1/2)^2 + h^2 = 1 |
|
110
|
|
|
|
|
|
|
# h^2 = 1 - 1/4 |
|
111
|
|
|
|
|
|
|
# h = sqrt(3)/2 = 0.866 |
|
112
|
|
|
|
|
|
|
# |
|
113
|
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
sub new { |
|
115
|
31
|
|
|
31
|
1
|
9736
|
my $self = shift->SUPER::new(@_); |
|
116
|
31
|
|
100
|
|
|
234
|
$self->{'arms'} = max(1, min(3, $self->{'arms'} || 1)); |
|
117
|
31
|
|
|
|
|
76
|
return $self; |
|
118
|
|
|
|
|
|
|
} |
|
119
|
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
# # next_state length 84 |
|
122
|
|
|
|
|
|
|
# my @next_state = (0, 35,49,14, 0,70, 7, 0,21, 7,21,42,28, 7, # 0,7 |
|
123
|
|
|
|
|
|
|
# 14,49,63,28,14, 0,21, 14,35,21,35,56,42,21, # 14,21 |
|
124
|
|
|
|
|
|
|
# 28,63,77,42,28,14,35, 28,49,35,49,70,56,35, # 28,35 |
|
125
|
|
|
|
|
|
|
# 42,77, 7,56,42,28,49, 42,63,49,63, 0,70,49, # 42,49 |
|
126
|
|
|
|
|
|
|
# 56, 7,21,70,56,42,63, 56,77,63,77,14, 0,63, # 56,63 |
|
127
|
|
|
|
|
|
|
# 70,21,35, 0,70,56,77, 70, 7,77, 7,28,14,77); # 70,77 |
|
128
|
|
|
|
|
|
|
# my @digit_to_i = (0, 1, 0,-1,-1, 0, 1, 0, 1, 2, 3, 3, 2, 1, # 0,7 |
|
129
|
|
|
|
|
|
|
# 0, 0,-1,-1,-2,-2,-1, 0, 0, 1, 1, 0, 0,-1, # 14,21 |
|
130
|
|
|
|
|
|
|
# 0, -1,-1, 0,-1,-2,-2, 0,-1,-1,-2,-3,-2,-2, # 28,35 |
|
131
|
|
|
|
|
|
|
# 0, -1, 0, 1, 1, 0,-1, 0,-1,-2,-3,-3,-2,-1, # 42,49 |
|
132
|
|
|
|
|
|
|
# 0, 0, 1, 1, 2, 2, 1, 0, 0,-1,-1, 0, 0, 1, # 56,63 |
|
133
|
|
|
|
|
|
|
# 0, 1, 1, 0, 1, 2, 2, 0, 1, 1, 2, 3, 2,2); # 70,77 |
|
134
|
|
|
|
|
|
|
# my @digit_to_j = (0, 0, 1, 1, 2, 2, 1, 0, 0,-1,-1, 0, 0, 1, # 0,7 |
|
135
|
|
|
|
|
|
|
# 0, 1, 1, 0, 1, 2, 2, 0, 1, 1, 2, 3, 2, 2, # 14,21 |
|
136
|
|
|
|
|
|
|
# 0, 1, 0,-1,-1, 0, 1, 0, 1, 2, 3, 3, 2, 1, # 28,35 |
|
137
|
|
|
|
|
|
|
# 0, 0,-1,-1,-2,-2,-1, 0, 0, 1, 1, 0, 0,-1, # 42,49 |
|
138
|
|
|
|
|
|
|
# 0, -1,-1, 0,-1,-2,-2, 0,-1,-1,-2,-3,-2,-2, # 56,63 |
|
139
|
|
|
|
|
|
|
# 0, -1, 0, 1, 1, 0,-1, 0,-1,-2,-3,-3,-2,-1); # 70,77 |
|
140
|
|
|
|
|
|
|
# my @state_to_di = ( 1, 1, 0, 0,-1,-1, -1,-1, 0, 0, 1,1); |
|
141
|
|
|
|
|
|
|
# my @state_to_dj = ( 0, 0, 1, 1, 1, 1, 0, 0,-1,-1,-1,-1); |
|
142
|
|
|
|
|
|
|
# |
|
143
|
|
|
|
|
|
|
# |
|
144
|
|
|
|
|
|
|
# sub n_to_xy { |
|
145
|
|
|
|
|
|
|
# my ($self, $n) = @_; |
|
146
|
|
|
|
|
|
|
# ### Flowsnake n_to_xy(): $n |
|
147
|
|
|
|
|
|
|
# |
|
148
|
|
|
|
|
|
|
# if ($n < 0) { return; } |
|
149
|
|
|
|
|
|
|
# if (is_infinite($n)) { return ($n,$n); } |
|
150
|
|
|
|
|
|
|
# |
|
151
|
|
|
|
|
|
|
# my $int = int($n); |
|
152
|
|
|
|
|
|
|
# $n -= $int; # fraction part |
|
153
|
|
|
|
|
|
|
# ### $int |
|
154
|
|
|
|
|
|
|
# ### frac: $n |
|
155
|
|
|
|
|
|
|
# |
|
156
|
|
|
|
|
|
|
# my $state; |
|
157
|
|
|
|
|
|
|
# { |
|
158
|
|
|
|
|
|
|
# my $arm = _divrem_mutate ($int, $self->{'arms'}); |
|
159
|
|
|
|
|
|
|
# $state = 28 * $arm; # initial rotation |
|
160
|
|
|
|
|
|
|
# |
|
161
|
|
|
|
|
|
|
# # adjust so that for arms=2 point N=1 has $int==1 |
|
162
|
|
|
|
|
|
|
# # or for arms=3 then points N=1 and N=2 have $int==1 |
|
163
|
|
|
|
|
|
|
# if ($arm) { $int += 1; } |
|
164
|
|
|
|
|
|
|
# } |
|
165
|
|
|
|
|
|
|
# ### initial state: $state |
|
166
|
|
|
|
|
|
|
# |
|
167
|
|
|
|
|
|
|
# my $i = my $j = $int*0; # bignum zero |
|
168
|
|
|
|
|
|
|
# |
|
169
|
|
|
|
|
|
|
# foreach my $digit (reverse digit_split_lowtohigh($int,7)) { # high to low |
|
170
|
|
|
|
|
|
|
# ### at: "state=$state digit=$digit i=$i,j=$j di=".$digit_to_i[$state+$digit]." dj=".$digit_to_j[$state+$digit] |
|
171
|
|
|
|
|
|
|
# |
|
172
|
|
|
|
|
|
|
# # i,j * (2+w), being 2*(i,j)+rot60(i,j) |
|
173
|
|
|
|
|
|
|
# # then add low digit position |
|
174
|
|
|
|
|
|
|
# # |
|
175
|
|
|
|
|
|
|
# $state += $digit; |
|
176
|
|
|
|
|
|
|
# ($i, $j) = (2*$i - $j + $digit_to_i[$state], |
|
177
|
|
|
|
|
|
|
# 3*$j + $i + $digit_to_j[$state]); |
|
178
|
|
|
|
|
|
|
# $state = $next_state[$state]; |
|
179
|
|
|
|
|
|
|
# } |
|
180
|
|
|
|
|
|
|
# ### integer: "i=$i, j=$j" |
|
181
|
|
|
|
|
|
|
# |
|
182
|
|
|
|
|
|
|
# # fraction in final $state direction |
|
183
|
|
|
|
|
|
|
# if ($n) { |
|
184
|
|
|
|
|
|
|
# ### apply: "frac=$n state=$state" |
|
185
|
|
|
|
|
|
|
# $state /= 7; |
|
186
|
|
|
|
|
|
|
# $i = $n * $state_to_di[$state] + $i; |
|
187
|
|
|
|
|
|
|
# $j = $n * $state_to_dj[$state] + $j; |
|
188
|
|
|
|
|
|
|
# } |
|
189
|
|
|
|
|
|
|
# |
|
190
|
|
|
|
|
|
|
# ### ret: "$i, $j x=".(2*$i+$j)." y=$j" |
|
191
|
|
|
|
|
|
|
# return (2*$i+$j, |
|
192
|
|
|
|
|
|
|
# $j); |
|
193
|
|
|
|
|
|
|
# |
|
194
|
|
|
|
|
|
|
# } |
|
195
|
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
# 4-->5 |
|
197
|
|
|
|
|
|
|
# ^ ^ |
|
198
|
|
|
|
|
|
|
# / \ |
|
199
|
|
|
|
|
|
|
# 3--- 2 6-- |
|
200
|
|
|
|
|
|
|
# \ |
|
201
|
|
|
|
|
|
|
# v |
|
202
|
|
|
|
|
|
|
# 0-->1 |
|
203
|
|
|
|
|
|
|
# |
|
204
|
|
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
my @digit_reverse = (0,1,1,0,0,0,1); # 1,2,6 |
|
206
|
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
sub n_to_xy { |
|
208
|
9488
|
|
|
9488
|
1
|
34641
|
my ($self, $n) = @_; |
|
209
|
|
|
|
|
|
|
### FlowsnakeCentres n_to_xy(): $n |
|
210
|
|
|
|
|
|
|
|
|
211
|
9488
|
50
|
|
|
|
16834
|
if ($n < 0) { return; } |
|
|
0
|
|
|
|
|
0
|
|
|
212
|
9488
|
50
|
|
|
|
18579
|
if (is_infinite($n)) { return ($n,$n); } |
|
|
0
|
|
|
|
|
0
|
|
|
213
|
|
|
|
|
|
|
|
|
214
|
|
|
|
|
|
|
# ENHANCE-ME: work $frac into initial $x,$y somehow |
|
215
|
|
|
|
|
|
|
# my $frac; |
|
216
|
|
|
|
|
|
|
# { |
|
217
|
|
|
|
|
|
|
# my $int = int($n); |
|
218
|
|
|
|
|
|
|
# $frac = $n - $int; # inherit possible BigFloat/BigRat |
|
219
|
|
|
|
|
|
|
# $n = $int; # BigInt instead of BigFloat |
|
220
|
|
|
|
|
|
|
# } |
|
221
|
|
|
|
|
|
|
{ |
|
222
|
9488
|
|
|
|
|
15974
|
my $int = int($n); |
|
|
9488
|
|
|
|
|
13323
|
|
|
223
|
|
|
|
|
|
|
### $int |
|
224
|
|
|
|
|
|
|
### $n |
|
225
|
9488
|
100
|
|
|
|
16904
|
if ($n != $int) { |
|
226
|
63
|
|
|
|
|
129
|
my ($x1,$y1) = $self->n_to_xy($int); |
|
227
|
63
|
|
|
|
|
167
|
my ($x2,$y2) = $self->n_to_xy($int+$self->{'arms'}); |
|
228
|
63
|
|
|
|
|
106
|
my $frac = $n - $int; # inherit possible BigFloat |
|
229
|
63
|
|
|
|
|
94
|
my $dx = $x2-$x1; |
|
230
|
63
|
|
|
|
|
89
|
my $dy = $y2-$y1; |
|
231
|
63
|
|
|
|
|
206
|
return ($frac*$dx + $x1, $frac*$dy + $y1); |
|
232
|
|
|
|
|
|
|
} |
|
233
|
9425
|
|
|
|
|
13347
|
$n = $int; # BigFloat int() gives BigInt, use that |
|
234
|
|
|
|
|
|
|
} |
|
235
|
|
|
|
|
|
|
|
|
236
|
|
|
|
|
|
|
# arm as initial rotation |
|
237
|
9425
|
|
|
|
|
19793
|
my $rot = _divrem_mutate ($n, $self->{'arms'}); |
|
238
|
|
|
|
|
|
|
|
|
239
|
9425
|
|
|
|
|
18264
|
my @digits = digit_split_lowtohigh($n,7); |
|
240
|
|
|
|
|
|
|
### @digits |
|
241
|
|
|
|
|
|
|
|
|
242
|
9425
|
|
|
|
|
13919
|
my $x = 0; |
|
243
|
9425
|
|
|
|
|
12743
|
my $y = 0; |
|
244
|
|
|
|
|
|
|
{ |
|
245
|
|
|
|
|
|
|
# if (! @n || $digits[0] == 0) { |
|
246
|
|
|
|
|
|
|
# $x = 2*$frac; |
|
247
|
|
|
|
|
|
|
# } elsif ($digits[0] == 1) { |
|
248
|
|
|
|
|
|
|
# $x = $frac; |
|
249
|
|
|
|
|
|
|
# $y = -$frac; |
|
250
|
|
|
|
|
|
|
# } elsif ($digits[0] == 2) { |
|
251
|
|
|
|
|
|
|
# $x = -2*$frac; |
|
252
|
|
|
|
|
|
|
# } elsif ($digits[0] == 3) { |
|
253
|
|
|
|
|
|
|
# $x = $frac; |
|
254
|
|
|
|
|
|
|
# $y = -$frac; |
|
255
|
|
|
|
|
|
|
# } elsif ($digits[0] == 4) { |
|
256
|
|
|
|
|
|
|
# $x = 2*$frac; |
|
257
|
|
|
|
|
|
|
# } elsif ($digits[0] == 5) { |
|
258
|
|
|
|
|
|
|
# $x = $frac; |
|
259
|
|
|
|
|
|
|
# $y = -$frac; |
|
260
|
|
|
|
|
|
|
# } elsif ($digits[0] == 6) { |
|
261
|
|
|
|
|
|
|
# $x = -$frac; |
|
262
|
|
|
|
|
|
|
# $y = -$frac; |
|
263
|
|
|
|
|
|
|
# } |
|
264
|
|
|
|
|
|
|
|
|
265
|
9425
|
|
|
|
|
12613
|
my $rev = 0; |
|
|
9425
|
|
|
|
|
12591
|
|
|
266
|
9425
|
|
|
|
|
15197
|
foreach my $digit (reverse @digits) { # high to low |
|
267
|
|
|
|
|
|
|
### $digit |
|
268
|
43149
|
100
|
|
|
|
68701
|
if ($rev) { |
|
269
|
|
|
|
|
|
|
### reverse: "$digit to ".(6 - $digit) |
|
270
|
19583
|
|
|
|
|
25283
|
$digit = 6 - $digit; # mutate the array |
|
271
|
|
|
|
|
|
|
} |
|
272
|
43149
|
|
|
|
|
62810
|
$rev ^= $digit_reverse[$digit]; |
|
273
|
|
|
|
|
|
|
### now rev: $rev |
|
274
|
|
|
|
|
|
|
} |
|
275
|
|
|
|
|
|
|
### reversed n: @n |
|
276
|
|
|
|
|
|
|
} |
|
277
|
|
|
|
|
|
|
|
|
278
|
9425
|
|
|
|
|
13936
|
my ($ox,$oy,$sx,$sy); |
|
279
|
9425
|
50
|
|
|
|
15107
|
if ($rot == 0) { |
|
|
|
0
|
|
|
|
|
|
|
280
|
9425
|
|
|
|
|
12411
|
$ox = 0; |
|
281
|
9425
|
|
|
|
|
12153
|
$oy = 0; |
|
282
|
9425
|
|
|
|
|
12124
|
$sx = 2; |
|
283
|
9425
|
|
|
|
|
12543
|
$sy = 0; |
|
284
|
|
|
|
|
|
|
} elsif ($rot == 1) { |
|
285
|
0
|
|
|
|
|
0
|
$ox = -1; # at +120 |
|
286
|
0
|
|
|
|
|
0
|
$oy = 1; |
|
287
|
0
|
|
|
|
|
0
|
$sx = -1; # rot to +120 |
|
288
|
0
|
|
|
|
|
0
|
$sy = 1; |
|
289
|
|
|
|
|
|
|
} else { |
|
290
|
0
|
|
|
|
|
0
|
$ox = -2; # at 180 |
|
291
|
0
|
|
|
|
|
0
|
$oy = 0; |
|
292
|
0
|
|
|
|
|
0
|
$sx = -1; # rot to +240 |
|
293
|
0
|
|
|
|
|
0
|
$sy = -1; |
|
294
|
|
|
|
|
|
|
} |
|
295
|
|
|
|
|
|
|
|
|
296
|
9425
|
|
|
|
|
17285
|
while (@digits) { |
|
297
|
43149
|
|
|
|
|
62632
|
my $digit = shift @digits; # low to high |
|
298
|
|
|
|
|
|
|
### digit: "$digit $x,$y side $sx,$sy origin $ox,$oy" |
|
299
|
|
|
|
|
|
|
|
|
300
|
43149
|
100
|
|
|
|
92801
|
if ($digit == 0) { |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
301
|
16984
|
|
|
|
|
28659
|
$x += (3*$sy - $sx)/2; # at -120 |
|
302
|
16984
|
|
|
|
|
25322
|
$y += ($sx + $sy)/-2; |
|
303
|
|
|
|
|
|
|
|
|
304
|
|
|
|
|
|
|
} elsif ($digit == 1) { |
|
305
|
5543
|
|
|
|
|
10134
|
($x,$y) = ((3*$y-$x)/2, # rotate -120 |
|
306
|
|
|
|
|
|
|
($x+$y)/-2); |
|
307
|
5543
|
|
|
|
|
9068
|
$x += ($sx + 3*$sy)/2; # at -60 |
|
308
|
5543
|
|
|
|
|
8097
|
$y += ($sy - $sx)/2; |
|
309
|
|
|
|
|
|
|
|
|
310
|
|
|
|
|
|
|
} elsif ($digit == 2) { |
|
311
|
|
|
|
|
|
|
# centre |
|
312
|
|
|
|
|
|
|
|
|
313
|
|
|
|
|
|
|
} elsif ($digit == 3) { |
|
314
|
2818
|
|
|
|
|
5484
|
($x,$y) = (($x+3*$y)/-2, # rotate +120 |
|
315
|
|
|
|
|
|
|
($x-$y)/2); |
|
316
|
2818
|
|
|
|
|
4006
|
$x -= $sx; # at -180 |
|
317
|
2818
|
|
|
|
|
3744
|
$y -= $sy; |
|
318
|
|
|
|
|
|
|
|
|
319
|
|
|
|
|
|
|
} elsif ($digit == 4) { |
|
320
|
3185
|
|
|
|
|
5731
|
$x += ($sx + 3*$sy)/-2; # at +120 |
|
321
|
3185
|
|
|
|
|
4903
|
$y += ($sx - $sy)/2; |
|
322
|
|
|
|
|
|
|
|
|
323
|
|
|
|
|
|
|
} elsif ($digit == 5) { |
|
324
|
2861
|
|
|
|
|
5207
|
$x += ($sx - 3*$sy)/2; # at +60 |
|
325
|
2861
|
|
|
|
|
4402
|
$y += ($sx + $sy)/2; |
|
326
|
|
|
|
|
|
|
|
|
327
|
|
|
|
|
|
|
} elsif ($digit == 6) { |
|
328
|
7773
|
|
|
|
|
14905
|
($x,$y) = (($x+3*$y)/-2, # rotate +120 |
|
329
|
|
|
|
|
|
|
($x-$y)/2); |
|
330
|
7773
|
|
|
|
|
10722
|
$x += $sx; # at X axis |
|
331
|
7773
|
|
|
|
|
10427
|
$y += $sy; |
|
332
|
|
|
|
|
|
|
} |
|
333
|
|
|
|
|
|
|
|
|
334
|
43149
|
|
|
|
|
55805
|
$ox += $sx; |
|
335
|
43149
|
|
|
|
|
55299
|
$oy += $sy; |
|
336
|
|
|
|
|
|
|
|
|
337
|
|
|
|
|
|
|
# 2*(sx,sy) + rot+60(sx,sy) |
|
338
|
43149
|
|
|
|
|
98518
|
($sx,$sy) = ((5*$sx - 3*$sy) / 2, |
|
339
|
|
|
|
|
|
|
($sx + 5*$sy) / 2); |
|
340
|
|
|
|
|
|
|
} |
|
341
|
|
|
|
|
|
|
|
|
342
|
|
|
|
|
|
|
|
|
343
|
|
|
|
|
|
|
### digits to: "$x,$y" |
|
344
|
|
|
|
|
|
|
### origin sum: "$ox,$oy" |
|
345
|
|
|
|
|
|
|
### origin rotated: (($ox-3*$oy)/2).','.(($ox+$oy)/2) |
|
346
|
9425
|
|
|
|
|
16330
|
$x += ($ox-3*$oy)/2; # rotate +60 |
|
347
|
9425
|
|
|
|
|
14892
|
$y += ($ox+$oy)/2; |
|
348
|
|
|
|
|
|
|
|
|
349
|
|
|
|
|
|
|
### final: "$x,$y" |
|
350
|
9425
|
|
|
|
|
20017
|
return ($x,$y); |
|
351
|
|
|
|
|
|
|
} |
|
352
|
|
|
|
|
|
|
|
|
353
|
|
|
|
|
|
|
# all even points when arms==3 |
|
354
|
|
|
|
|
|
|
sub xy_is_visited { |
|
355
|
0
|
|
|
0
|
1
|
0
|
my ($self, $x, $y) = @_; |
|
356
|
0
|
0
|
|
|
|
0
|
if ($self->{'arms'} == 3) { |
|
357
|
0
|
|
|
|
|
0
|
return xy_is_even($self,$x,$y); |
|
358
|
|
|
|
|
|
|
} else { |
|
359
|
0
|
|
|
|
|
0
|
return defined($self->xy_to_n($x,$y)); |
|
360
|
|
|
|
|
|
|
} |
|
361
|
|
|
|
|
|
|
} |
|
362
|
|
|
|
|
|
|
|
|
363
|
|
|
|
|
|
|
# 4-->5 |
|
364
|
|
|
|
|
|
|
# ^ ^ forw |
|
365
|
|
|
|
|
|
|
# / \ |
|
366
|
|
|
|
|
|
|
# 3--- 2 6--- |
|
367
|
|
|
|
|
|
|
# \ |
|
368
|
|
|
|
|
|
|
# v |
|
369
|
|
|
|
|
|
|
# 0-->1 |
|
370
|
|
|
|
|
|
|
# |
|
371
|
|
|
|
|
|
|
# 5 3 |
|
372
|
|
|
|
|
|
|
# \ rev |
|
373
|
|
|
|
|
|
|
# / \ / v |
|
374
|
|
|
|
|
|
|
# --6 4 2 |
|
375
|
|
|
|
|
|
|
# / |
|
376
|
|
|
|
|
|
|
# v |
|
377
|
|
|
|
|
|
|
# 0-->1 |
|
378
|
|
|
|
|
|
|
# |
|
379
|
|
|
|
|
|
|
|
|
380
|
|
|
|
|
|
|
my @modulus_to_digit |
|
381
|
|
|
|
|
|
|
= (0,3,1,2,4,6,5, 0,42,14,28, 0,56, 0, # 0 right forw 0 |
|
382
|
|
|
|
|
|
|
0,5,1,4,6,2,3, 0,42,14,70,14,14,28, # 14 +120 rev 1 |
|
383
|
|
|
|
|
|
|
6,3,5,4,2,0,1, 28,56,70, 0,28,42,28, # 28 left rev 2 |
|
384
|
|
|
|
|
|
|
4,5,3,2,6,0,1, 42,42,70,56,14,42,28, # 42 +60 forw 3 |
|
385
|
|
|
|
|
|
|
2,1,3,4,0,6,5, 56,56,14,42,70,56, 0, # 56 -60 rev 6 |
|
386
|
|
|
|
|
|
|
6,1,5,2,0,4,3, 28,56,70,14,70,70, 0, # 70 forw |
|
387
|
|
|
|
|
|
|
); |
|
388
|
|
|
|
|
|
|
sub xy_to_n { |
|
389
|
164
|
|
|
164
|
1
|
1319
|
my ($self, $x, $y) = @_; |
|
390
|
|
|
|
|
|
|
### FlowsnakeCentres xy_to_n(): "$x, $y" |
|
391
|
|
|
|
|
|
|
|
|
392
|
164
|
|
|
|
|
415
|
$x = round_nearest($x); |
|
393
|
164
|
|
|
|
|
342
|
$y = round_nearest($y); |
|
394
|
164
|
50
|
|
|
|
519
|
if (($x ^ $y) & 1) { |
|
395
|
|
|
|
|
|
|
### odd x,y ... |
|
396
|
0
|
|
|
|
|
0
|
return undef; |
|
397
|
|
|
|
|
|
|
} |
|
398
|
|
|
|
|
|
|
|
|
399
|
164
|
|
|
|
|
626
|
my $level_limit = log($x*$x + 3*$y*$y + 1) * 0.835 * 2; |
|
400
|
164
|
50
|
|
|
|
409
|
if (is_infinite($level_limit)) { return $level_limit; } |
|
|
0
|
|
|
|
|
0
|
|
|
401
|
|
|
|
|
|
|
|
|
402
|
164
|
|
|
|
|
524
|
my @digits; |
|
403
|
|
|
|
|
|
|
my $arm; |
|
404
|
164
|
|
|
|
|
0
|
my $state; |
|
405
|
164
|
|
|
|
|
248
|
for (;;) { |
|
406
|
732
|
50
|
|
|
|
1486
|
if ($level_limit-- < 0) { |
|
407
|
|
|
|
|
|
|
### oops, level limit ... |
|
408
|
0
|
|
|
|
|
0
|
return undef; |
|
409
|
|
|
|
|
|
|
} |
|
410
|
732
|
100
|
100
|
|
|
1721
|
if ($x == 0 && $y == 0) { |
|
411
|
|
|
|
|
|
|
### found first arm 0,0 ... |
|
412
|
161
|
|
|
|
|
254
|
$arm = 0; |
|
413
|
161
|
|
|
|
|
306
|
$state = 0; |
|
414
|
161
|
|
|
|
|
273
|
last; |
|
415
|
|
|
|
|
|
|
} |
|
416
|
571
|
100
|
100
|
|
|
1205
|
if ($x == -2 && $y == 0) { |
|
417
|
|
|
|
|
|
|
### found second arm -2,0 ... |
|
418
|
2
|
|
|
|
|
4
|
$arm = 1; |
|
419
|
2
|
|
|
|
|
5
|
$state = 42; |
|
420
|
2
|
|
|
|
|
4
|
last; |
|
421
|
|
|
|
|
|
|
} |
|
422
|
569
|
100
|
100
|
|
|
1091
|
if ($x == -1 && $y == -1) { |
|
423
|
|
|
|
|
|
|
### found third arm -1,-1 ... |
|
424
|
1
|
|
|
|
|
5
|
$arm = 2; |
|
425
|
1
|
|
|
|
|
2
|
$state = 70; |
|
426
|
1
|
|
|
|
|
4
|
last; |
|
427
|
|
|
|
|
|
|
} |
|
428
|
|
|
|
|
|
|
|
|
429
|
|
|
|
|
|
|
# if ((($x == -1 || $x == 1) && $y == -1) |
|
430
|
|
|
|
|
|
|
# || ($x == 0 && $y == -2)) { |
|
431
|
|
|
|
|
|
|
# ### below island ... |
|
432
|
|
|
|
|
|
|
# return undef; |
|
433
|
|
|
|
|
|
|
# } |
|
434
|
|
|
|
|
|
|
|
|
435
|
568
|
|
|
|
|
930
|
my $m = ($x + 2*$y) % 7; |
|
436
|
|
|
|
|
|
|
### at: "$x,$y digits=".join(',',@digits) |
|
437
|
|
|
|
|
|
|
### mod remainder: $m |
|
438
|
|
|
|
|
|
|
|
|
439
|
|
|
|
|
|
|
# 0,0 is m=0 |
|
440
|
568
|
100
|
|
|
|
1594
|
if ($m == 2) { # 2,0 = 2 |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
441
|
126
|
|
|
|
|
168
|
$x -= 2; |
|
442
|
|
|
|
|
|
|
} elsif ($m == 3) { # 1,1 = 1+2 = 3 |
|
443
|
97
|
|
|
|
|
138
|
$x -= 1; |
|
444
|
97
|
|
|
|
|
140
|
$y -= 1; |
|
445
|
|
|
|
|
|
|
} elsif ($m == 1) { # -1,1 = -1+2 = 1 |
|
446
|
74
|
|
|
|
|
126
|
$x += 1; |
|
447
|
74
|
|
|
|
|
115
|
$y -= 1; |
|
448
|
|
|
|
|
|
|
} elsif ($m == 4) { # 0,2 = 0+2*2 = 4 |
|
449
|
78
|
|
|
|
|
121
|
$y -= 2; |
|
450
|
|
|
|
|
|
|
} elsif ($m == 6) { # 2,2 = 2+2*2 = 6 |
|
451
|
61
|
|
|
|
|
110
|
$x -= 2; |
|
452
|
61
|
|
|
|
|
92
|
$y -= 2; |
|
453
|
|
|
|
|
|
|
} elsif ($m == 5) { # 3,1 = 3+2*1 = 5 |
|
454
|
70
|
|
|
|
|
134
|
$x -= 3; |
|
455
|
70
|
|
|
|
|
101
|
$y -= 1; |
|
456
|
|
|
|
|
|
|
} |
|
457
|
568
|
|
|
|
|
859
|
push @digits, $m; |
|
458
|
|
|
|
|
|
|
|
|
459
|
|
|
|
|
|
|
### digit: "$m to $x,$y" |
|
460
|
|
|
|
|
|
|
### shrink to: ((3*$y + 5*$x) / 14).','.((5*$y - $x) / 14) |
|
461
|
|
|
|
|
|
|
### assert: (3*$y + 5*$x) % 14 == 0 |
|
462
|
|
|
|
|
|
|
### assert: (5*$y - $x) % 14 == 0 |
|
463
|
|
|
|
|
|
|
|
|
464
|
|
|
|
|
|
|
# shrink |
|
465
|
568
|
|
|
|
|
1242
|
($x,$y) = ((3*$y + 5*$x) / 14, |
|
466
|
|
|
|
|
|
|
(5*$y - $x) / 14); |
|
467
|
|
|
|
|
|
|
} |
|
468
|
|
|
|
|
|
|
|
|
469
|
|
|
|
|
|
|
### @digits |
|
470
|
164
|
|
|
|
|
311
|
my $arms = $self->{'arms'}; |
|
471
|
164
|
100
|
|
|
|
381
|
if ($arm >= $arms) { |
|
472
|
1
|
|
|
|
|
5
|
return undef; |
|
473
|
|
|
|
|
|
|
} |
|
474
|
|
|
|
|
|
|
|
|
475
|
163
|
|
|
|
|
242
|
my $n = 0; |
|
476
|
163
|
|
|
|
|
340
|
foreach my $m (reverse @digits) { # high to low |
|
477
|
|
|
|
|
|
|
### $m |
|
478
|
|
|
|
|
|
|
### digit: $modulus_to_digit[$state + $m] |
|
479
|
|
|
|
|
|
|
### state: $state |
|
480
|
|
|
|
|
|
|
### next state: $modulus_to_digit[$state+7 + $m] |
|
481
|
|
|
|
|
|
|
|
|
482
|
565
|
|
|
|
|
886
|
$n = 7*$n + $modulus_to_digit[$state + $m]; |
|
483
|
565
|
|
|
|
|
1011
|
$state = $modulus_to_digit[$state+7 + $m]; |
|
484
|
|
|
|
|
|
|
} |
|
485
|
|
|
|
|
|
|
### final n along arm: $n |
|
486
|
|
|
|
|
|
|
|
|
487
|
163
|
|
|
|
|
627
|
return $n*$arms + $arm; |
|
488
|
|
|
|
|
|
|
} |
|
489
|
|
|
|
|
|
|
|
|
490
|
|
|
|
|
|
|
# exact |
|
491
|
|
|
|
|
|
|
sub rect_to_n_range { |
|
492
|
137
|
|
|
137
|
1
|
16260
|
my ($self, $x1,$y1, $x2,$y2) = @_; |
|
493
|
|
|
|
|
|
|
### FlowsnakeCentres rect_to_n_range(): "$x1,$y1 $x2,$y2" |
|
494
|
|
|
|
|
|
|
|
|
495
|
137
|
|
|
|
|
735
|
my ($r_lo, $r_hi) = _rect_to_radius_range ($x1,$y1*sqrt(3), $x2,$y2*sqrt(3)); |
|
496
|
137
|
|
|
|
|
319
|
$r_hi *= 2; |
|
497
|
137
|
|
|
|
|
381
|
my $level_plus_1 = ceil( log(max(1,$r_hi/4)) / log(sqrt(7)) ) + 2; |
|
498
|
|
|
|
|
|
|
# return (0, 7**$level_plus_1); |
|
499
|
|
|
|
|
|
|
|
|
500
|
|
|
|
|
|
|
|
|
501
|
137
|
|
|
|
|
291
|
my $level_limit = $level_plus_1; |
|
502
|
|
|
|
|
|
|
### $level_limit |
|
503
|
137
|
50
|
|
|
|
371
|
if (is_infinite($level_limit)) { return ($level_limit,$level_limit); } |
|
|
0
|
|
|
|
|
0
|
|
|
504
|
|
|
|
|
|
|
|
|
505
|
137
|
|
|
|
|
416
|
$x1 = round_nearest ($x1); |
|
506
|
137
|
|
|
|
|
307
|
$y1 = round_nearest ($y1); |
|
507
|
137
|
|
|
|
|
309
|
$x2 = round_nearest ($x2); |
|
508
|
137
|
|
|
|
|
300
|
$y2 = round_nearest ($y2); |
|
509
|
137
|
100
|
|
|
|
328
|
($x1,$x2) = ($x2,$x1) if $x1 > $x2; |
|
510
|
137
|
50
|
|
|
|
293
|
($y1,$y2) = ($y2,$y1) if $y1 > $y2; |
|
511
|
|
|
|
|
|
|
### sorted range: "$x1,$y1 $x2,$y2" |
|
512
|
|
|
|
|
|
|
|
|
513
|
|
|
|
|
|
|
my $rect_dist = sub { |
|
514
|
19277
|
|
|
19277
|
|
30747
|
my ($x,$y) = @_; |
|
515
|
19277
|
100
|
|
|
|
37479
|
my $xd = ($x < $x1 ? $x1 - $x |
|
|
|
100
|
|
|
|
|
|
|
516
|
|
|
|
|
|
|
: $x > $x2 ? $x - $x2 |
|
517
|
|
|
|
|
|
|
: 0); |
|
518
|
19277
|
100
|
|
|
|
34412
|
my $yd = ($y < $y1 ? $y1 - $y |
|
|
|
100
|
|
|
|
|
|
|
519
|
|
|
|
|
|
|
: $y > $y2 ? $y - $y2 |
|
520
|
|
|
|
|
|
|
: 0); |
|
521
|
19277
|
|
|
|
|
33479
|
return ($xd*$xd + 3*$yd*$yd); |
|
522
|
137
|
|
|
|
|
934
|
}; |
|
523
|
|
|
|
|
|
|
|
|
524
|
137
|
|
|
|
|
300
|
my $arms = $self->{'arms'}; |
|
525
|
|
|
|
|
|
|
### $arms |
|
526
|
137
|
|
|
|
|
260
|
my $n_lo; |
|
527
|
|
|
|
|
|
|
{ |
|
528
|
137
|
|
|
|
|
195
|
my @hypot = (6); |
|
|
137
|
|
|
|
|
283
|
|
|
529
|
137
|
|
|
|
|
219
|
my $top = 0; |
|
530
|
137
|
|
|
|
|
231
|
for (;;) { |
|
531
|
412
|
|
|
|
|
846
|
ARM_LO: foreach my $arm (0 .. $arms-1) { |
|
532
|
417
|
|
|
|
|
668
|
my $i = 0; |
|
533
|
417
|
|
|
|
|
548
|
my @digits; |
|
534
|
417
|
100
|
|
|
|
781
|
if ($top > 0) { |
|
535
|
276
|
|
|
|
|
605
|
@digits = ((0)x($top-1), 1); |
|
536
|
|
|
|
|
|
|
} else { |
|
537
|
141
|
|
|
|
|
266
|
@digits = (0); |
|
538
|
|
|
|
|
|
|
} |
|
539
|
|
|
|
|
|
|
|
|
540
|
417
|
|
|
|
|
669
|
for (;;) { |
|
541
|
9695
|
|
|
|
|
13642
|
my $n = 0; |
|
542
|
9695
|
|
|
|
|
15270
|
foreach my $digit (reverse @digits) { # high to low |
|
543
|
38225
|
|
|
|
|
53836
|
$n = 7*$n + $digit; |
|
544
|
|
|
|
|
|
|
} |
|
545
|
9695
|
|
|
|
|
13409
|
$n = $n*$arms + $arm; |
|
546
|
|
|
|
|
|
|
### lo consider: "i=$i digits=".join(',',reverse @digits)." is n=$n" |
|
547
|
|
|
|
|
|
|
|
|
548
|
9695
|
|
|
|
|
18836
|
my ($nx,$ny) = $self->n_to_xy($n); |
|
549
|
9695
|
|
|
|
|
18411
|
my $nh = &$rect_dist ($nx,$ny); |
|
550
|
9695
|
100
|
100
|
|
|
23649
|
if ($i == 0 && $nh == 0) { |
|
551
|
|
|
|
|
|
|
### lo found inside: $n |
|
552
|
139
|
100
|
66
|
|
|
386
|
if (! defined $n_lo || $n < $n_lo) { |
|
553
|
137
|
|
|
|
|
195
|
$n_lo = $n; |
|
554
|
|
|
|
|
|
|
} |
|
555
|
139
|
|
|
|
|
390
|
next ARM_LO; |
|
556
|
|
|
|
|
|
|
} |
|
557
|
|
|
|
|
|
|
|
|
558
|
9556
|
100
|
100
|
|
|
24493
|
if ($i == 0 || $nh > $hypot[$i]) { |
|
559
|
|
|
|
|
|
|
### too far away: "nxy=$nx,$ny nh=$nh vs ".$hypot[$i] |
|
560
|
|
|
|
|
|
|
|
|
561
|
8967
|
|
|
|
|
18797
|
while (++$digits[$i] > 6) { |
|
562
|
1318
|
|
|
|
|
1912
|
$digits[$i] = 0; |
|
563
|
1318
|
100
|
|
|
|
3145
|
if (++$i <= $top) { |
|
564
|
|
|
|
|
|
|
### backtrack up ... |
|
565
|
|
|
|
|
|
|
} else { |
|
566
|
|
|
|
|
|
|
### not found within this top and arm, next arm ... |
|
567
|
278
|
|
|
|
|
701
|
next ARM_LO; |
|
568
|
|
|
|
|
|
|
} |
|
569
|
|
|
|
|
|
|
} |
|
570
|
|
|
|
|
|
|
} else { |
|
571
|
|
|
|
|
|
|
### lo descend ... |
|
572
|
|
|
|
|
|
|
### assert: $i > 0 |
|
573
|
589
|
|
|
|
|
860
|
$i--; |
|
574
|
589
|
|
|
|
|
948
|
$digits[$i] = 0; |
|
575
|
|
|
|
|
|
|
} |
|
576
|
|
|
|
|
|
|
} |
|
577
|
|
|
|
|
|
|
} |
|
578
|
|
|
|
|
|
|
|
|
579
|
|
|
|
|
|
|
# if an $n_lo was found on any arm within this $top then done |
|
580
|
412
|
100
|
|
|
|
866
|
if (defined $n_lo) { |
|
581
|
137
|
|
|
|
|
270
|
last; |
|
582
|
|
|
|
|
|
|
} |
|
583
|
|
|
|
|
|
|
|
|
584
|
|
|
|
|
|
|
### lo extend top ... |
|
585
|
275
|
50
|
|
|
|
529
|
if (++$top > $level_limit) { |
|
586
|
|
|
|
|
|
|
### nothing below level limit ... |
|
587
|
0
|
|
|
|
|
0
|
return (1,0); |
|
588
|
|
|
|
|
|
|
} |
|
589
|
275
|
|
|
|
|
539
|
$hypot[$top] = 7 * $hypot[$top-1]; |
|
590
|
|
|
|
|
|
|
} |
|
591
|
|
|
|
|
|
|
} |
|
592
|
|
|
|
|
|
|
|
|
593
|
137
|
|
|
|
|
260
|
my $n_hi = 0; |
|
594
|
137
|
|
|
|
|
416
|
ARM_HI: foreach my $arm (reverse 0 .. $arms-1) { |
|
595
|
141
|
|
|
|
|
338
|
my @digits = ((6) x $level_limit); |
|
596
|
141
|
|
|
|
|
251
|
my $i = $#digits; |
|
597
|
141
|
|
|
|
|
209
|
for (;;) { |
|
598
|
9582
|
|
|
|
|
12853
|
my $n = 0; |
|
599
|
9582
|
|
|
|
|
15020
|
foreach my $digit (reverse @digits) { # high to low |
|
600
|
57361
|
|
|
|
|
79927
|
$n = 7*$n + $digit; |
|
601
|
|
|
|
|
|
|
} |
|
602
|
9582
|
|
|
|
|
13612
|
$n = $n*$arms + $arm; |
|
603
|
|
|
|
|
|
|
### hi consider: "arm=$arm i=$i digits=".join(',',reverse @digits)." is n=$n" |
|
604
|
|
|
|
|
|
|
|
|
605
|
9582
|
|
|
|
|
18777
|
my ($nx,$ny) = $self->n_to_xy($n); |
|
606
|
9582
|
|
|
|
|
18466
|
my $nh = &$rect_dist ($nx,$ny); |
|
607
|
9582
|
100
|
100
|
|
|
22284
|
if ($i == 0 && $nh == 0) { |
|
608
|
|
|
|
|
|
|
### hi found inside: $n |
|
609
|
139
|
100
|
|
|
|
304
|
if ($n > $n_hi) { |
|
610
|
131
|
|
|
|
|
197
|
$n_hi = $n; |
|
611
|
131
|
|
|
|
|
409
|
next ARM_HI; |
|
612
|
|
|
|
|
|
|
} |
|
613
|
|
|
|
|
|
|
} |
|
614
|
|
|
|
|
|
|
|
|
615
|
9451
|
100
|
100
|
|
|
26273
|
if ($i == 0 || $nh > (6 * 7**$i)) { |
|
616
|
|
|
|
|
|
|
### too far away: "$nx,$ny nh=$nh vs ".(6 * 7**$i) |
|
617
|
|
|
|
|
|
|
|
|
618
|
8063
|
|
|
|
|
17567
|
while (--$digits[$i] < 0) { |
|
619
|
866
|
|
|
|
|
1217
|
$digits[$i] = 6; |
|
620
|
866
|
100
|
|
|
|
2174
|
if (++$i < $level_limit) { |
|
621
|
|
|
|
|
|
|
### hi backtrack up ... |
|
622
|
|
|
|
|
|
|
} else { |
|
623
|
|
|
|
|
|
|
### hi nothing within level limit for this arm ... |
|
624
|
10
|
|
|
|
|
27
|
next ARM_HI; |
|
625
|
|
|
|
|
|
|
} |
|
626
|
|
|
|
|
|
|
} |
|
627
|
|
|
|
|
|
|
|
|
628
|
|
|
|
|
|
|
} else { |
|
629
|
|
|
|
|
|
|
### hi descend |
|
630
|
|
|
|
|
|
|
### assert: $i > 0 |
|
631
|
1388
|
|
|
|
|
1952
|
$i--; |
|
632
|
1388
|
|
|
|
|
2180
|
$digits[$i] = 6; |
|
633
|
|
|
|
|
|
|
} |
|
634
|
|
|
|
|
|
|
} |
|
635
|
|
|
|
|
|
|
} |
|
636
|
|
|
|
|
|
|
|
|
637
|
137
|
100
|
|
|
|
329
|
if ($n_hi == 0) { |
|
638
|
|
|
|
|
|
|
### oops, lo found but hi not found |
|
639
|
7
|
|
|
|
|
13
|
$n_hi = $n_lo; |
|
640
|
|
|
|
|
|
|
} |
|
641
|
|
|
|
|
|
|
|
|
642
|
137
|
|
|
|
|
1234
|
return ($n_lo, $n_hi); |
|
643
|
|
|
|
|
|
|
} |
|
644
|
|
|
|
|
|
|
|
|
645
|
|
|
|
|
|
|
#------------------------------------------------------------------------------ |
|
646
|
|
|
|
|
|
|
# levels |
|
647
|
|
|
|
|
|
|
|
|
648
|
|
|
|
|
|
|
# arms=1 arms=2 |
|
649
|
|
|
|
|
|
|
# level 1 0..6 = 7 0..13 = 14 |
|
650
|
|
|
|
|
|
|
# level 2 0..48 = 49 0..97 = 98 |
|
651
|
|
|
|
|
|
|
# 7^k-1 2*7^k-1 |
|
652
|
|
|
|
|
|
|
|
|
653
|
|
|
|
|
|
|
# level 7^k points |
|
654
|
|
|
|
|
|
|
# or arms*7^k |
|
655
|
|
|
|
|
|
|
# counting from 0 |
|
656
|
|
|
|
|
|
|
sub level_to_n_range { |
|
657
|
6
|
|
|
6
|
1
|
402
|
my ($self, $level) = @_; |
|
658
|
6
|
|
|
|
|
20
|
return (0, 7**$level * $self->{'arms'} - 1); |
|
659
|
|
|
|
|
|
|
} |
|
660
|
|
|
|
|
|
|
sub n_to_level { |
|
661
|
0
|
|
|
0
|
1
|
|
my ($self, $n) = @_; |
|
662
|
0
|
0
|
|
|
|
|
if ($n < 0) { return undef; } |
|
|
0
|
|
|
|
|
|
|
|
663
|
0
|
0
|
|
|
|
|
if (is_infinite($n)) { return $n; } |
|
|
0
|
|
|
|
|
|
|
|
664
|
0
|
|
|
|
|
|
$n = round_nearest($n); |
|
665
|
0
|
|
|
|
|
|
_divrem_mutate ($n, $self->{'arms'}); |
|
666
|
0
|
|
|
|
|
|
my ($pow, $exp) = round_up_pow ($n+1, 7); |
|
667
|
0
|
|
|
|
|
|
return $exp; |
|
668
|
|
|
|
|
|
|
} |
|
669
|
|
|
|
|
|
|
|
|
670
|
|
|
|
|
|
|
#------------------------------------------------------------------------------ |
|
671
|
|
|
|
|
|
|
1; |
|
672
|
|
|
|
|
|
|
__END__ |