Escape Room 3.15 - Level 1 Randomness Explorer
Learn how RANDOM(a,b) works in AP CSP pseudocode and visualize fairness with repeated trials
ποΈ Level 1 β Randomness Explorer (Pseudocode)
The first lock hums faintly. Strange runes on its surface spell out RANDOM(a, b).
To move forward, you must understand how this function works β the way the College Board expects you to on the AP exam.
π College Board Expectation
Hereβs College Boardβs Pseudocode for generating random numbers:
- Produces a random integer between
a
andb
. - Both
a
andb
are inclusive.
Examples:
RANDOM(1, 6)
β {1, 2, 3, 4, 5, 6}RANDOM(0, 1)
β {0, 1} (coin flip)RANDOM(5, 5)
β always {5}
π Essential Takeaways
- Uniform: Every value in the range is equally likely.
- Inclusive: Donβt forget both ends are included!
- Probability: Chance of one outcome =
1 / (# of possible outcomes)
.
Example:
RANDOM(1, 10) = 7
β probability = 1/10 = 10%.
π² Interactive Activity: Random Number Generator
Choose values for a and b, then roll once or roll many times. Watch the distribution form and notice how fairness emerges with larger trials. β
%%html
<div id="er-l1" style="margin:18px 0; padding:16px; border:1px solid rgba(255,255,255,.12); border-radius:14px; background:linear-gradient(180deg,#101635,#0b1026);">
<h3 style="margin:0 0 10px;">π Level 1 Lock β RANDOM(a,b) Lab</h3>
<p style="margin:6px 0 12px; color:#cfe7ff">Choose <code>a</code>, <code>b</code> (between -10 and 10), set trials, and roll. When distribution looks uniform, the lock humsβ¦</p>
<!-- Controls -->
<div style="display:flex; flex-wrap:wrap; gap:10px; align-items:flex-end; margin:8px 0 14px;">
<label> a<br><input id="er-l1-a" type="number" value="1" min="-10" max="10" style="width:90px"></label>
<label> b<br><input id="er-l1-b" type="number" value="6" min="-10" max="10" style="width:90px"></label>
<label> trials (for multi-roll)<br><input id="er-l1-n" type="number" value="100" min="1" max="100000" step="10" style="width:120px"></label>
<div style="display:flex; gap:8px;">
<button id="er-l1-roll1">Roll Γ1</button>
<button id="er-l1-rolln">Roll ΓN</button>
<button id="er-l1-reset" title="Clear counts">Reset</button>
</div>
</div>
<!-- Feedback -->
<div id="er-l1-msg" style="min-height:20px; color:#ffd27a; margin-bottom:8px;"></div>
<div><strong>Latest values:</strong> <span id="er-l1-last" style="font-family: ui-monospace, Menlo, monospace;"></span></div>
<!-- Chart -->
<div id="er-l1-chart" style="margin-top:12px; display:grid; grid-template-columns: 90px 1fr 110px; gap:6px; align-items:center;"></div>
<!-- Status -->
<div id="er-l1-status" style="margin-top:10px; font-weight:600;"></div>
<style>
/* General text inside the lock container */
#er-l1, #er-l1 label, #er-l1 strong, #er-l1 .tick, #er-l1 .count {
color: #e9eefc; /* bright off-white */
}
#er-l1 input {
background: #0f1530;
color: #e9eefc;
border: 1px solid rgba(255,255,255,.25);
padding: 4px 6px;
border-radius: 6px;
}
#er-l1 button {
padding:6px 10px;
border-radius:8px;
border:1px solid rgba(255,255,255,.25);
background:rgba(255,255,255,.06);
color:#e9eefc; /* force bright text */
cursor:pointer;
}
#er-l1 button:hover {
background: rgba(255,255,255,.12);
}
#er-l1 .bar {
height:10px;
background: linear-gradient(90deg,#8ab4ff,#4e89ff);
border-radius:6px;
width:0;
transition: width .12s ease;
}
#er-l1 .count {
text-align:right;
font-family: ui-monospace, Menlo, monospace;
}
#er-l1 .tick {
font-variant-numeric: tabular-nums;
}
/* Feedback messages */
#er-l1-msg { color:#ffd27a; }
#er-l1-status { color:#cfe7ff; }
</style>
<script>
(function(){
const root = document.getElementById('er-l1');
const aIn = root.querySelector('#er-l1-a');
const bIn = root.querySelector('#er-l1-b');
const nIn = root.querySelector('#er-l1-n');
const lastEl = root.querySelector('#er-l1-last');
const chart = root.querySelector('#er-l1-chart');
const status = root.querySelector('#er-l1-status');
const msg = root.querySelector('#er-l1-msg');
let counts = {};
let total = 0;
const maxBar = 380;
function rngInt(lo, hi){
const a = Math.min(lo, hi), b = Math.max(lo, hi);
return Math.floor(Math.random() * (b - a + 1)) + a;
}
function ensureDomain(){
chart.innerHTML = '';
msg.textContent = '';
let a = clamp(Number(aIn.value), -10, 10);
let b = clamp(Number(bIn.value), -10, 10);
aIn.value = a; bIn.value = b;
if (!Number.isFinite(a) || !Number.isFinite(b)) {
msg.textContent = 'Enter valid numbers for a and b.';
return null;
}
const lo = Math.min(a,b), hi = Math.max(a,b);
if (lo === hi) {
msg.textContent = 'Range has one value; distribution will be a spike.';
}
counts = {};
for (let v = lo; v <= hi; v++) {
counts[v] = 0;
const lab = document.createElement('div'); lab.textContent = v; lab.className='tick';
const bar = document.createElement('div'); bar.className='bar'; bar.dataset.v = v;
const ct = document.createElement('div'); ct.className='count'; ct.dataset.v = v; ct.textContent = '0';
chart.append(lab, bar, ct);
}
total = 0;
lastEl.textContent = '';
render();
return {lo, hi};
}
function render(){
const bars = chart.querySelectorAll('.bar');
const cts = chart.querySelectorAll('.count');
const maxC = Math.max(1, ...Object.values(counts));
bars.forEach(bar=>{
const v = Number(bar.dataset.v);
const w = total===0 ? 0 : Math.round((counts[v]/maxC) * maxBar);
bar.style.width = w + 'px';
});
cts.forEach(cell=>{
const v = Number(cell.dataset.v);
cell.textContent = counts[v] + (total ? ` (${(counts[v]/total*100).toFixed(1)}%)` : '');
});
if (total < 1) { status.textContent = "π The lock waitsβ¦"; return; }
const mean = total / Object.keys(counts).length;
const maxDev = Math.max(...Object.values(counts).map(c=>Math.abs(c-mean)));
status.textContent = (total >= 150 && (maxDev / Math.max(1,mean) < 0.25))
? "π The lock hums β distribution looks uniform."
: "π Keep rolling; approach a uniform spread.";
}
function rollOnce(){
const a = Number(aIn.value), b = Number(bIn.value);
const x = rngInt(a,b);
counts[x] = (counts[x] || 0) + 1;
total++;
lastEl.textContent = (lastEl.textContent + ' ' + x).trim().split(/\s+/).slice(-20).join(' ');
render();
}
function rollMany(n){
const a = Number(aIn.value), b = Number(bIn.value);
const out = [];
for (let i=0;i<n;i++){ const x = rngInt(a,b); counts[x] = (counts[x]||0)+1; total++; out.push(x); }
lastEl.textContent = out.slice(-20).join(' ');
render();
}
function reset(){ ensureDomain(); }
function clamp(val,min,max){ return Math.max(min, Math.min(max, val)); }
// Wire buttons
root.querySelector('#er-l1-roll1').onclick = ()=> rollOnce();
root.querySelector('#er-l1-rolln').onclick = ()=>{
const n = Math.max(1, Math.min(100000, Number(nIn.value) || 100));
rollMany(n);
};
root.querySelector('#er-l1-reset').onclick = reset;
// Auto-reset when a or b changes
aIn.addEventListener('input', ensureDomain);
bIn.addEventListener('input', ensureDomain);
ensureDomain();
})();
</script>
</div>
π Level 1 Lock β RANDOM(a,b) Lab
Choose a
, b
(between -10 and 10), set trials, and roll. When distribution looks uniform, the lock humsβ¦
Latest values:
β οΈ Common Misconceptions
RANDOM(1,6)
does not give decimals β only whole numbers.- Donβt forget that both ends are included (students often think
RANDOM(1,6)
gives 1β5). - If you want 0/1 for a coin flip, use
RANDOM(0,1)
, notRANDOM(1,2)
.