Escape Room 3.15 — Level 2 Randomness in Python
Learn and play with Python's random module coin flips, dice rolls, shuffles, and probabilities
🗝️ Level 2 — Randomness in Python
The second chamber glows faintly, with glowing serpents (🐍) carved into the walls.
You’ll learn how Python generates random values and use it to simulate coins, dice, and more.
📘 Python’s random
Module
Python provides randomness with the random
module.
We’ll mainly use:
random.randint(a, b)
→ random integer between a and b, inclusiverandom.choice(list)
→ pick a random element from a listrandom.shuffle(list)
→ shuffle a list in place
🔑 Note: random.randint(a,b)
behaves exactly like AP CSP’s RANDOM(a,b)
.
Demo: random.randint
Generates a random integer between two inclusive bounds a
and b
.
import random
# roll a die
roll = random.randint(1, 6)
print("Die roll:", roll)
# simulate 5 random numbers between -3 and 3
nums = [random.randint(-3, 3) for _ in range(5)]
print("Random sample:", nums)
Die roll: 2
Random sample: [2, -2, 3, 2, 1]
Demo: random.choice
Selects a random element from a sequence (list, string, etc.).
import random
colors = ["red", "blue", "green", "yellow"]
pick = random.choice(colors)
print("Picked color:", pick)
# random character from a string
char = random.choice("ABCDE")
print("Random letter:", char)
10 coin flips: ['Heads', 'Tails', 'Heads', 'Heads', 'Tails', 'Heads', 'Tails', 'Tails', 'Heads', 'Tails']
Demo: random.shuffle
Randomizes the order of elements in a list (in place).
import random
deck = ["A♠", "2♠", "3♠", "4♠", "5♠"]
print("Original deck:", deck)
random.shuffle(deck)
print("Shuffled deck:", deck)
Original deck: ['A♠', '2♠', '3♠', '4♠', '5♠']
Shuffled deck: ['2♠', '4♠', '5♠', '3♠', 'A♠']
%%html
<div id="py-quiz" 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;">🧩 Python Random Mini-Quiz</h3>
<p style="margin:6px 0 12px; color:#cfe7ff">Answer correctly to proceed.</p>
<!-- Progress -->
<div id="pyq-progress" style="margin:10px 0 12px;">
<div style="display:flex; align-items:center; gap:10px;">
<div id="pyq-counter" style="min-width:110px; font-weight:600;">Q 1 / 12</div>
<div style="flex:1; height:8px; background:rgba(255,255,255,.12); border-radius:999px; overflow:hidden;">
<div id="pyq-bar" style="height:100%; width:0%; background:#7CFC00;"></div>
</div>
</div>
</div>
<!-- Question mount -->
<div id="pyq-stage"></div>
<!-- Nav -->
<div style="display:flex; gap:8px; margin-top:12px;">
<button id="pyq-prev" disabled>◀ Back</button>
<button id="pyq-next" disabled>Next ▶</button>
</div>
<!-- Status -->
<div id="pyq-status" style="margin-top:14px; font-weight:600;"></div>
<style>
/* Force readable light text in dark theme */
#py-quiz, #py-quiz *, #py-quiz code { color:#e9eefc; }
#py-quiz code { background:rgba(255,255,255,.08); padding:1px 4px; border-radius:4px; }
/* Buttons */
#py-quiz button{
padding:6px 10px; border-radius:6px;
border:1px solid rgba(255,255,255,.25);
background:rgba(255,255,255,.06); color:#e9eefc; cursor:pointer;
}
#py-quiz button:hover{ background:rgba(255,255,255,.12); }
#py-quiz button[disabled]{ opacity:.5; cursor:not-allowed; }
/* Card */
#py-quiz .card{
margin-bottom:14px; padding:12px; border-radius:10px;
background:rgba(255,255,255,.05); border:1px solid rgba(255,255,255,.08);
}
/* Choices */
#py-quiz .choices{ display:grid; gap:6px; margin:8px 0; }
#py-quiz .choices label{ cursor:pointer; }
#py-quiz input[type="radio"]{ accent-color:#8ab4ff; }
/* Feedback */
#py-quiz .feedback{ margin-top:8px; font-size:.95rem; }
#py-quiz .ok{ color:#7CFC00; }
#py-quiz .bad{ color:#FF6B6B; }
</style>
<script>
(function(){
const qs = [
// 1 Basics — inclusivity & behavior
{ stem: "What values can <code>random.randint(1, 3)</code> produce?",
choices:["{1,2}","{1,2,3}","{0,1,2,3}"], answer:1,
explain:"<code>randint</code> is inclusive → 1, 2, or 3." },
{ stem: "<code>random.randint(5,5)</code> always returns…",
choices:["5","a random number between 1–5","Error"], answer:0,
explain:"Inclusive endpoints; only 5 exists in the range." },
// 2 Probability reasoning
{ stem: "What is the probability that <code>random.randint(1, 10) == 7</code>?",
choices:["1/7","1/9","1/10","10%"], answer:2,
explain:"10 equally likely outcomes → 1/10 = 10%." },
{ stem: "<code>random.randint(2, 6) <= 4</code> is true what percent of the time?",
choices:["20%","40%","60%","80%"], answer:2,
explain:"Outcomes {2,3,4,5,6}. ≤4 gives {2,3,4} → 3/5 = 60%." },
// 3 random.choice
{ stem: "<code>random.choice(['red','blue','green'])</code> returns…",
choices:["Always 'red'","A random element from the list","An index number"], answer:1,
explain:"<code>choice</code> returns one random element, not an index." },
{ stem: "Which call gives a fair coin flip?",
choices:[
"<code>random.randint(0,1)</code>",
"<code>random.randint(1,2)</code>",
"<code>random.choice(['Heads','Tails'])</code>",
"All of these"
], answer:3,
explain:"All three produce two equally likely outcomes." },
// 4 Shuffle & lists
{ stem: "After <code>random.shuffle(deck)</code>, what happens?",
choices:[
"deck is unchanged",
"deck is shuffled in place",
"shuffle returns a new shuffled copy",
"Error"
], answer:1,
explain:"<code>shuffle</code> shuffles the original list in place and returns None." },
// 5 Code tracing
{ stem: "What can this print?<br><pre style='margin:6px 0;'>import random\na = random.randint(1,2)\nif a == 1:\n print('Hi')\nelse:\n print('Bye')</pre>",
choices:["Always 'Hi'","Always 'Bye'","'Hi' or 'Bye' randomly"], answer:2,
explain:"a is 1 or 2 → branch chosen at random." },
{ stem: "Given:<br><pre style='margin:6px 0;'>rolls = [random.randint(1,6) for _ in range(1000)]</pre>What is <code>rolls</code>?",
choices:["A single integer","A list of 1000 random integers (1–6)","An error"], answer:1,
explain:"List comprehension builds a 1000-element list of die rolls." },
// 6 Trickier probability
{ stem: "What percent of runs display TRUE?<br><code>random.randint(1,4) == 5</code>",
choices:["0%","20%","25%","100%"], answer:0,
explain:"Impossible; 1–4 never equals 5." },
{ stem: "What percent of runs display TRUE?<br><code>random.randint(1,4) <= 2</code>",
choices:["25%","40%","50%","100%"], answer:2,
explain:"Outcomes {1,2,3,4}; ≤2 is {1,2} → 2/4 = 50%." },
// 7 Combo / parity
{ stem: "If <code>x = random.randint(1,6)</code>, what is <code>P(x % 2 == 0)</code>?",
choices:["1/6","1/2","2/3","100%"], answer:1,
explain:"Even faces {2,4,6} are 3 of 6 → 1/2." }
];
const root = document.getElementById('py-quiz');
const stage = document.getElementById('pyq-stage');
const status = document.getElementById('pyq-status');
const prevBtn= document.getElementById('pyq-prev');
const nextBtn= document.getElementById('pyq-next');
const counter= document.getElementById('pyq-counter');
const bar = document.getElementById('pyq-bar');
const solved = new Set();
let idx = 0;
let lastCorrect = false;
function render(){
stage.innerHTML = '';
const q = qs[idx];
const card = document.createElement('div');
card.className = 'card';
card.innerHTML = `
<div style="font-weight:600; margin-bottom:6px;">Q${idx+1}.</div>
<div>${q.stem}</div>
<div class="choices">
${q.choices.map((c,i)=>`
<label><input type="radio" name="q-${idx}" value="${i}"> ${String.fromCharCode(65+i)}. ${c}</label>
`).join('')}
</div>
<button id="check">Check</button>
<div id="fb" class="feedback"></div>
`;
stage.appendChild(card);
const fb = card.querySelector('#fb');
card.querySelector('#check').onclick = ()=>{
const sel = card.querySelector('input[type="radio"]:checked');
if(!sel){
fb.textContent = "Pick an option.";
fb.className = 'feedback bad';
lastCorrect = false;
update();
return;
}
const ok = Number(sel.value) === q.answer;
if(ok){
fb.innerHTML = `✅ <span class="ok">Correct.</span> ${q.explain || ''}`;
fb.className = 'feedback ok';
solved.add(idx);
lastCorrect = true;
}else{
fb.innerHTML = `❌ <span class="bad">Not quite.</span>`;
fb.className = 'feedback bad';
solved.delete(idx);
lastCorrect = false;
}
update();
};
// if previously solved, allow next
lastCorrect = solved.has(idx);
update();
}
function update(){
counter.textContent = `Q ${idx+1} / ${qs.length}`;
const pct = (solved.size / qs.length) * 100;
bar.style.width = pct.toFixed(1) + '%';
status.textContent = solved.size === qs.length
? "🎉 All tumblers solved! You’ve cleared the Python chamber."
: `🔐 ${solved.size}/${qs.length} solved.`;
prevBtn.disabled = (idx===0);
nextBtn.disabled = !lastCorrect || (idx===qs.length-1);
nextBtn.textContent = (idx===qs.length-1) ? "Finish" : "Next ▶";
}
prevBtn.onclick = ()=>{ if(idx>0){ idx--; render(); } };
nextBtn.onclick = ()=>{
if(idx < qs.length-1){ idx++; render(); }
else { status.textContent = "🏆 You mastered the Python lock — onward!"; }
};
render();
})();
</script>
</div>
🧩 Python Random Mini-Quiz
Answer correctly to proceed.
Q 1 / 12