mager-bench

GPT-OSS 120B × slots

0.7

Vegas 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 addEventListener

run 1 of 1

0.7
correctness 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!