)
}
}
)
(
}
{
)
)
(
)
(
(
{
}
)
(
)
}
)
)
{
(
(
)
)
}
)
(
}

2x mod 1 Map

  1. function twoXmodMap(start = 0.2) {
  2.   const seed = () => Math.random() * Math.random() * start
  3.   let xn = seed()
  4.   let xn1
  5.   let iter = 0
  6.   return () => {
  7.     iter++
  8.     if (iter > 50) {
  9.       xn = seed()
  10.       iter = 0
  11.     }
  12.  
  13.     // this is the key part:
  14.     xn1 = (2 * xn) % 1
  15.     xn = xn1
  16.  
  17.     return xn1
  18.   }
  19. }
  20.  
  21. const el = document.body.appendChild(document.createElement('div'))
  22. el.innerHTML = `
  23.   <svg>
  24.     <path d="M 0 0 L 1 1" fill="none" stroke="red" />
  25.   </svg>
  26.   <style>
  27.     svg, body, html {
  28.       width: 100%;
  29.       height: 100%;
  30.       overflow: visible;
  31.     }
  32.   </style>
  33. `
  34.  
  35. const path = el.querySelector('path')
  36. let pathStr = ''
  37.  
  38. const map = twoXmodMap()
  39.  
  40. let x = 0
  41. let yo = 0
  42. let y;
  43. function loop() {
  44.   y = map()
  45.   x += 2
  46.  
  47.   if (pathStr == '' || x > 300) {
  48.     x = 10
  49.     yo += 50
  50.     pathStr += `M 10 ${yo}`
  51.   } else {
  52.     pathStr += ` L ${x} ${yo + y * 30} `
  53.   }
  54.  
  55.   path.setAttribute('d', pathStr)
  56.   window.requestAnimationFrame(loop)
  57. }
  58. loop()

Drawing the 2x mod 1 map.

// javascript // math // svg

Find a String Naive Hill Climbing

  1. const target = 'snippetzone'.split``;
  2. const leng = target.length;
  3. const alphabet = 'abcdefghijklmnopqrstuvwxyz'.split``;
  4.  
  5. function randomString() {
  6.   let str = [];
  7.   for (let i = 0; i < leng; i++) {
  8.     str.push(randomChar());
  9.   }
  10.   return str;
  11. }
  12.  
  13. function randomChar() {
  14.   return alphabet[Math.floor(Math.random() * alphabet.length)];
  15. }
  16.  
  17. let iterations = 0;
  18. const search = randomString();
  19. const indices = [];
  20. for (var i = 0; i < leng; i++) indices.push(i);
  21. let found = false;
  22.  
  23. function loop() {
  24.   for (let i = 0; i < 10; i++) {
  25.     if (indices.length > 0) {
  26.       let ii = Math.floor(Math.random() * indices.length);
  27.       let index = indices[ii];
  28.       search[index] = randomChar();
  29.       if (search[index] == target[index]) {
  30.         indices.splice(ii, 1);
  31.       }
  32.       console.log(search.join(','));
  33.       iterations++;
  34.     } else {
  35.       console.log('found after', iterations, 'iterations');
  36.       found = true;
  37.       break;
  38.     }
  39.   }
  40.  
  41.   if (!found) {
  42.     requestAnimationFrame(loop);
  43.   }
  44. }
  45. loop();

This is a port of an old snippet of mine. It naively and randomly finds a target string. In this case the string “snippetzone”.

It’s fun to see it randomly perform better/worse…

e,f,k,w,q,s,o,h,n,r,f e,f,k,w,q,s,o,h,n,r,u k,f,k,w,q,s,o,h,n,r,u k,f,k,w,q,o,o,h,n,r,u k,f,k,w,q,o,o,v,n,r,u k,f,k,w,q,v,o,v,n,r,u ... s,e,i,p,p,e,t,z,o,n,e s,v,i,p,p,e,t,z,o,n,e s,h,i,p,p,e,t,z,o,n,e s,d,i,p,p,e,t,z,o,n,e s,s,i,p,p,e,t,z,o,n,e s,e,i,p,p,e,t,z,o,n,e s,g,i,p,p,e,t,z,o,n,e s,q,i,p,p,e,t,z,o,n,e s,m,i,p,p,e,t,z,o,n,e s,w,i,p,p,e,t,z,o,n,e s,g,i,p,p,e,t,z,o,n,e s,x,i,p,p,e,t,z,o,n,e s,t,i,p,p,e,t,z,o,n,e s,o,i,p,p,e,t,z,o,n,e s,e,i,p,p,e,t,z,o,n,e s,k,i,p,p,e,t,z,o,n,e s,p,i,p,p,e,t,z,o,n,e s,b,i,p,p,e,t,z,o,n,e s,n,i,p,p,e,t,z,o,n,e found after 176 iterations

Fast Sine and Cosine Approximation

  1. let t = 0, cos, sin, x, y;
  2.  
  3. const PI = Math.PI;
  4. const TWO_PI = PI * 2;
  5. const HALF_PI = PI / 2;
  6. const tA = 4 / PI;
  7. const tB = 4 / PI ** 2;
  8.  
  9. const canvas = document.body.appendChild(document.createElement('canvas'));
  10. const c = canvas.getContext('2d');
  11. canvas.width = canvas.height = 300;
  12.  
  13. function loop() {
  14.   // low precision sine/cosine
  15.   // always wrap input angle to -PI..PI
  16.   t += 0.1;
  17.   if (t < -PI) {
  18.     t += TWO_PI;
  19.   } else if (t > PI) {
  20.     t -= TWO_PI;
  21.   }
  22.  
  23.   // compute sine
  24.   if (t < 0) {
  25.     sin = tA * t + tB * t * t;
  26.   } else {
  27.     sin = tA * t - tB * t * t;
  28.   }
  29.  
  30.   // compute cosine: sin(t + PI/2) = cos(t)
  31.   t += HALF_PI;
  32.   if (t > PI) {
  33.     t -= TWO_PI;
  34.   }
  35.  
  36.   if (t < 0) {
  37.     cos = tA * t + tB * t * t;
  38.   } else {
  39.     cos = tA * t - tB * t * t;
  40.   }
  41.  
  42.   t -= HALF_PI; // move the shape
  43.  
  44.   x = 110 + 100 * cos;
  45.   y = 110 + 100 * sin;
  46.  
  47.   c.fillStyle = 'rgba(100, 100, 20, .5)';
  48.   c.fillRect(x, y, 10, 10);
  49.   window.requestAnimationFrame(loop);
  50. }
  51. loop();

This is an old trick for fast sine/cosine approximation. I learned about it from Michael Baczynski’s blog which now seems to be down. Here is a wayback link for the original article and another one to a more in-depth discussion about it:
original post
original thread

It’s unlikely that the speed gain (if there even is one here) makes sense in javascript. This is really more for fun… a quick search will turn up all kinds of cool info about fast sine/cosine stuff.

isPowerOfTwo

  1. function isPowerOfTwo(value) {
  2.   return (value & (value - 1)) === 0 && value !== 0;
  3. }
  4.  
  5. for (let i = 0; i < 66; i++) {
  6.   console.log(i, isPowerOfTwo(i));
  7. }

I’ve had the pleasure of using THREE.js quite a bit over the years. The MathUtils file has some great utility functions. This version of isPowerOfTwo comes straight from there. I may post a few more from there in the future…

Lerp

  1. const lerp = (a, b, t) => a + (b - a) * t;
  2.  
  3. console.log(lerp(0, 100, 0.5));
  4. console.log(lerp(0, 100, 0.1));
  5.  
  6. console.log(lerp(50, 100, 0.5));
  7. console.log(lerp(100, 50, 0.5));
  8.  
  9. const c = document.body.appendChild(document.createElement`canvas`)
  10.   .getContext`2d`;
  11. c.canvas.width = c.canvas.height = 100;
  12. c.fillStyle = 'black';
  13. c.fillRect(0, 0, 100, 100);
  14.  
  15. let time = 0;
  16. const loop = () => {
  17.   c.fillStyle = 'rgba(255, 255, 255, .5)';
  18.  
  19.   time += 0.01;
  20.  
  21.   if (time < 1) {
  22.     c.fillRect(lerp(10, 55, time), lerp(10, 90, time), 5, 5);
  23.   }
  24.   window.requestAnimationFrame(loop);
  25. };
  26. loop();
snippet.zone ~ 2021-24 /// {s/z}