| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package Games::Solitaire::BlackHole::Solver::Golf::App; |
|
2
|
|
|
|
|
|
|
$Games::Solitaire::BlackHole::Solver::Golf::App::VERSION = '0.18.0'; |
|
3
|
2
|
|
|
2
|
|
270653
|
use 5.014; |
|
|
2
|
|
|
|
|
9
|
|
|
4
|
2
|
|
|
2
|
|
1435
|
use Moo; |
|
|
2
|
|
|
|
|
18522
|
|
|
|
2
|
|
|
|
|
11
|
|
|
5
|
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
extends('Games::Solitaire::BlackHole::Solver::App::Base'); |
|
7
|
2
|
|
|
2
|
|
4360
|
use Games::Solitaire::BlackHole::Solver::App::Base qw/ $card_re /; |
|
|
2
|
|
|
|
|
9
|
|
|
|
2
|
|
|
|
|
1637
|
|
|
8
|
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
sub run |
|
11
|
|
|
|
|
|
|
{ |
|
12
|
1
|
|
|
1
|
1
|
4960
|
my $self = shift; |
|
13
|
1
|
|
|
|
|
11
|
my $RANK_KING = $self->_RANK_KING; |
|
14
|
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
# A boolean |
|
16
|
1
|
|
|
|
|
3
|
my $place_queens_on_kings = ''; |
|
17
|
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
# A boolean |
|
19
|
1
|
|
|
|
|
2
|
my $wrap_ranks = ''; |
|
20
|
1
|
|
|
|
|
15
|
$self->_process_cmd_line( |
|
21
|
|
|
|
|
|
|
{ |
|
22
|
|
|
|
|
|
|
extra_flags => { |
|
23
|
|
|
|
|
|
|
"queens-on-kings!" => \$place_queens_on_kings, |
|
24
|
|
|
|
|
|
|
"wrap-ranks!" => \$wrap_ranks, |
|
25
|
|
|
|
|
|
|
} |
|
26
|
|
|
|
|
|
|
} |
|
27
|
|
|
|
|
|
|
); |
|
28
|
1
|
50
|
|
|
|
7
|
if ($wrap_ranks) |
|
29
|
|
|
|
|
|
|
{ |
|
30
|
0
|
|
|
|
|
0
|
$place_queens_on_kings = 1; |
|
31
|
|
|
|
|
|
|
} |
|
32
|
1
|
|
|
|
|
9
|
$self->_calc_lines( shift(@ARGV), ); |
|
33
|
|
|
|
|
|
|
|
|
34
|
1
|
|
|
|
|
2
|
my $talon_line = shift( @{ $self->_board_lines } ); |
|
|
1
|
|
|
|
|
5
|
|
|
35
|
1
|
|
|
|
|
3
|
my @talon_values; |
|
36
|
1
|
|
|
|
|
2
|
my $talon_ptr = 0; |
|
37
|
1
|
50
|
|
|
|
69
|
if ( my ($cards) = $talon_line =~ m{\ATalon:((?: $card_re){16})\z} ) |
|
38
|
|
|
|
|
|
|
{ |
|
39
|
16
|
|
|
|
|
41
|
@talon_values = map { $self->_get_rank($_) } |
|
40
|
1
|
|
|
|
|
3
|
@{ $self->_talon_cards( [ $cards =~ /($card_re)/g ] ) }; |
|
|
1
|
|
|
|
|
67
|
|
|
41
|
|
|
|
|
|
|
} |
|
42
|
|
|
|
|
|
|
else |
|
43
|
|
|
|
|
|
|
{ |
|
44
|
0
|
|
|
|
|
0
|
die "Could not match first talon line!"; |
|
45
|
|
|
|
|
|
|
} |
|
46
|
|
|
|
|
|
|
|
|
47
|
1
|
50
|
|
|
|
13
|
$self->_set_up_solver( $talon_ptr, |
|
48
|
|
|
|
|
|
|
[ 1, ( $wrap_ranks ? ($RANK_KING) : () ) ] ); |
|
49
|
|
|
|
|
|
|
|
|
50
|
1
|
|
|
|
|
2
|
my $positions = $self->_positions; |
|
51
|
1
|
|
|
|
|
8
|
my $board_values = $self->_board_values; |
|
52
|
|
|
|
|
|
|
|
|
53
|
1
|
|
|
|
|
2
|
my $verdict = 0; |
|
54
|
|
|
|
|
|
|
|
|
55
|
1
|
|
|
|
|
6
|
$self->_next_task; |
|
56
|
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
QUEUE_LOOP: |
|
58
|
1
|
|
|
|
|
5
|
while ( my $state = $self->_get_next_state_wrapper ) |
|
59
|
|
|
|
|
|
|
{ |
|
60
|
|
|
|
|
|
|
# The foundation |
|
61
|
953
|
|
|
|
|
1443
|
my $fnd = vec( $state, 0, 8 ); |
|
62
|
953
|
|
|
|
|
1246
|
my $no_cards = 1; |
|
63
|
953
|
|
|
|
|
1230
|
my $tln = vec( $state, 1, 8 ); |
|
64
|
953
|
|
|
|
|
1346
|
my @sub_queue; |
|
65
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
my @_pending; |
|
67
|
|
|
|
|
|
|
|
|
68
|
953
|
50
|
33
|
|
|
1917
|
if ( $place_queens_on_kings || ( $fnd != $RANK_KING ) ) |
|
69
|
|
|
|
|
|
|
{ |
|
70
|
953
|
|
|
|
|
1899
|
$self->_find_moves( \@sub_queue, $state, \$no_cards ); |
|
71
|
|
|
|
|
|
|
} |
|
72
|
|
|
|
|
|
|
else |
|
73
|
|
|
|
|
|
|
{ |
|
74
|
|
|
|
|
|
|
COL: |
|
75
|
0
|
|
|
|
|
0
|
foreach my $col_idx ( keys @$board_values ) |
|
76
|
|
|
|
|
|
|
{ |
|
77
|
0
|
|
|
|
|
0
|
my $pos = vec( $state, 4 + $col_idx, 4 ); |
|
78
|
|
|
|
|
|
|
|
|
79
|
0
|
0
|
|
|
|
0
|
if ($pos) |
|
80
|
|
|
|
|
|
|
{ |
|
81
|
0
|
|
|
|
|
0
|
$no_cards = 0; |
|
82
|
0
|
|
|
|
|
0
|
last COL; |
|
83
|
|
|
|
|
|
|
} |
|
84
|
|
|
|
|
|
|
} |
|
85
|
|
|
|
|
|
|
} |
|
86
|
|
|
|
|
|
|
|
|
87
|
953
|
100
|
|
|
|
1821
|
if ($no_cards) |
|
88
|
|
|
|
|
|
|
{ |
|
89
|
1
|
|
|
|
|
32
|
$self->_trace_solution( $state, ); |
|
90
|
1
|
|
|
|
|
2
|
$verdict = 1; |
|
91
|
1
|
|
|
|
|
2
|
last QUEUE_LOOP; |
|
92
|
|
|
|
|
|
|
} |
|
93
|
|
|
|
|
|
|
|
|
94
|
952
|
100
|
|
|
|
1658
|
if ( $tln < @talon_values ) |
|
95
|
|
|
|
|
|
|
{ |
|
96
|
833
|
|
|
|
|
1178
|
my $next_s = $state; |
|
97
|
833
|
|
|
|
|
1630
|
vec( $next_s, 0, 8 ) = $talon_values[$tln]; |
|
98
|
833
|
|
|
|
|
1637
|
++vec( $next_s, 1, 8 ); |
|
99
|
833
|
100
|
|
|
|
1716
|
if ( !exists( $positions->{$next_s} ) ) |
|
100
|
|
|
|
|
|
|
{ |
|
101
|
586
|
|
|
|
|
1851
|
$positions->{$next_s} = |
|
102
|
|
|
|
|
|
|
[ $state, scalar(@$board_values), 1, 0 ]; |
|
103
|
586
|
|
|
|
|
1407
|
push @_pending, [ $next_s, 0 ]; |
|
104
|
|
|
|
|
|
|
} |
|
105
|
|
|
|
|
|
|
} |
|
106
|
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
# Give preference to non-talon moves |
|
108
|
952
|
|
|
|
|
1528
|
push @_pending, @sub_queue; |
|
109
|
|
|
|
|
|
|
last QUEUE_LOOP |
|
110
|
952
|
50
|
|
|
|
2050
|
if not $self->_process_pending_items( \@_pending, $state ); |
|
111
|
|
|
|
|
|
|
} |
|
112
|
|
|
|
|
|
|
|
|
113
|
1
|
|
|
|
|
9
|
return $self->_my_exit( $verdict, ); |
|
114
|
|
|
|
|
|
|
} |
|
115
|
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
1; |
|
118
|
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
__END__ |