/
generate-board
165 lines (146 loc) · 5.14 KB
/
generate-board
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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
use v6;
use Num :Trig;
sub header {
'<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns="http://www.w3.org/2000/svg"
width="500"
height="500">
'
}
sub polygon($id, $color, @coords) {
qq[ <path
id="$id"
style="fill:$color;stroke:none"
d="] ~ pathspec(@coords) ~ '" />
'
}
sub pathspec(@coords) {
die "Need an even number of coords, got {+@coords}"
if @coords % 2;
return [~]
'M ',
(join ' L ', map -> $x, $y { sprintf '%.3f,%.3f', $x, $y }, @coords),
' z';
}
sub footer {
'</svg>
'
}
sub project(@coords3d, $camera-distance) {
die "Number of coords must be multiple of 3, got {+@coords3d}"
if @coords3d % 3;
return map -> $x,$y,$z {
my $t = $camera-distance / ($camera-distance - $z);
$x*$t, $y*$t
}, @coords3d;
}
sub translate(@coords, $dx, $dy) {
return map -> $x,$y { $x+$dx, $y+$dy }, @coords;
}
sub scale(@coords, $fx, $fy = $fx) {
return map -> $x,$y { $x*$fx, $y*$fx }, @coords;
}
sub rot-x(@coords3d, $deg) {
my $rad = $deg * pi / 180;
return map -> $x,$y,$z {
$x, $y*cos($rad)-$z*sin($rad), $y*sin($rad)+$z*cos($rad)
}, @coords3d;
}
sub rot-z(@coords3d, $deg) {
my $rad = $deg * pi / 180;
return map -> $x,$y,$z {
$x*cos($rad)-$y*sin($rad), $x*sin($rad)+$y*cos($rad), $z
}, @coords3d;
}
sub translate3d(@coords3d, $dx, $dy, $dz) {
die "Number of coords must be multiple of 3, got {+@coords3d}"
if @coords3d % 3;
return map -> $x,$y,$z { $x+$dx, $y+$dy, $z+$dz }, @coords3d;
}
sub block($name, $color, @one-corner, @other-corner) {
my ($x1,$y1,$z1) = @one-corner;
my ($x2,$y2,$z2) = @other-corner;
my $c = $color.substr(1);
my $brighter-color = [~] '#', map { sprintf '%x', :16($_)+3 }, $c.comb;
my $darker-color = [~] '#', map { sprintf '%x', :16($_)-3 }, $c.comb;
# RAKUDO: Multi-arg return
return [
$name~'-ns', $darker-color,
[$x1,$y2,$z1, $x1,$y2,$z2, $x2,$y2,$z2, $x2,$y2,$z1],
$name~'-ew', $color,
[$x1,$y1,$z1, $x1,$y1,$z2, $x1,$y2,$z2, $x1,$y2,$z1],
$name~'-top', $brighter-color,
[$x1,$y1,$z2, $x1,$y2,$z2, $x2,$y2,$z2, $x2,$y1,$z2],
].list;
}
sub board {
return block('board', '#999999', [0,0,-.25], [8,8,0]);
}
sub piece($color, $row, $column, $height) {
state $n = 0;
return block("piece{++$n}",
($color eq 'black' ?? '#553333' !! '#aaaacc'),
[$column-1,8-$row,$height-1],
[$column, 9-$row,$height ]);
}
sub rotate-widget {
' <script type="text/ecmascript"> <![CDATA[
function rotate(evt) {
var arrow = evt.target;
document.getElementById("board-top").setAttribute("d", "M 83.647,217.186 L 171.448,412.607 L 439.538,308.781 L 304.701,153.729 z");
}
]]> </script>
<path
d="M 365,406 L 365,441 C 365,448 393,454 427,454 C 461,454 489,448 489,441 L 489,406 C 486,414 460,420 427,420 C 393,420 365,414 365,406 z"
style="fill:none;stroke:#000000" />
<path
d="M 408,388 C 406,399 405,414 405,430 C 405,446 406,475 408,485 C 414,486 419,486 425,486 C 432,486 439,486 445,485 C 447,474 449,446 449,430 C 449,414 447,399 445,388 C 437,388 433,389 427,389 C 420,389 414,388 408,388 z"
style="fill:none;stroke:#000000" />
<path
onclick="rotate(evt)"
d="M 454,427 L 470,427 L 470,421 L 483,433 L 470,445 L 470,439 L 454,439 L 454,427 z"
style="fill:#ffffff;stroke:#000000;stroke-width:0.5px" />
<path
onclick="rotate(evt)"
d="M 399,428 L 383,428 L 383,422 L 370,434 L 383,446 L 383,440 L 399,440 L 399,428 z"
style="fill:#ffffff;stroke:#000000;stroke-width:0.5px" />
<path
onclick="rotate(evt)"
d="M 421,418 L 421,402 L 415,402 L 427,389 L 439,402 L 433,402 L 433,418 L 421,418 z"
style="fill:#ffffff;stroke:#000000;stroke-width:0.5px" />
<path
onclick="rotate(evt)"
d="M 422,455 L 422,471 L 416,471 L 428,485 L 439,471 L 433,471 L 433,455 L 422,455 z"
style="fill:#ffffff;stroke:#000000;stroke-width:0.5px" />
'
}
my @heights = map { [ map { 0 }, ^8 ] }, ^8;
my @pieces = map {
[
<black white>.pick()[0],
(my $row = (1..8).pick()[0]),
(my $column = (1..8).pick()[0]),
++@heights[$row-1][$column-1]
]
}, ^25;
@pieces.=sort: -> $p1, $p2 {
my ($c1, $ro1, $co1, $h1, $c2, $ro2, $co2, $h2) = $p1.list, $p2.list;
my ($x1, $y1, $z1, $x2, $y2, $z2)
= $co1-.5, 8.5-$ro1, $h1-.5, $co2-.5, 8.5-$ro2, $h2-.5;
my @center-board = translate3d([$x1,$y1,$z1,$x2,$y2,$z2], -4, -4, 0);
my @rotated-coords3d = rot-x(rot-z(@center-board, -25), 45);
$h1 <=> $h2 || .[2] <=> .[5] given @rotated-coords3d;
};
print header;
for board() -> $id, $color, @coords3d {
my @center-board = translate3d(@coords3d, -4, -4, 0);
my @rotated-coords3d = rot-x(rot-z(@center-board, -25), 45);
my @move-board-back = translate3d(@rotated-coords3d, 0, 0, -20);
my @projected-coords = project(@move-board-back, 1);
my @scaled-coords = scale(@projected-coords, 700);
my @coords2d = translate(@scaled-coords, 250, 250);
print polygon($id, $color, @coords2d);
}
print rotate-widget;
print footer;