<pre id=p><script>n=setInterval("for(n+=7,i=k,P='p.\\n';i-=1/k;P+=P[i%2?(i%2*j-j+n/k^j)&1:2])j=k/i;p.innerHTML=P",k=64)</script>
code.js
file, and p
quoted in id="p"
. <script src="code.js"></script> <pre id="p"></pre>
k
is just a constant, so I removed it from the line and renamed delay
. var delay = 64; var draw = "for(n+=7,i=delay,P='p.\\n';i-=1/delay;P+=P[i%2?(i%2*j-j+n/delay^j)&1:2])j=delay/i;p.innerHTML=P"; var n = setInterval(draw, delay);
var draw
was just a string that was executed as a function of eval
at intervals of setInterval, because setInterval can take both functions and strings. I moved var draw
to an explicit function, but I saved the original line for reference just in case.p
element actually referred to the DOM element with the p
identifier declared in HTML, which I recently quoted. It turns out that elements in JavaScript can be referenced by their identifier, if id consists only of letters and numbers. I added document.getElementById("p")
to make the code clearer. var delay = 64; var p = document.getElementById("p"); // < -------------- // var draw = "for(n+=7,i=delay,P='p.\\n';i-=1/delay;P+=P[i%2?(i%2*j-j+n/delay^j)&1:2])j=delay/i;p.innerHTML=P"; var draw = function() { for (n += 7, i = delay, P = 'p.\n'; i -= 1 / delay; P += P[i % 2 ? (i % 2 * j - j + n / delay ^ j) & 1 : 2]) { j = delay / i; p.innerHTML = P; } }; var n = setInterval(draw, delay);
i
, p
and j
and transferred them to the beginning of the function. var delay = 64; var p = document.getElementById("p"); // var draw = "for(n+=7,i=delay,P='p.\\n';i-=1/delay;P+=P[i%2?(i%2*j-j+n/delay^j)&1:2])j=delay/i;p.innerHTML=P"; var draw = function() { var i = delay; // < --------------- var P ='p.\n'; var j; for (n += 7; i > 0 ;P += P[i % 2 ? (i % 2 * j - j + n / delay ^ j) & 1 : 2]) { j = delay / i; p.innerHTML = P; i -= 1 / delay; } }; var n = setInterval(draw, delay);
for
loop and converted it into a while
. Of the three parts of the former for
, only one part of the CHECK_EVERY_LOOP remained, and the rest (RUNS_ONCE_ON_INIT; DO_EVERY_LOOP) moved beyond the cycle. var delay = 64; var p = document.getElementById("p"); // var draw = "for(n+=7,i=delay,P='p.\\n';i-=1/delay;P+=P[i%2?(i%2*j-j+n/delay^j)&1:2])j=delay/i;p.innerHTML=P"; var draw = function() { var i = delay; var P ='p.\n'; var j; n += 7; while (i > 0) { // <---------------------- //Update HTML p.innerHTML = P; j = delay / i; i -= 1 / delay; P += P[i % 2 ? (i % 2 * j - j + n / delay ^ j) & 1 : 2]; } }; var n = setInterval(draw, delay);
( condition ? do if true : do if false) in P += P[i % 2 ? (i % 2 * j - j + n / delay ^ j) & 1 : 2];
( condition ? do if true : do if false) in P += P[i % 2 ? (i % 2 * j - j + n / delay ^ j) & 1 : 2];
.i%2
checks if the variable i
even or odd. If it is even, then it simply returns 2. If it is odd, then it returns the magic value magic (i % 2 * j - j + n / delay ^ j) & 1;
(more on this later).index
and turn the string into P += P[index];
. var delay = 64; var p = document.getElementById("p"); // var draw = "for(n+=7,i=delay,P='p.\\n';i-=1/delay;P+=P[i%2?(i%2*j-j+n/delay^j)&1:2])j=delay/i;p.innerHTML=P"; var draw = function() { var i = delay; var P ='p.\n'; var j; n += 7; while (i > 0) { //Update HTML p.innerHTML = P; j = delay / i; i -= 1 / delay; let index; let iIsOdd = (i % 2 != 0); // <--------------- if (iIsOdd) { // <--------------- index = (i % 2 * j - j + n / delay ^ j) & 1; } else { index = 2; } P += P[index]; } }; var n = setInterval(draw, delay);
& 1
from the value index = (i % 2 * j - j + n / delay ^ j) & 1
into another if
.&
is a bitwise AND operator. It works like this:something & 1
converts the "something" into a binary representation, and also finishes the required number of zeros before the unit to match the size of the "something", and returns just the AND result of the last bit. For example, 5 in binary format equals 101
, so if we apply the logical AND operation with a unit on it, we get the following: 101 AND 001 001
0 & 1 // 0 - even return 0 1 & 1 // 1 - odd return 1 2 & 1 // 0 - even return 0 3 & 1 // 1 - odd return 1 4 & 1 // 0 - even return 0 5 & 1 // 1 - odd return 1
index
to magic
, so the code with the expanded &1
will look like this: var delay = 64; var p = document.getElementById("p"); // var draw = "for(n+=7,i=delay,P='p.\\n';i-=1/delay;P+=P[i%2?(i%2*j-j+n/delay^j)&1:2])j=delay/i;p.innerHTML=P"; var draw = function() { var i = delay; var P ='p.\n'; var j; n += 7; while (i > 0) { //Update HTML p.innerHTML = P; j = delay / i; i -= 1 / delay; let index; let iIsOdd = (i % 2 != 0); if (iIsOdd) { let magic = (i % 2 * j - j + n / delay ^ j); let magicIsOdd = (magic % 2 != 0); // &1 < -------------------------- if (magicIsOdd) { // &1 <-------------------------- index = 1; } else { index = 0; } } else { index = 2; } P += P[index]; } }; var n = setInterval(draw, delay);
P += P[index];
in the switch
. At this point, it became clear that index
can take only one of three values βββ 0, 1, or 2. It is also clear that the variable P
always initialized with the values var P ='p.\n';
where 0 points to p
, 1 points to .
, and 2 points to a \n
newline character var delay = 64; var p = document.getElementById("p"); // var draw = "for(n+=7,i=delay,P='p.\\n';i-=1/delay;P+=P[i%2?(i%2*j-j+n/delay^j)&1:2])j=delay/i;p.innerHTML=P"; var draw = function() { var i = delay; var P ='p.\n'; var j; n += 7; while (i > 0) { //Update HTML p.innerHTML = P; j = delay / i; i -= 1 / delay; let index; let iIsOdd = (i % 2 != 0); if (iIsOdd) { let magic = (i % 2 * j - j + n / delay ^ j); let magicIsOdd = (magic % 2 != 0); // &1 if (magicIsOdd) { // &1 index = 1; } else { index = 0; } } else { index = 2; } switch (index) { // P += P[index]; <----------------------- case 0: P += "p"; // aka P[0] break; case 1: P += "."; // aka P[1] break; case 2: P += "\n"; // aka P[2] } } }; var n = setInterval(draw, delay);
var n = setInterval(draw, delay);
. The setInterval method returns integers starting from one, increasing the value with each call. This integer can be used for clearInterval (that is, for undo). In our case, setInterval is called only once, and the variable n
simply set to 1.delay
to DELAY
to remind you that this is just a constant.i % 2 * j - j + n / DELAY ^ j
to indicate that y ^
(bitwise XOR) is lower priority than the %
, *
, β
, +
and /
. In other words, all the above calculations will be performed first, and only then ^
. That is, it turns out (i % 2 * j - j + n / DELAY) ^ j)
.p.innerHTML = P; //Update HTML
p.innerHTML = P; //Update HTML
into a loop, so I removed it from there. const DELAY = 64; // approximately 15 frames per second 15 frames per second * 64 seconds = 960 frames var n = 1; var p = document.getElementById("p"); // var draw = "for(n+=7,i=delay,P='p.\\n';i-=1/delay;P+=P[i%2?(i%2*j-j+n/delay^j)&1:2])j=delay/i;p.innerHTML=P"; /** * Draws a picture * 128 chars by 32 chars = total 4096 chars */ var draw = function() { var i = DELAY; // 64 var P ='p.\n'; // First line, reference for chars to use var j; n += 7; while (i > 0) { j = DELAY / i; i -= 1 / DELAY; let index; let iIsOdd = (i % 2 != 0); if (iIsOdd) { let magic = ((i % 2 * j - j + n / DELAY) ^ j); // < ------------------ let magicIsOdd = (magic % 2 != 0); // &1 if (magicIsOdd) { // &1 index = 1; } else { index = 0; } } else { index = 2; } switch (index) { // P += P[index]; case 0: P += "p"; // aka P[0] break; case 1: P += "."; // aka P[1] break; case 2: P += "\n"; // aka P[2] } } //Update HTML p.innerHTML = P; }; setInterval(draw, 64);
i
set to 64 by means of var i = DELAY;
and then each cycle it decreases by 1/64 (0.016625) through i -= 1 / DELAY;
. The loop continues until i
greater than zero ( while (i > 0) {
code while (i > 0) {
). Since for each pass i
decreases by 1/64, it takes 64 cycles before it decreases by one (64/64 = 1). In general, a decrease in i
will occur 64 Γ 64 = 4096 times in order to decrease to zero.i
can be even (not odd let iIsOdd = (i % 2 != 0);
) if i
is strictly an even number. This will happen 32 times when it equals 64, 62, 60, etc. These 32 times the index
will take the value 2 index = 2;
, and a new line character will be added to the line: P += "\n"; // aka P[2]
P += "\n"; // aka P[2]
. The remaining 127 characters in the string will take the values p
or .
.p
, and when .
?.
for odd values, let magic = ((i % 2 * j - j + n / DELAY) ^ j);
, or set p
if "magic" is even. var P ='p.\n'; ... if (magicIsOdd) { // &1 index = 1; // second char in P - . } else { index = 0; // first char in P - p }
magic
even and when is odd? This is a million dollar question. Before moving on to it, let's define something else.+ n/DELAY
from let magic = ((i % 2 * j - j + n / DELAY) ^ j);
, you get a static picture in which nothing moves at all:magic
without + n/DELAY
. How did this beautiful picture come about?(i % 2 * j - j) ^ j
j = DELAY / i; i -= 1 / DELAY;
j
through finite i
as j = DELAY/ (i + 1/DELAY)
. But since 1 / DELAY is too small a number, for this example you can drop + 1/DELAY
and simplify the expression to j = DELAY/i = 64/i
.(i % 2 * j - j) ^ j
as i % 2 * 64/i - 64/i) ^ 64/i
.i%2
.64/i
, we get the following graph:(i % 2 * j - j) ^ j
takes an even value, then you need to add p
, and for an odd number you need to add .
.i
has values ββfrom 64 to 32.Math.floor
method, which rounds the number down.j
starts from one and slowly moves to a two, stopping right next to it, so we can always consider it as a unit when rounding down ( Math.floor(1.9999) === 1
), and we need one more unit on the left side to get a result of zero and give us p
.(i % 2 * j - j) ^ j
, it is i % 2 * i/64 β i/64
, that is, the green diagonal, will also be higher than 1 or lower than β1. 1 ^ 1 // 0 - even p 1.1 ^ 1.1 // 0 - even p 0.9 ^ 1 // 1 - odd . 0 ^ 1 // 1 - odd . -1 ^ 1 // -2 - even p -1.1 ^ 1.1 // -2 - even p
p
characters). The next one goes a little further beyond these boundaries, the third one goes a little further, and so on. Line number 16 is barely held between 2 and β2. After line 16, we see that our static graph changes its character.j
crosses the limit 2, so that the expected result changes. Now we will get an even number if the green diagonal line is higher than 2 or lower than β2, or inside frames 1 and β1, but does not touch them. That is why we see in the picture two or more groups of p
characters starting from the 17th line.+ n/DELAY
. In the code, we see that the value of n
begins with 8 (1 from setInteval and plus 7 on each method call). It then increases by 7 each time setInteval is triggered.j
is still around one, but now the left half of the red diagonal is around 62-63, around about zero, and the right half is around 63-64 around one. Since our characters appear in descending order from 64 to 62, we can expect that the right half of the diagonal in the region of 63-64 (1 ^ 1 = 0 // even) will add a handful of characters p
, and the left half of the diagonal in the region of 62-63 ( 1 ^ 0 = 1 // odd) will add a bunch of points. All this will grow from left to right, as usual text.n
in the CodePen editor and see). This coincides with our expectations.p
has grown to a constant value. For example, in the first row, half of all values ββwill always be even. Now the characters p
and .
will only change places.n
incremented by 7 on the next call to setInterval, the graph changes slightly.n
equals 64 + 9 Γ 7.j
is still equal to 1. Now the upper half of the red diagonal near the 64 mark abutted approximately into two, and the lower end near the unit. This turns the picture in the other direction, since now 1^2 = 3 // odd - .
and 1 ^ 1 = 0 //even - p
. So you can expect a bunch of points, followed by the characters p
.Source: https://habr.com/ru/post/333372/
All Articles