Generates an Ulam Spiral of total cycle depth for the Kaprekar Routine for the range [0, 998k].
Try the linear [0, 1M] version here.
A Pen by Riley Shaw on CodePen.
button#go Generate |
Generates an Ulam Spiral of total cycle depth for the Kaprekar Routine for the range [0, 998k].
Try the linear [0, 1M] version here.
A Pen by Riley Shaw on CodePen.
;(function() { | |
// recursively runs through Kaprekar Routine until | |
// we hit a duplicate value (.: end of cycle) | |
function step (cur, prev, i) { | |
if (prev[cur]) return i - 1; | |
else prev[cur] = true; | |
var lo = String(cur).split('').sort(); | |
var hi = lo.slice().reverse(); | |
lo = +(lo.join('')); hi = +(hi.join('')); | |
return step(hi - lo, prev, i + 1); | |
} | |
// initialization for the first step | |
function kaprekar (num) { | |
return step(num, {}, 0); | |
} | |
function download () { | |
var img = canvas.toDataURL('image/png'); | |
var imgLink = document.createElement('a'); | |
imgLink.href = img; | |
imgLink.download = 'kaprekar-ulam'; | |
imgLink.click(); | |
} | |
var i, depth = 19; // max depth [0, 1M) = 19 | |
var button = document.getElementById('go'); | |
var canvas = document.createElement('canvas'); | |
canvas.width = canvas.height = 999; | |
var ctx = canvas.getContext('2d'); | |
// initialize a color array with evenly spaced values | |
var c1 = [52, 152, 219], c2 = [44, 62, 80], delta = [], color = []; | |
// calculate color deltas between depths | |
for (i = 0; i < 3; i++) { | |
delta.push((c2[i] - c1[i]) / depth); | |
} | |
// populate the color array | |
for (i = 0; i < depth; i++) { | |
color.push([ | |
Math.round(c1[0] + delta[0] * i), | |
Math.round(c1[1] + delta[1] * i), | |
Math.round(c1[2] + delta[2] * i) | |
]); | |
} | |
color.push(c2); | |
// end color initialization | |
var dirs = [ | |
{ x: 1, y: 0 }, | |
{ x: 0, y: 1 }, | |
{ x: -1, y: 0 }, | |
{ x: 0, y: -1 } | |
]; | |
button.addEventListener('click', function populate1M () { | |
var redir = 3; // next number that the spiral changes direction at | |
var run = 1; // current spiral arm length | |
var dir = 0; // 0: right, 1: up, 2: left, 3: down | |
var pos = {x: 499, y: 500}; // offset x by -1; we move right before drawing | |
// start timer & main loop | |
var t1 = window.performance.now(), i = 0; | |
button.textContent = '0%'; | |
setTimeout(function drawChunk () { // draws 1% of the canvas | |
for (var c = 9980; c--; i++) { | |
if (i === redir) { | |
dir = (dir + 1) % 4; | |
if (dir % 2 === 0) run++; // run increases when switching left or right | |
redir += run; | |
} | |
pos.x += dirs[dir].x; | |
pos.y += dirs[dir].y; | |
ctx.fillStyle = 'rgb(' + color[kaprekar(i)] + ')'; | |
ctx.fillRect(pos.x, pos.y, 1, 1); | |
} | |
if (i < 998000) { | |
button.textContent = (i) / 9980 + '%'; | |
setTimeout(drawChunk, 1); | |
} else loopDone(); | |
}, 1); | |
function loopDone () { | |
var t2 = window.performance.now(); | |
download(); | |
// log execution time in seconds | |
console.log('Main loop execution took ' + | |
((t2 - t1) / 1000).toFixed(2) + 's'); | |
button.textContent = 'Regenerate'; | |
} | |
}, false); | |
})(); |
$light: rgb(52, 152, 219) | |
$dark: rgb(44, 62, 80) | |
body | |
background: $dark | |
button | |
position: absolute | |
top: 50% | |
left: 50% | |
height: 2em | |
width: 8em | |
margin: -1em -4em | |
border: 0 | |
border-radius: 0 | |
outline: 0 | |
font: 24px Open Sans, sans-serif | |
background: $light | |
color: $dark | |
cursor: pointer |