Skip to content

Instantly share code, notes, and snippets.

@BiatuAutMiahn
Last active May 15, 2025 21:47
Show Gist options
  • Select an option

  • Save BiatuAutMiahn/360b19298bd74bb848229cedbaeaf77c to your computer and use it in GitHub Desktop.

Select an option

Save BiatuAutMiahn/360b19298bd74bb848229cedbaeaf77c to your computer and use it in GitHub Desktop.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>DigitalRootCompass</title>
<style>
body {
font-family: sans-serif;
display: flex;
flex-direction: column;
align-items: center;
padding: 20px;
background-color: #f0f0f0;
}
#graph-container {
display: flex;
align-items: flex-end; /* Align bars at the bottom */
border: 1px solid #ccc;
padding: 10px;
height: 300px; /* Max height for graph area */
background-color: white;
box-shadow: 0 0 10px rgba(0,0,0,0.1);
margin-bottom: 20px;
}
.column {
display: flex;
flex-direction: column;
align-items: center;
margin: 0 5px;
width: 50px;
}
.bar {
width: 100%;
background-color: steelblue;
transition: height 0.1s linear; /* Smooth height transition */
height: 0; /* Initial height */
}
.label, .count {
margin-top: 5px;
font-size: 12px;
}
.count {
font-weight: bold;
color: #333;
}
.controls button {
padding: 10px 15px;
margin: 5px;
cursor: pointer;
border: 1px solid #ccc;
background-color: #e9e9e9;
}
.controls button:hover {
background-color: #dcdcdc;
}
</style>
</head>
<body>
<h1>Digital Root Compass</h1>
<p>Your flything through time, which path are you taking? You are a Kite with a string in a hurricane...good luck.</p>
<div id="graph-container">
<!-- Columns will be generated by JavaScript -->
</div>
<div class="controls">
<button id="startButton">Start</button>
<button id="stopButton">Stop</button>
</div>
<script>
const dataStore = {};
const graphContainer = document.getElementById('graph-container');
const MAX_BAR_HEIGHT_PX = 275; // Max height for individual bars within the container
let generatorIntervalId = null;
let discarderIntervalId = null;
let graphUpdateIntervalId = null;
// --- Configuration ---
const GENERATION_INTERVAL_MS = 9; // Add a new number every 50ms
const DISCARD_INTERVAL_MS = 72; // Attempt to discard from each array every 200ms
const GRAPH_UPDATE_INTERVAL_MS = 36; // Update graph display every 100ms (10 FPS)
const TARGET_MAX_RANDOM_VALUE = 4294967292;//65529; // Our new "balanced" upper bound
// Helper function for cryptographically secure random integer in a range [0, maxInclusive]
function getSecureRandomInt(maxInclusive) {
const range = maxInclusive + 1;
// We'll use a Uint32Array as our source of randomness. Max value is 2^32 - 1.
const maxSourceValue = 0xFFFFFFFF;
// The largest multiple of 'range' that is less than or equal to (maxSourceValue + 1)
// This is the 'limit' for rejection sampling to avoid modulo bias.
const limit = Math.floor((maxSourceValue + 1) / range) * range;
let randomNumber;
const buffer = new Uint32Array(1);
do {
window.crypto.getRandomValues(buffer);
randomNumber = buffer[0];
} while (randomNumber >= limit); // Keep generating until we get a number within the unbiased part of the source range
return randomNumber % range; // Now, modulo is unbiased
}
131070
function generateAndAppend() {
let randomNumber;
if (window.crypto && window.crypto.getRandomValues) {
randomNumber = getSecureRandomInt(TARGET_MAX_RANDOM_VALUE); // Generate 0 to 65537
} else {
console.error("Cryptographically secure random number generator (window.crypto.getRandomValues) is not available. Stopping number generation.");
if (generatorIntervalId) {
clearInterval(generatorIntervalId);
generatorIntervalId = null;
}
return;
}
const root = getDigitalRoot(randomNumber);
const key = root.toString();
if (dataStore[key]) {
dataStore[key].push(randomNumber);
} else {
console.warn(`Calculated root ${root} for ${randomNumber} (crypto) has no corresponding array.`);
}
}
// 1. Initialize Data Store and Graph Structure
function initialize() {
graphContainer.innerHTML = ''; // Clear previous graph if any
for (let i = 1; i <= 9; i++) {
const key = i.toString();
dataStore[key] = [];
const columnDiv = document.createElement('div');
columnDiv.classList.add('column');
const countSpan = document.createElement('span');
countSpan.classList.add('count');
countSpan.id = `count-${key}`;
countSpan.textContent = '0';
const barDiv = document.createElement('div');
barDiv.classList.add('bar');
barDiv.id = `bar-${key}`;
barDiv.style.height = '0px';
const labelSpan = document.createElement('span');
labelSpan.classList.add('label');
labelSpan.textContent = key;
columnDiv.appendChild(countSpan);
columnDiv.appendChild(barDiv);
columnDiv.appendChild(labelSpan);
graphContainer.appendChild(columnDiv);
}
}
// 2. Digital Root Calculation
function getDigitalRoot(num) {
if (num === 0) return 9; // As per problem, map 0 to column 9 (1-9 range)
let n = num;
while (n >= 10) {
n = String(n)
.split('')
.reduce((sum, digit) => sum + parseInt(digit), 0);
}
return n; // Will be 1-9 (for n > 0 original input)
}
// 4. Discarding Elements
function discardOldest() {
for (let i = 1; i <= 9; i++) {
const key = i.toString();
if (dataStore[key] && dataStore[key].length > 0) {
dataStore[key].shift(); // Remove the first element
}
}
}
// 5. Graph Update Function
function updateGraph() {
let overallMaxCount = 0; // Find max count across all arrays for scaling
for (let i = 1; i <= 9; i++) {
const count = dataStore[i.toString()]?.length || 0;
if (count > overallMaxCount) {
overallMaxCount = count;
}
}
// To prevent division by zero if all counts are 0, and ensure bars are 0 height then
const scalingFactor = overallMaxCount > 0 ? MAX_BAR_HEIGHT_PX / overallMaxCount : 0;
for (let i = 1; i <= 9; i++) {
const key = i.toString();
const count = dataStore[key]?.length || 0;
const barElement = document.getElementById(`bar-${key}`);
const countElement = document.getElementById(`count-${key}`);
if (barElement && countElement) {
const barHeight = Math.min(MAX_BAR_HEIGHT_PX, count * scalingFactor);
barElement.style.height = `${barHeight}px`;
countElement.textContent = count;
}
}
}
// 6. Control Functions
function startSimulation() {
if (generatorIntervalId !== null) return; // Already running
console.log('Starting simulation...');
initialize(); // Reset graph and data
updateGraph(); // Initial render of empty graph
generatorIntervalId = setInterval(generateAndAppend, GENERATION_INTERVAL_MS);
discarderIntervalId = setInterval(discardOldest, DISCARD_INTERVAL_MS);
graphUpdateIntervalId = setInterval(updateGraph, GRAPH_UPDATE_INTERVAL_MS);
document.getElementById('startButton').disabled = true;
document.getElementById('stopButton').disabled = false;
}
function stopSimulation() {
if (generatorIntervalId === null) return; // Already stopped
console.log('Stopping simulation...');
clearInterval(generatorIntervalId);
clearInterval(discarderIntervalId);
clearInterval(graphUpdateIntervalId);
generatorIntervalId = null;
discarderIntervalId = null;
graphUpdateIntervalId = null;
document.getElementById('startButton').disabled = false;
document.getElementById('stopButton').disabled = true;
}
// --- Event Listeners ---
document.getElementById('startButton').addEventListener('click', startSimulation);
document.getElementById('stopButton').addEventListener('click', stopSimulation);
// --- Initial Setup ---
document.addEventListener('DOMContentLoaded', () => {
initialize(); // Set up the graph structure
updateGraph(); // Show initial empty state
document.getElementById('stopButton').disabled = true; // Stop is initially disabled
});
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment