_="H=64Oh=H/2,R=N=F=21,DYa<2?0:3*--a+D_L=[],BYR+9*a+&&D)_g=Ol^d,e,,beginQmova,bQEd,eQf&&(EQEQclose)QZ(QX(_VJ,eYe=N=[Gc*e,Gb*e][2#46#0`[7#53#1`},wJl(v[aUaUbUbUcUcUdUd]_A=j{[r*N+C]with(v=V(f,.concat(V(f,QM)Z~xa('+[gz18W(g2z(g+24z.85*f/(F)]+')';k=(N)/2,r<(6!4Qqr==(qr>(O2O8Qq8O124)}};L[F]=OsetInterval(j$g=(g+7)%36Ox(1O5O1',XRect(OOH,HQL.pop(I=[]Qi=N*N;i--;)I.push(M.random()>.98);$L.unshift(IQff<F;f=L[f])$n=N,II;I$ii-I;iC@I,CKI,CKQr@IKIK_8qC<2!0QC>O64,8)Qjfunction(z*PI/18)+.5|OxX~'rgbQ),W0+37*(cos(ElinYreturn U],v[O0,Gh-2+J^cKn-ZstrokeXfill!,42@=I+i,A(#]=d[$for(^,b,_)},~Style=`])+ek&&C)+1B)/]=(d[P(n-II,n-C,1c.0)QA(=ja=0;w(++)){atheTo(-1<N/2if(Sr,,d(af,gh,i12W";for(Y=0;$="`~_^$#@!XZKJGOUYEWQxzjq"[Y++];)with(_.split($))_=join(pop());eval(_)
/*
<html>
<head>
<meta charset='UTF-8'>
<title>3d-tetris</title>
</head>
<body bgcolor=black>
<canvas id='z' width='640' height='640'></canvas>
<script src='tetris.js'></script>
</body>
</html>
*/
var // (drop all 'let' after compress)
H = 640, // width === height : {640 x 640}
h = H / 2,
c = z.getContext('2d'), // (drop before submit on js1k)
R = // first floor radius
N = // count of L on OX and OY
F = 21, // count of floors
/**
* Sum of floor diff's
* 3 - diff height between near floor (floor height increment)
* @param a floor
*/
D = function(a) { return a < 2 ? 0 : --a * 3 + D(a) },
L = [], // list of floors cubes
/**
* Width/height of floor 'f'
* "B(f) / N" - Width/height of cube on floor 'f'
* 9 - first floor height
* @param a floor
*/
B = function(a) { return R + a * 9 + (a && D(a)) },
// local variables (drop after compress)
I = // loop index
i = // loop index
f = // floor index
r = // row index
C = // column index
o = // color of cubes in each iteration
v = // vertexes of cube during cube rendering
S = // list of cubes on rendering floor
g = 0, // g of color rotate, 0..359
/**
* Draw line {a,b} -> {c,d}
* or area {a,b} -> {c,d} -> {e,f} -> {g,h} if 'e' exists
*/
l = function(a, b, C, d, e, f, g, h) {
// begin line
c.beginPath();
c.moveTo(a, b);
c.lineTo(C, d);
// draw +2 lines of area if need
e && (
c.lineTo(e, f),
c.lineTo(g, h),
c.closePath()
)
// close path and fill if need
c.stroke();
c.fill();
},
/**
* Vertexes of cubes floor
* Return array of {x,y}
* 0,1 --- 2,3
* | |
* | |
* 6,7 --- 4,5
*/
V = function(f, r, c, a, b) {
b = B(f) / N,
a = [
h - B(f) / 2 + c * b,
h - B(f) / 2 + r * b
];
a[2] = a[4] = (a[6] = a[0]) + b;
a[7] = a[5] = (a[3] = a[1]) + b;
return a;
},
// render shortcut; args is indexes of vertexes of render area (index of y = x + 1)
w = function(a, b, c, d) {
l(v[a], v[a + 1], v[b], v[b + 1], v[c], v[c + 1], v[d], v[d + 1]);
},
// check and draw cube
A = function(r, C) {
// draw cube if it exists
if (S[r * N + C]) {
/**
* Vertexes of cube (by floor-number, row-number and column-number)
* Floor first. Then roof.
*
* Top-view:
*
* 8,9 --------------- 10,11
* | \ /|
* | 0,1 ------- 2,3 |
* | | | |
* | | floor | |
* | | | |
* | 6,7 ------- 4,5 |
* | / \ |
* 14,15 ------------- 12,13
*/
v = V(f, r, C).concat(V(f + 1, r, C));
/**
* Color of current iteration
*
* red-vector = 'g' + 0 degree
* green-vector = 'g' + 120 degree
* blue-vector = 'g' + 240 degree
*
* color-value:
* get cos(color-vector) = -1 .. +1
* then +1 = 0 .. +2
* then /2 = 0 .. +1
* then *74 = 0 .. 74
* then +minValue = true color value in {minValue, 255}
* "/ 2 * 74" === "* 37"
*
* Math.round(x) === x + .5 | 0
*/
with (Math)
c.strokeStyle =
c.fillStyle = 'rgba(' + [
// red
120 + (cos(g * PI / 180) + 1) * 37 + .5 | 0,
// green
180 + (cos((g + 120) * PI / 180) + 1) * 37 + .5 | 0,
// blue
120 + (cos((g + 240) * PI / 180) + 1) * 37 + .5 | 0,
// alpha = floor * maxAlpha / visibleFloors
f * .85 / (F - 1)
] + ')';
// for check cube-position on floor
k = (N - 1) / 2;
// top lines
if (r < k) {
w(6, 4, 12, 14); // front edge
C < k && w(2, 4, 12, 10); // right edge
C > k && w(0, 6, 14, 8); // left edge
}
// center line
if (r == k) {
C < k && w(2, 4, 12, 10); // right edge
C > k && w(0, 6, 14, 8); // left edge
}
// bottom lines
if (r > k) {
w(0, 2, 10, 8); // back edge
C < k && w(2, 4, 12, 10); // right edge
C > k && w(0, 6, 14, 8); // left edge
}
w(8, 10, 12, 14); // roof
}
};
L[F - 1] = 0; // init empty array cubes
setInterval(function() {
g = (g + 7) % 360; // rotate color-vector again
// reset, fill background
c.fillStyle = 'rgb(10,50,10)';
c.fillRect(0, 0, H/*W*/, H);
// floors
// for (f = 0; f < F; f++) {
// // alpha = floor * maxAlpha / visibleFloors
// c.strokeStyle = 'rgba(180,220,180,' + f * .5 / (F - 1) + ')';
// c.strokeRect(
// h - B(f) / 2,
// h - B(f) / 2,
// B(f),
// B(f)
// );
// }
// lines of walls
// c.strokeStyle = 'rgba(180,220,180,.1)';
// for (i = 0, I = B(F - 1) / N, k = B(F - 1) / 2; i < N; i++) {
// // top
// l(
// X = h - k + i * I,
// Y = h - k,
// x = h - R / 2 + i * (R / N),
// y = h - R / 2
// );
// // bottom (отражение координат top'а по диагонали)
// // от центра (симметрии) откладываем вправо столько же, на сколько верхняя точка лежит левее центра
// // bottom.x = C.x + (C.x - top.x)
// // => 2 * C.x - top.x
// // => width - top.x
// l(
// H - X, // W - X, but W === H
// H - Y,
// H - x, // W - x
// H - y
// );
// // right (поворот top'а на 90 по часовой)
// // от центра отложить вправо столько, на сколько точка лежит выше центра
// // right.x = C.x + (C.y - top.y)
// // C.x + C.y = h + h = H
// l(
// H - Y,
// h - k + i * I,
// H - y,
// h - R / 2 + i * (R / N)
// );
// // left
// // h - h + Y = 0 + Y = Y
// l(
// Y,
// H - X,
// y,
// H - x
// );
// }
// move cubes!
L.pop(I = []);
for (i = N * N; i--;)
I.push(Math.random() > .98);
L.unshift(I);
for (f = 0; f < F - 1; f++) {
if (S = L[f]) {
n = N - 1;
/**
* Порядок рендера кубов.
*
* Номер в клетке - удалённость клетки от угла.
* Равен числу 'шагов' от угла, за которые можно достичь клетки.
* Равен сумме индексов строки и столбца.
*
* N: 0: 1: 2:
* 0: | 0 | 1 | 2 |
* 1: | 1 | 2 | 3 |
* 2: | 2 | 3 | 4 |
*/
// ползём от края к центру
for (I = 0; I < N / 2; I++) {
// на каждом уровне погружения ползём из угла вправо и вниз до середины
for (i = 0; i < N / 2 - I; i++) {
// .. вправо
// r = I;
C = I + i;
A(I, C);
// отражения
A(I, n - C); // вправо
A(n - I, C); // вниз
A(n - I, n - C); // по диагонали
// .. вниз
r = I + i;
// C = I;
A(r, I);
// отражения
A(r, n - I); // вправо
A(n - r, I); // вниз
A(n - r, n - I); // по диагонали
}
}
}
}
}, 80)