GPT-OSS 120B × slots
0.7Vegas slot machine — reels, pay table, betting, win animations
correctness 0.0quality 1.0documentation 1.09193ms
$ cat slots.prompt — what the model was asked
Build a fully playable Vegas-style slot machine in a single self-contained HTML file with no external libraries and no external assets.
## Reels
- 3 reels, each with these 7 symbols: 🍒 Cherry, 🍋 Lemon, 🍊 Orange, 🍇 Grape, 🔔 Bell, ⭐ Star, 7️⃣ Seven
- Spin animation: each reel spins independently (reel 1 stops ~800ms, reel 2 ~1200ms, reel 3 ~1600ms), showing symbols scrolling at ~12 symbols/sec before snapping to the result
- SPIN button disabled while spinning
## Pay table (multipliers × bet)
- 7️⃣ 7️⃣ 7️⃣ → 100×
- ⭐ ⭐ ⭐ → 50×
- 🔔 🔔 🔔 → 20×
- 🍇 🍇 🍇 → 15×
- 🍊 🍊 🍊 → 10×
- 🍋 🍋 🍋 → 5×
- 🍒 🍒 🍒 → 3×
- Any two 🍒 in first two positions → 2×
- All other → 0× (loss)
## Betting & credits
- Start with 100 credits
- Bet buttons: 1, 5, 10 credits (highlighted active; default: 1)
- Bet deducted immediately on spin; win adds bet × multiplier
- GAME OVER at 0 credits with 'Play Again' button that resets to 100
## Win feedback
- Win: flash matching symbols, show '+[amount] credits' in gold, display win name ('JACKPOT!', 'THREE BELLS', etc.)
- Loss: shake animation on reels
- Credit balance count-up animation over 400ms
## Pay table display
- Visible panel on page (not a modal) listing all combinations
- Highlight winning row when that combination hits
## Code quality
- Single HTML file; all JS in <script>, all CSS in <style>
- Game state: { credits, bet, spinning, reels, result }
- Named functions: initState(), spin(), checkWin(), animateReels(), updateUI()
- RNG: Math.random() only
- No inline onclick= handlers; use addEventListenerrun 1 of 1
0.7correctness 0.0quality 1.0documentation 1.09193ms
# judge: The response is truncated mid-function and never completes the core game logic (spin, checkWin, animateReels, updateUI), making it entirely non-functional.
$ cat gpt-oss-120b.slots.r1.response
**Slot‑Machine – one HTML file**
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>💰 Vegas‑Style Slot Machine</title>
<style>
body{
font-family:Arial,Helvetica,sans-serif;
background:#222;
color:#ddd;
text-align:center;
margin:0;
padding:0;
}
h1{margin:20px 0 5px; color:#ff0;}
#credits{font-size:1.5rem; margin:10px;}
#message{font-size:1.2rem; height:1.4rem; color:#ff0;}
#reels{
display:flex;
justify-content:center;
margin:20px auto;
width:320px;
font-size:4rem;
line-height:1;
position:relative;
}
.reel{
width:80px;
height:80px;
margin:0 8px;
background:#111;
border:4px solid #444;
border-radius:8px;
display:flex;
align-items:center;
justify-content:center;
user-select:none;
}
.flash{
animation:flash 0.6s ease-in-out 2;
}
@keyframes flash{
0%,100%{background:#111; transform:scale(1);}
50%{background:#ff0; transform:scale(1.1);}
}
.shake{
animation:shake 0.4s;
}
@keyframes shake{
0%{transform:translateX(0);}
25%{transform:translateX(-6px);}
50%{transform:translateX(6px);}
75%{transform:translateX(-6px);}
100%{transform:translateX(0);}
}
#controls{
margin:15px auto;
}
.bet-btn, #spin{
padding:8px 16px;
margin:0 4px;
font-size:1rem;
cursor:pointer;
border:none;
border-radius:4px;
background:#555;
color:#fff;
}
.bet-btn.active{background:#0a0; color:#fff;}
.bet-btn:disabled, #spin:disabled{
background:#333;
cursor:not-allowed;
}
#paytable{
margin:20px auto;
width:90%;
max-width:500px;
border-collapse:collapse;
color:#ddd;
}
#paytable th,#paytable td{
border:1px solid #555;
padding:6px 8px;
}
#paytable th{
background:#333;
}
#paytable tr.highlight{
background:#006400;
color:#ff0;
}
#overlay{
position:fixed;
inset:0;
background:rgba(0,0,0,0.8);
display:flex;
align-items:center;
justify-content:center;
color:#fff;
font-size:2rem;
flex-direction:column;
visibility:hidden;
}
#overlay.show{visibility:visible;}
#overlay button{
margin-top:20px;
padding:10px 20px;
font-size:1rem;
cursor:pointer;
}
.gain{
position:absolute;
top:-40px;
left:50%;
transform:translateX(-50%);
font-size:2rem;
color:#ff0;
animation:gain 1.2s ease-out forwards;
pointer-events:none;
}
@keyframes gain{
0%{opacity:0; transform:translate(-50%,0);}
30%{opacity:1;}
100%{opacity:0; transform:translate(-50%,-60px);}
}
</style>
</head>
<body>
<h1>VEGAS SLOT</h1>
<div id="credits">Credits: <span id="creditVal">100</span></div>
<div id="message"></div>
<div id="reels">
<div class="reel" data-pos="0">🍒</div>
<div class="reel" data-pos="1">🍒</div>
<div class="reel" data-pos="2">🍒</div>
</div>
<div id="controls">
<button class="bet-btn" data-bet="1">1</button>
<button class="bet-btn" data-bet="5">5</button>
<button class="bet-btn" data-bet="10">10</button>
<button id="spin">SPIN</button>
</div>
<table id="paytable">
<thead>
<tr><th>Combination</th><th>× Bet</th></tr>
</thead>
<tbody>
<tr data-index="0"><td>777 (JACKPOT!)</td><td>100</td></tr>
<tr data-index="1"><td>⭐ ⭐ ⭐</td><td>50</td></tr>
<tr data-index="2"><td>🔔 🔔 🔔</td><td>20</td></tr>
<tr data-index="3"><td>🍇 🍇 🍇</td><td>15</td></tr>
<tr data-index="4"><td>🍊 🍊 🍊</td><td>10</td></tr>
<tr data-index="5"><td>🍋 🍋 🍋</td><td>5</td></tr>
<tr data-index="6"><td>🍒 🍒 🍒</td><td>3</td></tr>
<tr data-index="7"><td>🍒 🍒 (first 2)</td><td>2</td></tr>
</tbody>
</table>
<div id="overlay">
<div>GAME OVER</div>
<button id="playAgain">Play Again</button>
</div>
<script>
/* ---------- Game State ---------- */
const state = {
credits: 100,
bet: 1,
spinning: false,
symbols: ['🍒','🍋','🍊','🍇','🔔','⭐','7️⃣'],
result: [] // final symbols after a spin
};
/* ---------- DOM references ---------- */
const creditSpan = document.getElementById('creditVal');
const betButtons = document.querySelectorAll('.bet-btn');
const spinBtn = document.getElementById('spin');
const reelEls = document.querySelectorAll('.reel');
const messageEl = document.getElementById('message');
const overlay = document.getElementById('overlay');
const playAgainBtn = document.getElementById('playAgain');
const payRows = document.querySelectorAll('#paytable tbody tr');
/* ---------- Init ---------- */
function initState(){
state.credits = 100;
state.bet = 1;
state.spinning = false;
state.result = [];
updateUI();
}
initState();
/* ---------- UI helpers ---------- */
function updateCreditsDisplay(oldVal, newVal){
const diff = newVal - oldVal;
const duration = 400;
const start = performance.now();
function step(ts){
const progress = Math.min((ts-start)/duration,1);
const cur = Math.round(oldVal + diff*progress);
creditSpan.textContent = cur;
if(progress<1) requestAnimationFrame(step);
}
requestAnimationFrame(step);
}
function highlightBet(){
betButtons.forEach(b=>b.classList.toggle('active', +b.dataset.bet===state.bet));
}
function setSpinDisabled(v){
spinBtn.disabled = v;
betButtons.forEach(b=>b.disabled = v);
}
function flashReels(posArray){
posArray.forEach(i=>{
const el = reelEls[i];
el.classList.add('flash');
el.addEventListener('animationend',()=>el.classList.remove('flash'),{once:true});
});
}
function shakeReels(){
const container = document.getElementById('reels');
container.classList.add('shake');
container.addEventListener('animationend',()=>container.classList.remove('shake'),{once:true});
}
function showGain(amount){
const gain = document.createElement('div');
gain.className = 'gain';
gain.textContent = `+${amount}`;
document.getElementById('reels').appendChild(gain);
gain.addEventListener('animationend',()=>gain.remove());
}
function highlightPayRow(idx){
payRows.forEach(r=>r.classList.toggle('highlight', +r.dataset.index===idx));
}
function clearPayHighlight(){
payRows.forEach(r=>r.classList.remove('highlight'));
}
/* ---------- Pay Table ---------- */
const payTable = [
{combo:['7️⃣','7️⃣','7️⃣'], multiplier:100, name:'JACKPOT! (777)'},
{combo:['⭐','⭐','⭐'], multiplier:50, name:'THREE STARS'},
{combo:['🔔','🔔','🔔'], multiplier:20, name:'THREE BELLS'},
{combo:['🍇','🍇','🍇'], multiplier:15, name:'THREE GRAPES'},
{combo:['🍊','🍊','🍊'], multiplier:10, name:'THREE ORANGES'},
{combo:['🍋','🍋','🍋'], multiplier:5, name:'THREE LEMONS'},
{combo:['🍒','🍒','🍒'], multiplier:3, name:'THREE CHERRIES'},
{combo:['🍒','🍒','*'], multiplier:2, name:'DOUBLE CHERRY'} // * means any third
];
/* ---------- Core Functions ---------- */
function updateUI(){
// credits
creditSpan.textContent = state.credits;
// bet highlight
highlightBet();
// spin button state
spinBtn.disabled = state.spinning || state.bet>state.credits;
betButtons.forEach(b=>b.disabled = state.spinning);
// clear any message
messageEl.textContent = '';
clearPayHighlight();
}
function spin(){
if(state.spinning) return;
if(state.bet>state.credits) return;
// deduct bet
const oldCred = state.credits;
state.credits -= state.bet;
updateCreditsDisplay(oldCred, state.credits);
state.spinning = true;
setSpinDisabled(true);
// start animation
animateReels().then(res=>{
state.result = res;
const win = checkWin(res);
const winAmount = state.bet * win.multiplier;
if(win.multiplier>0){
// win
flashReels(win.positions);
messageEl.textContent = win.name;
showGain(winAmount);
const old = state.credits;
state.credits += winAmount;
updateCreditsDisplay(old, state.credits);
highlightPayRow(win.row);
}else{
// loss
messageEl.textContent = 'No win';
shakeReels();
}
state.spinning = false;
setSpinDisabled(false);
// check game over
if(state.credits===0){
overlay.classList.add('show');
}
});
}
function animateReels(){
const durations = [800,1200,1600]; // ms
const promises = Array.from(reelEls).map((el,idx)=>{
return new Promise(resolve=>{
const intervalTime = 1000/12; // ~12 symbols/sec
let interval = setInterval(()=>{
const rnd = state.symbols[Math.floor(Math.random()*state.symbols.length)];
el.textContent = rnd;
}, intervalTime);
setTimeout(()=>{
clearInterval(interval);
const final = state.symbols[Math.floor(Math.random()*state.symbols.length)];
el.textContent = final;
resolve(final);
}, durations[idx] + Math.random()*200 - 100); // slight random variation
});
});
return Promise.all(promises);
}
function checkWin(result){
// exact triple matches first
for(let i=0;i<payTable.length;i++){
const entry = payTable[i];
const combo = entry.combo;
if(combo[2]==='*'){
// double cherry case
if(result[0]==='🍒' && result[1]==='🍒'){
return {
multiplier:entry.multiplier,
name:entry.name,
positions:[0,1],
row:i
};
}
continue;
}
if(result[0]===combo[0] && result[1]===combo[1] && result[2]===combo[2]){
return {
multiplier:entry.multiplier,
name:entry.name,
positions:[0,1,2],
row:i
};
}
}
// no win
return {multiplier:0, name:null, positions:[], row:-1};
}
/* ---------- Event Listeners ---------- */
betButtons.forEach(btn=>{
btn.addEventListener('click',()=>{
if(state.spinning) return;
state.bet = +btn.dataset.bet;
updateUI();
});
});
spinBtn.addEventListener('click',spin);
playAgainBtn.addEventListener('click',()=>{
overlay.classList.remove('show');
initState();
});
</script>
</body>
</html>
```
### How it works
* **Game state** lives in a single `state` object (`credits`, `bet`, `spinning`, `symbols`, `result`).
* **UI** is built with plain HTML elements; all updates go through `updateUI()`.
* **Spinning**
* Each reel is updated ≈ 12 times / sec via `setInterval`.
* After a fixed (800 ms / 1200 ms / 1600 ms) plus a small random offset the interval stops and a final random symbol is chosen.
* The three reels run independently, creating the classic “staggered stop” effect.
* **Betting** – three buttons (1, 5, 10) set `state.bet`. The active bet is highlighted.
* **Winning** – after a spin `checkWin()` compares the three symbols to the pay‑table.
* If a win occurs the matching reels flash, a gold “+X” flies up, the win description appears, and the appropriate row in the pay‑table is highlighted.
* If nothing matches the reels shake briefly.
* **Credits** – the bet is deducted instantly, winnings are added after the animation. The credit counter animates smoothly from the old to the new value (400 ms).
* **Game‑over** – when credits hit zero, an overlay shows “GAME OVER” with a *Play Again* button that resets the state.
* **No external libraries or assets** – everything (HTML, CSS, JavaScript, emojis) is self‑contained.
Open the file in any modern browser and enjoy a tiny, fully‑functional Vegas‑style slot machine!