-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsnakesolver.pl
More file actions
executable file
·120 lines (93 loc) · 3.18 KB
/
snakesolver.pl
File metadata and controls
executable file
·120 lines (93 loc) · 3.18 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
#!perl6
use v6;
sub dont(&) {}
my $dim=4;
my @snake_short=<5 1 1 2 1 1 1 6 1 1 2 2 4 2 3 4 3 5 5 2 2 4 2 2 2>;
# my @snake_short=<7 1 1 2 1 1 1 6 1 1 2 2 4 2 3 4 3 5 5 2 2 4 2 2>;
# my @snake_short=<2 4 2 2 4 4 4 2 2 4 1 1 4 2 2 4 4 4 2 2 4 3 1>;
my $dimm1= $dim - 1;
my $dimp1= $dim + 1;
my $dimp2= $dim + 2;
my $dimp2sq= $dimp2 * $dimp2;
my $slen= $dim * $dim * $dim;
my $color= 2;
my @snake= @snake_short.map({ my $c= $color= 3 - $color; (^$_).map({ $c }); });
die "snake length is not $slen!" if $slen != @snake.elems;
die "snake length is uneven!" if @snake.elems ~& 1;
sub xyz2n($x, $y, $z) { $z * $dimp2sq + $y * $dimp2 + $x };
sub n2x($n) { $n % $dimp2 };
sub n2y($n) { ($n div $dimp2) % $dimp2 };
sub n2z($n) { ($n div $dimp2sq) % $dimp2 };
sub getCube( @result ) {
(1..$dim).map(sub ($z) {
# z
"\nz=$z\n" ~ (^$dimp1).map(sub ($y) {
# y
if $y == 0 || $y == $dimp1 {
return "\t+----+----+----+----+\t+---+---+---+---+\n";
}
else {
return "\t|" ~ (1..$dim).map(sub ($x) {
# x
my $n= xyz2n($x, $y, $z);
sprintf " %2d |", @result[$n];
}).join('') ~ "\t|" ~ (1..$dim).map(sub ($x) {
# x
my $n= xyz2n($x, $y, $z);
if @snake[@result[$n]] == 2 {
" X |";
}
else {
" |";
}
}).join('') ~ "\n\t+----+----+----+----+\t+---+---+---+---+\n";
}
});
});
};
my @result;
my @expected;
# prepare an empty cube with borders (@result) and define color of visible fronts (@expected)
for ^$dimp2 -> $x {
for ^$dimp2 -> $y {
for ^$dimp2 -> $z {
my $n= xyz2n($x, $y, $z);
if ($x, $y, $z).grep({ $_ == 0 || $_ == $dimp1 }) {
# we are in outer space
@result[$n]= -1;
next;
}
if ($x, $y, $z).grep({ $_ == 1 || $_ == $dim }) {
# we are at the surface
@expected[$n]= ([+] ($x, $y, $z).map({ ($_ + 3) div 2 })) % 2 + 1;
next;
}
}
}
}
my $try= 0;
sub solve($n, $idx, @currentState is copy) {
# return if new position is occupated already
return if @currentState[$n];
# return if special color is required but does not match
return if @expected[$n] && @expected[$n] != @snake[$idx];
@currentState[$n]= $idx;
$try++;
print "\r$try (" ~ n2x($n) ~ "," ~ n2y($n) ~ "," ~ n2z($n) ~ ") -> $idx: " ~ @snake[$idx] unless $try % 300;
# we have solved it that way
solved(@currentState) if $idx === @snake.elems;
return (1, -1, $dimp2, -$dimp2, $dimp2sq, -$dimp2sq).map({ $n + $_ }).grep({ !@currentState[$_] }).map({ [$_, $idx + 1, [@currentState]] });
}
sub solved( @result ) {
say "SOLVED! in $try tries";
say getCube(@result);
}
for ^$slen {
say;
say "Starting over: $_";
my @queue= ([xyz2n(1, 1, 1), 0, [@result]], );
while @queue {
@queue.unshift(solve(|@queue.shift));
}
@snake.push(@snake.shift);
}