0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

テレビの中の砂嵐

Last updated at Posted at 2025-05-03

シードあり乱数が欲しかっただけなのですが、アルゴリズムを幾つか実装する序でに砂嵐画面にしてみた。砂嵐は表示領域4x4倍分の一部を切り出す、なんちゃって方式です。毎回生成している訳ではありません。画像のクリックで更新の切り替えです。

See the Pen テレビの中の砂嵐 by Ikiuo (@ikiuo) on CodePen.

sample.html
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <title>テレビの中の砂嵐</title>
  </head>
  <body>
    <table>
      <tr><th>MT19937</th><td> <canvas id="tagMT19937"></canvas></td></tr>
      <tr><th>XorShift<br>32Bit</th><td><canvas id="tagXorShift32"></canvas></td></tr>
      <tr><th>LCG<br>64Bit</th><td><canvas id="tagLCG64"></canvas></td></tr>
      <tr><th>LCG<br>32Bit</th><td><canvas id="tagLCG32"></canvas></td></tr>
    </table>

    <script>

     function seed32(seed) {
         while (!seed)
             seed = (Math.random() * 4294967296) >>> 0;
         return seed;
     }

     /*
      * メルセンヌツイスタ
      */

     class MT19937 {
         constructor(seed = 5489) {
             seed = seed >>> 0;

             const state = new Uint32Array(624);
             state[0] = seed;
             for (let i = 1; i < 624; i++) {
                 const x = (seed ^ (seed >>> 30)) >>> 0;
                 const y = (BigInt(x) * 0x6c078965n) & 0xffffffffn;
                 state[i] = seed = (Number(y) + i) >>> 0;
             }
             this.state = state;
             this.index = 0;
         }

         generate() {
             const state = this.state;

             const cidx = this.index;
             const nidx = (cidx < 623) ? cidx + 1 : 0;
             const xidx = (cidx < 227) ? cidx + 397 : cidx - 227;
             this.index = nidx;

             const sc = state[cidx];
             const sn = state[nidx];
             const sx = state[xidx];
             const sy = ((sc & 0x80000000) | (sn & 0x7fffffff)) >>> 1;
             const sz = (sn & 1) ? 0x9908b0df : 0;
             const ss = (sx ^ sy ^ sz) >>> 0;
             state[cidx] = ss;

             const t1 = ss ^ (ss >>> 11);
             const t2 = t1 ^ ((t1 << 7) & 0x9d2c5680);
             const t3 = t2 ^ ((t2 << 15) & 0xefc60000);
             const tr = t3 ^ (t3 >>> 18);
             return tr >>> 0;
         }

         genreal() {
             return this.generate() / 4294967296;
         }
     }

     /*
      * Xorshift (32ビット)
      */

     class XorShift32 {
         constructor(seed) {
             this.seed = seed32(seed);
         }

         generate() {
             let x = this.seed;
             x ^= x << 13;
             x ^= x >>> 17;
             x ^= x << 5;
             return (this.seed = x >>> 0);
         }

         genreal() {
             return this.generate() / 4294967296;
         }
     }

     /*
      * 線形合同法(64ビット)
      */

     class LCG64 {
         constructor(seed) {
             this.seed = BigInt(seed32(seed));
             this.generate64()
         }

         generate64() {
             return this.seed = (this.seed * 0x5851f42d4c957f2dn + 0x14057b7ef767814fn) & 0xffff_ffff_ffff_ffffn;
         }

         generate() {
             return Number(this.generate64() >> 32n) >>> 0;
         }

         genreal() {
             return Number(this.generate64() >> 11n) / 9007199254740992;
         }
     }

     /*
      * 線形合同法(32ビット)
      */

     class LCG32 {
         constructor(seed) {
             this.seed = seed32(seed);
         }

         generate() {
             return this.seed = (this.seed * 0x0019660d + 0x3c6ef35f) >>> 0;
         }

         genreal() {
             return this.generate() / 4294967296;
         }
     }

     /*
      * 以下、砂嵐画面処理
      */

     function makeImage(ctx, width, height, rand) {
         const total = width * height;

         const image = ctx.createImageData(width, height);
         const pixel = image.data;

         const brightness = 0.70;
         const table = [...Array(256)].map(
             (_, n) => 255.4 * Math.pow(n / 255, 1.0 - brightness) >>> 0);

         let c = 0;
         for (let i = 0; i < pixel.length; i += 4, c >>= 8) {
             if (!(i & 0x0c))
                 c = rand.generate();
             const g = table[c & 255];
             pixel[i + 0] = g;
             pixel[i + 1] = g;
             pixel[i + 2] = g;
             pixel[i + 3] = 255;
         }

         return image;
     }

     class SandStorm
     {
         constructor(tag, rand) {
             const width = 720;
             const height = 480;
             tag.width = width;
             tag.height = height;

             this.tag = tag;
             this.rand = rand;
             this.ctx = this.tag.getContext('2d');
             this.width = this.ctx.canvas.width;
             this.height = this.ctx.canvas.height;
             this.image = makeImage(this.ctx, this.width * 4, this.height * 4, this.rand);
             this.count = 0;

             this.enable = true;
             this.tag.onclick = (() => this.onclick ());
         }
         update() {
             if (!this.enable)
                 return;

             const ox = this.count & 1 ? this.width * 2 : 0;
             const oy = this.count & 2 ? this.height * 2 : 0;
             const dx = ox + this.rand.genreal () * this.width;
             const dy = oy + this.rand.genreal () * this.height;
             this.ctx.putImageData(this.image, -dx, -dy);
             ++this.count;
         }
         onclick() {
             this.enable = !this.enable;
         }
     }

     window.onload = function() {
         const mt = new SandStorm(tagMT19937, new MT19937());
         const xs32 = new SandStorm(tagXorShift32, new XorShift32());
         const lcg64 = new SandStorm(tagLCG64, new LCG64());
         const lcg32 = new SandStorm(tagLCG32, new LCG32());

         const render = (() => {
             window.requestAnimationFrame(render);
             mt.update();
             xs32.update();
             lcg64.update();
             lcg32.update();
         });
         window.requestAnimationFrame(render);
     }

    </script>
  </body>
</html>
0
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?