Category Archives: random

PRNG Sine Rendering (Easiest Seeded Random with Index)

Here is a codepen showing seeded random numbers created use `Math.sin`. We’ll get to the code in a bit, first a little backstory…

Over the years I’ve used all manner of famous random number generators. From Tausworthe to Mersenne Twister.

Sometime last year I was trying to find a seeded PRNG, when working in Objective-C `arc4random` seems to be the common choice. I quickly became frustrated however as it didn’t seem possible or at least didn’t seem easy at all to reset the sequence of numbers. Maybe there’s an easy way, but whatever it is, I couldn’t find it. So after probably an hour of frustration trying all the weird different PRNGs, I decided to resort to a super simple old trick.

Why do you care about resetting the sequence?

Having a seed that you save at the beginning of your program can be super powerful. You can use anything for this seed, like the time or just another random number. From that point on your random numbers will be completely deterministic and depending on the complexity of your program you can simply save the seed and use it again later - causing your program to do exactly the same thing it did last time it had that seed. Those of you who dabble with generative artwork are probably familiar with this idea.

This experiment uses that trick:

Those textures will always be the same when the seed is 18. Thats an old experiment from the flash days, I think I used Grant Skinner’s seeded PRNG for that.

On the off chance you still have flash in your browser you can see it here:

Static black and white:
http://zevanrosser.com/sketchbook/things/bw_tex_static.html

Animated black and white:
http://zevanrosser.com/sketchbook/things/bw_tex_animated.html

Ugly colors version:
http://zevanrosser.com/sketchbook/things/col_tex_animated.html

It turns out that if you take sine or cosine and pop very large values for theta into it - you get something that looks very random. Lets look at the code:

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
var rc = 0,
  seed = 30,
  MAX_RAND = 0xffffff;
 
function idxRand(nth) {
  if (nth != null) rc = nth;
  rc++;
  return Math.abs(Math.sin(seed * rc) * MAX_RAND);
}
 
var firstFour = [idxRand(), idxRand(), idxRand(), idxRand()],
  second = idxRand(1),
  fourth = idxRand(3);
 
console.log(firstFour);
console.log(second);
console.log(fourth);
 
var canvas = document.createElement("canvas"),
  c = canvas.getContext("2d");
 
canvas.width = 400;
canvas.height = 300;
c.fillStyle = "black";
c.fillRect(0, 0, canvas.width, canvas.height);
document.body.appendChild(canvas);
 
for (var i = 0; i < 300; i++) {
  c.fillStyle = "red";
  c.fillRect(idxRand() % 200, i, 4, 4);
 
  c.fillStyle = "green";
  c.fillRect(200 + Math.random() * 200, i, 4, 4);
}

Will output something like this:

[16576418.984205123, 5113873.3245154265, 14998774.234509233, 9741038.668934602]
5113873.3245154265
9741038.668934602

This code could be improved in a few different ways - but its good enough to illustrate the technique. Lines 1-9 are all you need to have a reproducible random sequence. With a large step value for theta and an even larger coefficient (0xffffff) for sine, you can use modulo to get the range you need (line 30). You can access the old values by passing an index to `idxRand`. This is illustrated in lines 11 through 17 - where we get the first four values and then grab them again using the index argument.

While significantly statistically different - and likely significantly different performance-wise, you’ll notice that visually there is little difference… :D

UPDATE: Had an idea that an alternative post title for this would be Easily Attain the Nth value from a PPRNG(pseudo-pseudo-random-number-generator)…

Also posted in Math, Uncategorized, javascript, misc | Tagged , , | Leave a comment

2D Map Avoid

Actionscript:
  1. [SWF(width=401,height=401,background=0xEFEFEF)]
  2.  
  3. var w:Number = stage.stageWidth-1;
  4. var h:Number = stage.stageHeight-1;
  5. var tileSize:Number = 20;
  6. var halfTileSize:Number = 20;
  7. var hTiles:Number = w / tileSize;
  8. var vTiles:Number = h / tileSize;
  9. var world:Shape = Shape(addChild(new Shape()));
  10. var map:Array=[];
  11. populateMap();
  12. var gridColor:uint = 0xCCCCCC;
  13. grid(tileSize,  gridColor);
  14.  
  15. vTiles -= 1;
  16. var movers:Array = [];
  17. for (var i:int = 0; i<100; i++){
  18.     movers.push(makeMover(i % hTiles, int( i / hTiles),0x000000))
  19.     movers.push(makeMover(i % hTiles, vTiles - int( i / hTiles),0xFF0000))
  20. }
  21. var moverNum:int = movers.length;
  22. hTiles -= 1;
  23.  
  24. addEventListener(Event.ENTER_FRAME, onLoop);
  25. function onLoop(evt:Event):void {
  26.     world.graphics.clear();
  27.     for (var i:int = 0; i<moverNum; i++){
  28.        movers[i]();
  29.      }
  30. }
  31. function populateMap():void{
  32.     for (var i:int = 0; i<vTiles; i++){
  33.         map[i] = [];
  34.         for (var j:int = 0; j<hTiles; j++){
  35.             map[i][j] = 0;
  36.         }
  37.     }
  38. }
  39. function grid(size:Number=30, lineColor:uint=0xFFFF00, lineAlpha:Number=1):void {
  40.     with(graphics){
  41.         lineStyle(0, lineColor, lineAlpha);
  42.         drawRect(0,0,w,h);
  43.         for (var i:Number = size; i<w; i+=size) {
  44.             moveTo(i, 0);
  45.             lineTo(i, w);
  46.         }
  47.         for (i = size; i<h; i+=size) {
  48.             moveTo(0, i);
  49.             lineTo(h, i);
  50.         }
  51.     }
  52. }
  53. function makeMover(x:Number, y:Number, col:uint):Function{
  54.     var xp:Number = x;
  55.     var yp:Number = y;
  56.     var prevX:Number = x;
  57.     var prevY:Number = y;
  58.     map[yp][xp] = 1;
  59.     var dx:Number = xp;
  60.     var dy:Number = yp;
  61.     var counter:int = 0;
  62.     return function():void{
  63.         if (counter> 20){
  64.             if (int(Math.random()*30) == 1){
  65.                 xp += int(Math.random()*2) - 1 | 1;
  66.                 xp = xp <0 ? 0 : xp;
  67.                 xp = xp> hTiles ? hTiles : xp;
  68.                 if (map[yp][xp] == 1){
  69.                      xp = prevX;
  70.                 }else{
  71.                     map[prevY][prevX] = 0;
  72.                     map[yp][xp] = 1;
  73.                     counter = 0;
  74.                 }
  75.                 prevX = xp;
  76.             }else
  77.             if (int(Math.random()*30) == 1){
  78.                 yp += int(Math.random()*2) - 1 | 1;
  79.                 yp = yp <0 ? 0 : yp;
  80.                 yp = yp> vTiles ? vTiles : yp;
  81.                 if (map[yp][xp] == 1){
  82.                      yp = prevY;
  83.                 }else{
  84.                     map[prevY][prevX] = 0;
  85.                     map[yp][xp] = 1;
  86.                     counter = 0;
  87.                 }
  88.                 prevY = yp;
  89.             }
  90.         }
  91.         counter++;
  92.         dx += (xp - dx) * 0.5;
  93.         dy += (yp - dy) * 0.5;
  94.         with(world.graphics){
  95.             lineStyle(0, gridColor,1, true)
  96.             beginFill(col);
  97.             drawRect(dx * tileSize, dy * tileSize, tileSize, tileSize);
  98.         }
  99.     }
  100. }

This (somewhat long) snippet moves boxes around on a grid - the boxes avoid one another by reading values in a 2D array. This technique can also be used for collision detection in tile-based games.


Have a look at the swf here...

Also posted in arrays, motion | Tagged , , | Leave a comment

Math.random() * Math.random()

Actionscript:
  1. var rand:Number = Math.random() * Math.random() * Math.random();

This is a trick I use when I need more contrast in my random numbers. In this case, the variable rand will get closer to the number 1 significantly less frequently than if you just used Math.random() once.

To illustrate this I created this snippet:

Actionscript:
  1. [SWF(width=800, height=600)]
  2.  
  3. var r:Number = Math.random() * Math.random() * Math.random();
  4. var inc:int = 0;
  5. var xp:Number = 10;
  6. var yp:Number = 10;
  7. var count:int = 1;
  8.  
  9. var compare:Shape = Shape(addChild(new Shape()));
  10. compare.graphics.lineStyle(0,0x2222FF);
  11.  
  12. graphics.lineStyle(0,0x00000);
  13. scaleX = scaleY = 2;
  14.  
  15. addEventListener(Event.ENTER_FRAME, onLoop);
  16. function onLoop(evt:Event):void {
  17.    
  18.      r =  Math.random() * Math.random() * Math.random();
  19.  
  20.      if (inc == 0){
  21.          graphics.moveTo(xp + inc, yp + 30 - r * 30);
  22.      }else{
  23.          graphics.lineTo(xp + inc, yp + 30 - r * 30);
  24.      }
  25.      
  26.      r = Math.random();
  27.       if (inc == 0){
  28.          compare.graphics.moveTo(xp + inc, yp + 70 - r * 30);
  29.      }else{
  30.          compare.graphics.lineTo(xp + inc, yp + 70 - r * 30);
  31.      }
  32.      inc++;
  33.      if (inc == 50){
  34.          inc = 0;
  35.          xp = 10 + count % 6 * 60;
  36.          yp = 10 + int(count / 6) * 80;
  37.          r = Math.random()*Math.random();
  38.          count++;
  39.      }
  40. }

The blue lines plots normal Math.random() and the black lines plots Math.random()*Math.random()*Math.random()

Also posted in one-liners | Tagged , , | 2 Comments

Random Guitar Tablature

Actionscript:
  1. // number of notes in chord
  2. var noteNum:int = 3;
  3. var lowNote:Number = 0;
  4. var highNote:Number = 4;
  5. // delay between chords
  6. var delay:int = 2000;
  7. ////////////////////////////////////////
  8. var chord:String = "";
  9. highNote += 1;
  10. var tab:TextField = TextField(addChild(new TextField()));
  11. tab.x = tab.y = 20;
  12. tab.defaultTextFormat = new TextFormat("Courier", 12);
  13. tab.multiline = true;
  14. tab.width = 200;
  15.  
  16. changeChord();
  17. setInterval(changeChord, delay);
  18.  
  19. function changeChord():void{
  20.     var strings:Array = [];
  21.     strings[0] = "e|---------------\n"
  22.     strings[1] = "B|---------------\n"
  23.     strings[2] = "G|---------------\n"
  24.     strings[3] = "D|---------------\n"
  25.     strings[4] = "A|---------------\n"
  26.     strings[5] = "E|---------------\n"
  27.    
  28.     for (var i:int = 0; i<3; i++){
  29.         var place:int = 5 + i * 4;
  30.         var choices:Array = [0,1,2,3,4,5];
  31.         for (var j:int = 0; j<noteNum; j++){
  32.             var ii:int = int(Math.random()*choices.length);
  33.             var index:int = choices[ii];
  34.             strings[index] = strings[index].slice(0, place) + (int(Math.random()*highNote)+lowNote) +  strings[index].substring(place+1);
  35.             choices.splice(ii, 1);
  36.         }
  37.     }
  38.     chord = strings.join("");
  39.     tab.text = chord;
  40. }

I'm working on a small program to help me practice guitar. It randomly generates guitar tabs. The idea for the program is similar to a program that helps you learn to type (like Mavis Beacon).

I wrote this snippet today as a proof of concept - just to help me start thinking about what kind of features I want the program to have. There are settings at the top so that you can tweak the number of notes in the chord and the delay between chords etc....

It generates three chords at a time... here are some stills:

Also posted in string manipulation, strings | Tagged , , | 6 Comments