File Coverage

blib/lib/App/Asciio/Cross.pm
Criterion Covered Total %
statement 27 179 15.0
branch 0 76 0.0
condition 0 96 0.0
subroutine 9 46 19.5
pod 0 8 0.0
total 36 405 8.8


line stmt bran cond sub pod time code
1              
2             package App::Asciio::Cross ;
3              
4             $|++ ;
5              
6 4     4   34 use strict;
  4         18  
  4         202  
7 4     4   26 use warnings;
  4         7  
  4         237  
8 4     4   28 use utf8;
  4         7  
  4         58  
9              
10 4     4   197 use Clone;
  4         7  
  4         236  
11              
12 4     4   25 use List::Util qw(first) ;
  4         7  
  4         362  
13 4     4   51 use List::MoreUtils qw(any) ;
  4         8  
  4         33  
14              
15 4     4   6167 use App::Asciio::String ;
  4         15  
  4         293  
16 4     4   29 use App::Asciio::Markup ;
  4         39  
  4         2857  
17              
18              
19             sub get_ascii_array_and_crossings
20             {
21 0     0 0   my ($asciio, $cross_filler_chars, $start_x, $end_x, $start_y, $end_y) = @_ ;
22              
23 0           my (@lines, @cross_point_index) ;
24              
25 0           for my $element (@{$asciio->{ELEMENTS}})
  0            
26             {
27 0 0   0     next if any { $_ eq ref($element) } @{$asciio->{CROSS_MODE_IGNORE}} ;
  0            
  0            
28            
29 0           for my $strip (@{$element->get_stripes()})
  0            
30             {
31 0           my $line_index = -1 ;
32            
33 0           for my $sub_strip (split("\n", $strip->{TEXT}))
34             {
35 0           $line_index++ ;
36            
37 0           my $y = $element->{Y} + $strip->{Y_OFFSET} + $line_index ;
38            
39 0 0 0       next if defined $start_y && ($y < $start_y || $y >= $end_y) ;
      0        
40            
41 0           $sub_strip = $USE_MARKUP_CLASS->delete_markup_characters($sub_strip) ;
42            
43 0           my $character_index = 0 ;
44            
45 0           for my $character (split '', $sub_strip)
46             {
47 0           my $x = $element->{X} + $strip->{X_OFFSET} + $character_index ;
48            
49 0 0 0       if((defined $start_x) && ($x < $start_x || $x >= $end_x))
    0 0        
      0        
50             {
51             # skip
52             }
53             elsif($x >= 0 && $y >= 0)
54             {
55             # keep the characters that may be crossing in the array
56             # other characters are discarded
57 0 0         if(exists $cross_filler_chars->{$character})
58             {
59 0 0         if(defined $lines[$y][$x])
60             {
61 0           push @{$lines[$y][$x]}, $character ;
  0            
62            
63 0           push @cross_point_index, [$y, $x] ;
64             }
65             else
66             {
67 0           $lines[$y][$x] = [$character] ;
68             }
69            
70             }
71             else
72             {
73 0           delete $lines[$y][$x] ;
74             }
75             }
76            
77 0           $character_index += unicode_length($character);
78             }
79             }
80             }
81             }
82              
83 0           @cross_point_index = grep { defined $lines[$_->[0]][$_->[1]][1] } @cross_point_index ;
  0            
84              
85 0           return(\@lines, \@cross_point_index) ;
86             }
87              
88             #-----------------------------------------------------------------------------
89             # ascii: + X . '
90             # unicode: ┼ ┤ ├ ┬ ┴ ╭ ╮ ╯ ╰ ╳ ... ...
91              
92 4     4   972 use Readonly ;
  4         5754  
  4         23082  
93             Readonly my $CHARACTER => 0 ;
94             Readonly my $FUNCTION => 1 ;
95             Readonly my $CHAR_CATEGORY_INDEXS => 2 ;
96              
97             {
98              
99             my ($undef_char, %normal_char_cache, %diagonal_char_cache) = ('w') ;
100              
101             my %all_cross_chars = map {$_, 1}
102             (
103             '-', '|', '.', '\'', '\\', '/', '+', '╱', '╲', '╳',
104             '─', '│', '┼', '┤', '├', '┬', '┴', '╭', '╮', '╯', '╰',
105             '━', '┃', '╋', '┫', '┣', '┳', '┻', '┏', '┓', '┛', '┗',
106             '═', '║', '╬', '╣', '╠', '╦', '╩', '╔', '╗', '╝', '╚',
107             '╫', '╪', '╨', '╧', '╥', '╤', '╢', '╡', '╟', '╞', '╜',
108             '╛', '╙', '╘', '╖', '╕', '╓', '╒', '<', '>', '^', 'v',
109             '┍', '┎', '┑', '┒', '┕', '┖', '┙', '┚',
110             '┝', '┞', '┟', '┠', '┡', '┢',
111             '┥', '┦', '┧', '┨', '┩', '┪',
112             '┭', '┮', '┯', '┰', '┱', '┲',
113             '┵', '┶', '┷', '┸', '┹', '┺',
114             '┽', '┾', '┿', '╀', '╁', '╂', '╃',
115             '╄', '╅', '╆', '╇', '╈', '╉', '╊',
116             ) ;
117              
118             my %diagonal_cross_chars = map {$_, 1} ('\\', '/', '╱', '╲', '╳') ;
119              
120             my %unicode_left_thin_chars = map {$_, 1} ('─', '┼', '├', '┬', '┴', '╭', '╰', '╫', '╨', '╥', '╟', '╙', '╓', '┎', '┖', '┞', '┟', '┠', '┭', '┰', '┱', '┵', '┸', '┹', '┽', '╀', '╁', '╂', '╃', '╅', '╉') ;
121             my %unicode_right_thin_chars = map {$_, 1} ('─', '┼', '┤', '┬', '┴', '╮', '╯', '╫', '╨', '╥', '╢', '╜', '╖', '┒', '┚', '┦', '┧', '┨', '┮', '┰', '┲', '┶', '┸', '┺', '┾', '╀', '╁', '╂', '╄', '╆', '╊') ;
122             my %unicode_up_thin_chars = map {$_, 1} ('│', '┼', '┤', '├', '┬', '╭', '╮', '╪', '╤', '╡', '╞', '╕', '╒', '┍', '┑', '┝', '┞', '┡', '┥', '┦', '┩', '┭', '┮', '┯', '┽', '┾', '┿', '╀', '╃', '╄', '╇') ;
123             my %unicode_down_thin_chars = map {$_, 1} ('│', '┼', '┤', '├', '┴', '╯', '╰', '╪', '╧', '╡', '╞', '╛', '╘', '┕', '┙', '┝', '┟', '┢', '┥', '┧', '┪', '┵', '┶', '┷', '┽', '┾', '┿', '╁', '╅', '╆', '╈') ;
124              
125             my %unicode_left_double_chars = map {$_, 1} ('═', '╬', '╠', '╦', '╩', '╔', '╚', '╪', '╧', '╤', '╞', '╘', '╒') ;
126             my %unicode_right_double_chars = map {$_, 1} ('═', '╬', '╣', '╦', '╩', '╗', '╝', '╪', '╧', '╤', '╡', '╛', '╕') ;
127             my %unicode_up_double_chars = map {$_, 1} ('║', '╬', '╣', '╠', '╦', '╔', '╗', '╫', '╥', '╢', '╟', '╖', '╓') ;
128             my %unicode_down_double_chars = map {$_, 1} ('║', '╬', '╣', '╠', '╩', '╝', '╚', '╫', '╨', '╢', '╟', '╜', '╙') ;
129              
130             my %unicode_left_bold_chars = map {$_, 1} ('━', '╋', '┣', '┳', '┻', '┏', '┗', '┍', '┕', '┝', '┡', '┢', '┮', '┯', '┲', '┶', '┷', '┺', '┾', '┿', '╄', '╆', '╇', '╈', '╊') ;
131             my %unicode_right_bold_chars = map {$_, 1} ('━', '╋', '┫', '┳', '┻', '┓', '┛', '┑', '┙', '┥', '┩', '┪', '┭', '┯', '┱', '┵', '┷', '┹', '┽', '┿', '╃', '╅', '╇', '╈', '╉') ;
132             my %unicode_up_bold_chars = map {$_, 1} ('┃', '╋', '┫', '┣', '┳', '┏', '┓', '┎', '┒', '┟', '┠', '┢', '┧', '┨', '┪', '┰', '┱', '┲', '╁', '╂', '╅', '╆', '╈', '╉', '╊') ;
133             my %unicode_down_bold_chars = map {$_, 1} ('┃', '╋', '┫', '┣', '┻', '┛', '┗', '┖', '┚', '┞', '┠', '┡', '┦', '┨', '┩', '┸', '┹', '┺', '╀', '╂', '╃', '╄', '╇', '╉', '╊') ;
134              
135             my @unicode_cross_chars = (
136             {%unicode_left_thin_chars} , {%unicode_left_double_chars} , {%unicode_left_bold_chars} ,
137             {%unicode_right_thin_chars} , {%unicode_right_double_chars} , {%unicode_right_bold_chars} ,
138             {%unicode_up_thin_chars} , {%unicode_up_double_chars} , {%unicode_up_bold_chars} ,
139             {%unicode_down_thin_chars} , {%unicode_down_double_chars} , {%unicode_down_bold_chars}
140             );
141              
142             # The index here has a one-to-one correspondence with the array unicode_cross_chars.
143             my $left_thin_index = 0;
144             my $left_double_index = 1;
145             my $left_bold_index = 2;
146             my $right_thin_index = 3;
147             my $right_double_index = 4;
148             my $right_bold_index = 5;
149             my $up_thin_index = 6;
150             my $up_double_index = 7;
151             my $up_bold_index = 8;
152             my $down_thin_index = 9;
153             my $down_double_index = 10;
154             my $down_bold_index = 11;
155              
156             my %left_index_map = map {$_ , 1} ($left_thin_index , $left_double_index , $left_bold_index) ;
157             my %right_index_map = map {$_ , 1} ($right_thin_index , $right_double_index , $right_bold_index) ;
158             my %up_index_map = map {$_ , 1} ($up_thin_index , $up_double_index , $up_bold_index) ;
159             my %down_index_map = map {$_ , 1} ($down_thin_index , $down_double_index , $down_bold_index) ;
160              
161             my @normal_char_func = (
162             ['+', \&scene_cross, ],
163             ['.', \&scene_dot, ],
164             ['\'',\&scene_apostrophe, ],
165            
166             # Arranging them in order can reduce logical judgment. Because calculations are done sequentially
167             # 1. First are cross,
168             # 2. then are corner missing
169             # 3. and finally are two corners missing.
170             # Therefore, the order of functions in the array cannot be disrupted
171            
172             # cross functios
173             ['┽' , \&scene_unicode , [$left_bold_index , $right_thin_index , $up_thin_index , $down_thin_index ]],
174             ['┾' , \&scene_unicode , [$left_thin_index , $right_bold_index , $up_thin_index , $down_thin_index ]],
175             ['┿' , \&scene_unicode , [$left_bold_index , $right_bold_index , $up_thin_index , $down_thin_index ]],
176             ['╀' , \&scene_unicode , [$left_thin_index , $right_thin_index , $up_bold_index , $down_thin_index ]],
177             ['╁' , \&scene_unicode , [$left_thin_index , $right_thin_index , $up_thin_index , $down_bold_index ]],
178             ['╂' , \&scene_unicode , [$left_thin_index , $right_thin_index , $up_bold_index , $down_bold_index ]],
179             ['╃' , \&scene_unicode , [$left_bold_index , $right_thin_index , $up_bold_index , $down_thin_index ]],
180             ['╄' , \&scene_unicode , [$left_thin_index , $right_bold_index , $up_bold_index , $down_thin_index ]],
181             ['╅' , \&scene_unicode , [$left_bold_index , $right_thin_index , $up_thin_index , $down_bold_index ]],
182             ['╆' , \&scene_unicode , [$left_thin_index , $right_bold_index , $up_thin_index , $down_bold_index ]],
183             ['╇' , \&scene_unicode , [$left_bold_index , $right_bold_index , $up_bold_index , $down_thin_index ]],
184             ['╈' , \&scene_unicode , [$left_bold_index , $right_bold_index , $up_thin_index , $down_bold_index ]],
185             ['╉' , \&scene_unicode , [$left_bold_index , $right_thin_index , $up_bold_index , $down_bold_index ]],
186             ['╊' , \&scene_unicode , [$left_thin_index , $right_bold_index , $up_bold_index , $down_bold_index ]],
187             ['╫' , \&scene_unicode , [$left_thin_index , $right_thin_index , $up_double_index , $down_double_index ]],
188             ['╪' , \&scene_unicode , [$left_double_index , $right_double_index , $up_thin_index , $down_thin_index ]],
189             ['┼' , \&scene_unicode , [$left_thin_index , $right_thin_index , $up_thin_index , $down_thin_index ]],
190             ['╋' , \&scene_unicode , [$left_bold_index , $right_bold_index , $up_bold_index , $down_bold_index ]],
191             ['╬' , \&scene_unicode , [$left_double_index , $right_double_index , $up_double_index , $down_double_index ]],
192              
193             # one corner missing functios
194             ['┵' , \&scene_unicode , [$left_bold_index , $right_thin_index , $up_thin_index ]],
195             ['┶' , \&scene_unicode , [$left_thin_index , $right_bold_index , $up_thin_index ]],
196             ['┷' , \&scene_unicode , [$left_bold_index , $right_bold_index , $up_thin_index ]],
197             ['┸' , \&scene_unicode , [$left_thin_index , $right_thin_index , $up_bold_index ]],
198             ['┹' , \&scene_unicode , [$left_bold_index , $right_thin_index , $up_bold_index ]],
199             ['┺' , \&scene_unicode , [$left_thin_index , $right_bold_index , $up_bold_index ]],
200             ['┭' , \&scene_unicode , [$left_bold_index , $right_thin_index , $down_thin_index ]],
201             ['┮' , \&scene_unicode , [$left_thin_index , $right_bold_index , $down_thin_index ]],
202             ['┯' , \&scene_unicode , [$left_bold_index , $right_bold_index , $down_thin_index ]],
203             ['┰' , \&scene_unicode , [$left_thin_index , $right_thin_index , $down_bold_index ]],
204             ['┱' , \&scene_unicode , [$left_bold_index , $right_thin_index , $down_bold_index ]],
205             ['┲' , \&scene_unicode , [$left_thin_index , $right_bold_index , $down_bold_index ]],
206             ['┥' , \&scene_unicode , [$left_bold_index , $up_thin_index , $down_thin_index ]],
207             ['┦' , \&scene_unicode , [$left_thin_index , $up_bold_index , $down_thin_index ]],
208             ['┧' , \&scene_unicode , [$left_thin_index , $up_thin_index , $down_bold_index ]],
209             ['┨' , \&scene_unicode , [$left_thin_index , $up_bold_index , $down_bold_index ]],
210             ['┩' , \&scene_unicode , [$left_bold_index , $up_bold_index , $down_thin_index ]],
211             ['┪' , \&scene_unicode , [$left_bold_index , $up_thin_index , $down_bold_index ]],
212             ['┝' , \&scene_unicode , [$right_bold_index , $up_thin_index , $down_thin_index ]],
213             ['┞' , \&scene_unicode , [$right_thin_index , $up_bold_index , $down_thin_index ]],
214             ['┟' , \&scene_unicode , [$right_thin_index , $up_thin_index , $down_bold_index ]],
215             ['┠' , \&scene_unicode , [$right_thin_index , $up_bold_index , $down_bold_index ]],
216             ['┡' , \&scene_unicode , [$right_bold_index , $up_bold_index , $down_thin_index ]],
217             ['┢' , \&scene_unicode , [$right_bold_index , $up_thin_index , $down_bold_index ]],
218             ['╨' , \&scene_unicode , [$left_thin_index , $right_thin_index , $up_double_index ]],
219             ['╧' , \&scene_unicode , [$left_double_index , $right_double_index , $up_thin_index ]],
220             ['╥' , \&scene_unicode , [$left_thin_index , $right_thin_index , $down_double_index ]],
221             ['╤' , \&scene_unicode , [$left_double_index , $right_double_index , $down_thin_index ]],
222             ['╢' , \&scene_unicode , [$left_thin_index , $up_double_index , $down_double_index ]],
223             ['╡' , \&scene_unicode , [$left_double_index , $up_thin_index , $down_thin_index ]],
224             ['╟' , \&scene_unicode , [$right_thin_index , $up_double_index , $down_double_index ]],
225             ['╞' , \&scene_unicode , [$right_double_index , $up_thin_index , $down_thin_index ]],
226             ['┤' , \&scene_unicode , [$left_thin_index , $up_thin_index , $down_thin_index ]],
227             ['├' , \&scene_unicode , [$right_thin_index , $up_thin_index , $down_thin_index ]],
228             ['┬' , \&scene_unicode , [$left_thin_index , $right_thin_index , $down_thin_index ]],
229             ['┴' , \&scene_unicode , [$left_thin_index , $right_thin_index , $up_thin_index ]],
230             ['┫' , \&scene_unicode , [$left_bold_index , $up_bold_index , $down_bold_index ]],
231             ['┣' , \&scene_unicode , [$right_bold_index , $up_bold_index , $down_bold_index ]],
232             ['┳' , \&scene_unicode , [$left_bold_index , $right_bold_index , $down_bold_index ]],
233             ['┻' , \&scene_unicode , [$left_bold_index , $right_bold_index , $up_bold_index ]],
234             ['╣' , \&scene_unicode , [$left_double_index , $up_double_index , $down_double_index ]],
235             ['╠' , \&scene_unicode , [$right_double_index , $up_double_index , $down_double_index ]],
236             ['╦' , \&scene_unicode , [$left_double_index , $right_double_index , $down_double_index ]],
237             ['╩' , \&scene_unicode , [$left_double_index , $right_double_index , $up_double_index ]],
238              
239             # two corners missing
240             ['╜' , \&scene_unicode , [$left_thin_index , $up_double_index ]],
241             ['╛' , \&scene_unicode , [$left_double_index , $up_thin_index ]],
242             ['╙' , \&scene_unicode , [$right_thin_index , $up_double_index ]],
243             ['╘' , \&scene_unicode , [$right_double_index , $up_thin_index ]],
244             ['╖' , \&scene_unicode , [$left_thin_index , $down_double_index ]],
245             ['╕' , \&scene_unicode , [$left_double_index , $down_thin_index ]],
246             ['╓' , \&scene_unicode , [$right_thin_index , $down_double_index ]],
247             ['╒' , \&scene_unicode , [$right_double_index , $down_thin_index ]],
248             ['┍' , \&scene_unicode , [$right_bold_index , $down_thin_index ]],
249             ['┎' , \&scene_unicode , [$right_thin_index , $down_bold_index ]],
250             ['┑' , \&scene_unicode , [$left_bold_index , $down_thin_index ]],
251             ['┒' , \&scene_unicode , [$left_thin_index , $down_bold_index ]],
252             ['┕' , \&scene_unicode , [$right_bold_index , $up_thin_index ]],
253             ['┖' , \&scene_unicode , [$right_thin_index , $up_bold_index ]],
254             ['┙' , \&scene_unicode , [$left_bold_index , $up_thin_index ]],
255             ['┚' , \&scene_unicode , [$left_thin_index , $up_bold_index ]],
256             ['╭' , \&scene_unicode , [$right_thin_index , $down_thin_index ]],
257             ['╮' , \&scene_unicode , [$left_thin_index , $down_thin_index ]],
258             ['╯' , \&scene_unicode , [$left_thin_index , $up_thin_index ]],
259             ['╰' , \&scene_unicode , [$right_thin_index , $up_thin_index ]],
260             ['┏' , \&scene_unicode , [$right_bold_index , $down_bold_index ]],
261             ['┓' , \&scene_unicode , [$left_bold_index , $down_bold_index ]],
262             ['┛' , \&scene_unicode , [$left_bold_index , $up_bold_index ]],
263             ['┗' , \&scene_unicode , [$right_bold_index , $up_bold_index ]],
264             ['╔' , \&scene_unicode , [$right_double_index , $down_double_index ]],
265             ['╗' , \&scene_unicode , [$left_double_index , $down_double_index ]],
266             ['╝' , \&scene_unicode , [$left_double_index , $up_double_index ]],
267             ['╚' , \&scene_unicode , [$right_double_index , $up_double_index ]],
268             ) ;
269              
270             my @diagonal_char_func = (
271             ['X', \&scene_x],
272             ['╳', \&scene_unicode_x],
273             ) ;
274              
275              
276             sub get_cross_mode_overlays
277             {
278 0     0 0   my ($asciio, $start_x, $end_x, $start_y, $end_y) = @_;
279              
280 0           my ($ascii_array, $crossings) = get_ascii_array_and_crossings($asciio, \%all_cross_chars, $start_x, $end_x, $start_y, $end_y);
281 0           my @ascii_array = @{$ascii_array} ;
  0            
282              
283 0           my @overlays ;
284              
285 0           for(@{$crossings})
  0            
286             {
287 0           my ($row, $col) = @{$_} ;
  0            
288            
289 0           my ($up, $down, $left, $right) =
290             ($ascii_array[$row-1][$col], $ascii_array[$row+1][$col], $ascii_array[$row][$col-1], $ascii_array[$row][$col+1]);
291            
292 0           my $normal_key = ((defined $up) ? join('o', @{$up}) : $undef_char) . '_'
293 0           . ((defined $down) ? join('o', @{$down}) : $undef_char) . '_'
294 0           . ((defined $left) ? join('o', @{$left}) : $undef_char) . '_'
295 0 0         . ((defined $right) ? join('o', @{$right}) : $undef_char) ;
  0 0          
    0          
    0          
296            
297 0 0         unless(exists $normal_char_cache{$normal_key})
298             {
299 0     0     my $scene_func = first { $_->[$FUNCTION]($up, $down, $left, $right, $_->[$CHAR_CATEGORY_INDEXS]) } @normal_char_func;
  0            
300 0 0         $normal_char_cache{$normal_key} = ($scene_func) ? $scene_func->[$CHARACTER] : '';
301             }
302            
303 0 0         if($normal_char_cache{$normal_key})
304             {
305 0 0         if($normal_char_cache{$normal_key} ne $ascii_array[$row][$col][-1])
306             {
307 0           push @overlays, [$col, $row, $normal_char_cache{$normal_key}];
308             }
309              
310 0           next;
311             }
312            
313 0 0         next unless exists $diagonal_cross_chars{$ascii_array[$row][$col][-1]} ;
314            
315 0           my ($char_45, $char_135, $char_225, $char_315) =
316             ($ascii_array[$row-1][$col+1], $ascii_array[$row+1][$col+1], $ascii_array[$row+1][$col-1], $ascii_array[$row-1][$col-1]);
317            
318 0           my $diagonal_key = ((defined $char_45) ? join('o', @{$char_45}) : $undef_char) . '_'
319 0           . ((defined $char_135) ? join('o', @{$char_135}) : $undef_char) . '_'
320 0           . ((defined $char_225) ? join('o', @{$char_225}) : $undef_char) . '_'
321 0 0         . ((defined $char_315) ? join('o', @{$char_315}) : $undef_char) ;
  0 0          
    0          
    0          
322            
323 0 0         unless(exists $diagonal_char_cache{$diagonal_key})
324             {
325 0     0     my $scene_func = first { $_->[$FUNCTION]($char_45, $char_135, $char_225, $char_315) } @diagonal_char_func;
  0            
326 0 0         $diagonal_char_cache{$diagonal_key} = ($scene_func) ? $scene_func->[$CHARACTER] : '';
327             }
328            
329 0 0 0       if($diagonal_char_cache{$diagonal_key} && ($diagonal_char_cache{$diagonal_key} ne $ascii_array[$row][$col][-1]))
330             {
331 0           push @overlays, [$col, $row, $diagonal_char_cache{$diagonal_key}];
332             }
333              
334             }
335              
336 0           return @overlays ;
337             }
338              
339             #-----------------------------------------------------------------------------
340             # +
341             sub scene_cross
342             {
343 0     0 0   my ($up, $down, $left, $right, $char_category_indexs) = @_;
344              
345 0 0 0       return 0 unless defined $up && defined $down && defined $left && defined $right ;
      0        
      0        
346              
347 0     0     return ((any {$_ eq '|'} @{$up}) || (any {$_ eq '.'} @{$up}) || (any {$_ eq '\''} @{$up}) || (any {$_ eq '+'} @{$up}) || (any {$_ eq '^'} @{$up}))
  0            
  0            
  0            
  0            
348 0     0     && ((any {$_ eq '|'} @{$down}) || (any {$_ eq '.'} @{$down}) || (any {$_ eq '\''} @{$down}) || (any {$_ eq '+'} @{$down}) || (any {$_ eq 'v'} @{$down}))
  0            
  0            
  0            
  0            
349 0     0     && ((any {$_ eq '-'} @{$left}) || (any {$_ eq '.'} @{$left}) || (any {$_ eq '\''} @{$left}) || (any {$_ eq '+'} @{$left}) || (any {$_ eq '<'} @{$left}))
  0            
  0            
  0            
  0            
350 0   0 0     && ((any {$_ eq '-'} @{$right}) || (any {$_ eq '.'} @{$right}) || (any {$_ eq '\''} @{$right}) || (any {$_ eq '+'} @{$right}) || (any {$_ eq '>'} @{$right})) ;
  0            
  0            
  0            
  0            
  0            
351             }
352              
353             #-----------------------------------------------------------------------------
354             # .
355             # | |
356             # ---. .--- ---.--- | |
357             # | | | ---. .---
358             # | | | | |
359             sub scene_dot
360             {
361 0     0 0   my ($up, $down, $left, $right, $char_category_indexs) = @_;
362              
363 0     0     return 0 if defined $up && (any {$_ eq '|'} @{$up})
  0            
364 0     0     && defined $down && (any {$_ eq '|'} @{$down})
  0            
365 0     0     && defined $left && (any {$_ eq '-'} @{$left})
  0            
366 0 0 0 0     && defined $right && (any {$_ eq '-'} @{$right}) ;
  0   0        
  0   0        
      0        
      0        
      0        
      0        
367              
368 0     0     return (((defined($left) && (any {$_ eq '-'} @{$left})) && (defined($down) && (any {$_ eq '|'} @{$down}))) ||
  0            
369 0   0 0     ((defined($right) && (any {$_ eq '-'} @{$right})) && (defined($down) && (any {$_ eq '|'} @{$down})))) ;
  0            
  0            
370             }
371              
372             #-----------------------------------------------------------------------------
373             # '
374             # | | |
375             # | | |
376             # '--- ---' ---'---
377             sub scene_apostrophe
378             {
379 0     0 0   my ($up, $down, $left, $right, $char_category_indexs) = @_;
380              
381 0     0     return 1 if(((defined($up) && (any {$_ eq '|'} @{$up})) && (defined($right) && (any {$_ eq '-'} @{$right}))) &&
  0            
  0            
  0            
382 0 0 0 0     !(defined($down) && (any {$_ eq '|'} @{$down}))) ;
  0   0        
      0        
      0        
      0        
383              
384 0     0     return ((defined($up) && (any {$_ eq '|'} @{$up})) && (defined($left) && (any {$_ eq '-'} @{$left})) &&
  0            
385 0   0 0     !((defined($down) && (any {$_ eq '|'} @{$down})) || (defined($right) && (any {$_ eq '|'} @{$right})))) ;
  0            
  0            
386              
387             }
388              
389             sub scene_unicode
390             {
391 0     0 0   my ($up, $down, $left, $right, $char_category_indexs) = @_;
392              
393 0           for my $char_index (@{$char_category_indexs})
  0            
394             {
395 0 0         if(exists $left_index_map{$char_index})
    0          
    0          
396             {
397 0 0         return 0 unless defined $left;
398 0 0   0     return 0 unless any {exists $unicode_cross_chars[$char_index]{$_}} @{$left};
  0            
  0            
399             }
400             elsif(exists $right_index_map{$char_index})
401             {
402 0 0         return 0 unless defined $right;
403 0 0   0     return 0 unless any {exists $unicode_cross_chars[$char_index]{$_}} @{$right};
  0            
  0            
404             }
405             elsif(exists $up_index_map{$char_index})
406             {
407 0 0         return 0 unless defined $up;
408 0 0   0     return 0 unless any {exists $unicode_cross_chars[$char_index]{$_}} @{$up};
  0            
  0            
409             }
410             else
411             {
412 0 0         return 0 unless defined $down;
413 0 0   0     return 0 unless any {exists $unicode_cross_chars[$char_index]{$_}} @{$down};
  0            
  0            
414             }
415             }
416              
417 0           return 1;
418              
419             }
420              
421             #-----------------------------------------------------------------------------
422             # X
423             sub scene_x
424             {
425 0     0 0   my ($char_45, $char_135, $char_225, $char_315) = @_;
426              
427 0 0 0       return 0 unless defined $char_45 && defined $char_135 && defined $char_225 && defined $char_315 ;
      0        
      0        
428              
429 0     0     return (any {$_ eq '/' || $_ eq '^'} @{$char_45})
430 0     0     && (any {$_ eq '\\' || $_ eq 'v'} @{$char_135})
431 0     0     && (any {$_ eq '/' || $_ eq 'v'} @{$char_225})
432 0   0 0     && (any {$_ eq '\\' || $_ eq '^'} @{$char_315}) ;
  0            
433             }
434              
435             #-----------------------------------------------------------------------------
436             # ╳
437             sub scene_unicode_x
438             {
439 0     0 0   my ($char_45, $char_135, $char_225, $char_315) = @_;
440              
441 0 0 0       return 0 unless defined $char_45 && defined $char_135 && defined $char_225 && defined $char_315 ;
      0        
      0        
442              
443 0     0     return (any {$_ eq '╱' || $_ eq '^'} @{$char_45})
444 0     0     && (any {$_ eq '╲' || $_ eq 'v'} @{$char_135})
445 0     0     && (any {$_ eq '╱' || $_ eq 'v'} @{$char_225})
446 0   0 0     && (any {$_ eq '╲' || $_ eq '^'} @{$char_315}) ;
  0            
447             }
448              
449             }
450              
451             #-----------------------------------------------------------------------------
452              
453             1 ;
454