πŸ—οΈ 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: Random Values Reference

  • Produces a random integer between a and b.
  • Both a and b 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), not RANDOM(1,2).

⬅️ Back to Lobby