From d12aa6a29656ac1a94493302085c54fc4edd1439 Mon Sep 17 00:00:00 2001 From: alexander Date: Thu, 20 Nov 2025 18:42:42 +0700 Subject: [PATCH] revisi js dan css --- cliff.css | 221 ++++++++++++++++++++++++++++---- ody git.js | 370 +++++++++++++++++++++++++++++++---------------------- 2 files changed, 414 insertions(+), 177 deletions(-) diff --git a/cliff.css b/cliff.css index 613c005..4eb9aee 100644 --- a/cliff.css +++ b/cliff.css @@ -1,26 +1,197 @@ - :root{--bg:#0b1220;--card:#ffffff;--muted:#9aa6b2;--accent:#0abf5b} - *{box-sizing:border-box;font-family:Inter,ui-sans-serif,system-ui,Segoe UI,Roboto,Arial} - body{margin:0;min-height:100vh;background:linear-gradient(180deg,#08101a 0%, #0c1620 100%);color:var(--card);display:flex;align-items:center;justify-content:center;padding:24px} - .table{width:960px;max-width:98vw;background:linear-gradient(180deg,#072029,#0a2530);border-radius:14px;padding:20px;box-shadow:0 10px 40px rgba(2,6,12,.6)} - header{display:flex;align-items:center;justify-content:space-between;margin-bottom:12px} - header h1{font-size:20px;margin:0} - .controls{display:flex;gap:10px;align-items:center} +/* ============================== + BASE TABLE LAYOUT +================================*/ +body { + margin: 0; + padding: 0; + background: #0b6528; + font-family: Arial, sans-serif; + color: white; + display: flex; + justify-content: center; +} - .info{display:flex;gap:12px;align-items:center} - .chip{background:#072a1f;padding:8px 12px;border-radius:12px;color:var(--muted);font-weight:600} - .bet{display:flex;gap:8px;align-items:center} - input[type=number]{width:90px;padding:6px;border-radius:8px;border:1px solid rgba(255,255,255,.06);background:transparent;color:var(--card)} - button{background:var(--accent);border:none;padding:8px 12px;border-radius:10px;font-weight:700;color:#02220f;cursor:pointer} - button.secondary{background:transparent;border:1px solid rgba(255,255,255,.06);color:var(--card)} - main{display:grid;grid-template-columns:1fr 1fr;gap:14px} - .board{padding:14px;background:linear-gradient(180deg, rgba(255,255,255,.02), rgba(255,255,255,.01));border-radius:12px;min-height:220px} - .section-title{color:var(--muted);font-size:12px;margin-bottom:6px} - .hand{display:flex;gap:10px;align-items:flex-end} - .card{width:86px;height:120px;border-radius:8px;background:white;color:#000;display:flex;flex-direction:column;justify-content:space-between;padding:8px;font-weight:800;box-shadow:0 6px 18px rgba(0,0,0,.35)} - .card.red{color:#b22222} - .card.back{background:linear-gradient(180deg,#0a76b9,#094e7a);color:#fff;font-weight:700;display:flex;align-items:center;justify-content:center} - .values{margin-top:8px;color:var(--muted);font-weight:700} - .actions{display:flex;gap:8px;margin-top:12px} - .message{margin-top:10px;color:var(--muted)} - footer{margin-top:12px;text-align:center;color:var(--muted);font-size:13px} - @media(max-width:700px){.hand{overflow:auto;padding-bottom:8px}.card{min-width:72px;width:72px;height:100px}} +.table { + width: 900px; + margin-top: 20px; + background: #134b2f; + padding: 20px; + border-radius: 15px; + box-shadow: 0 0 20px #000a; +} + +header { + text-align: center; + margin-bottom: 20px; +} + +.controls { + display: flex; + justify-content: space-between; + margin-top: 10px; +} + +.info { + display: flex; + gap: 15px; +} + +.chip { + background: #222; + padding: 8px 14px; + border-radius: 10px; + font-weight: bold; +} + +.bet { + display: flex; + gap: 10px; +} + +.bet input { + width: 80px; + padding: 6px; + font-size: 16px; + border-radius: 6px; + border: none; +} + +button { + padding: 7px 14px; + font-size: 16px; + border: none; + background: #28a745; + color: white; + border-radius: 8px; + cursor: pointer; +} + +button.secondary { + background: #dc3545; +} + +button:hover { + filter: brightness(1.15); +} + +/* ============================== + MAIN BOARD +================================*/ + +main { + display: flex; + justify-content: space-between; +} + +.board { + width: 48%; + background: #0d3d23; + padding: 15px; + border-radius: 15px; + text-align: center; + box-shadow: inset 0 0 10px #000a; +} + +.section-title { + font-size: 24px; + margin-bottom: 10px; + font-weight: bold; +} + +/* ============================== + CARDS +================================*/ + +.hand { + display: flex; + justify-content: center; + gap: 10px; + min-height: 120px; + margin-bottom: 10px; +} + +.card { + width: 70px; + height: 100px; + background: white; + color: black; + border-radius: 10px; + display: flex; + flex-direction: column; + justify-content: space-between; + padding: 8px; + font-size: 20px; + box-shadow: 0 0 5px #000; +} + +.card.red { + color: red; +} + +.card.back { + background: #222; + color: white; + display: flex; + align-items: center; + justify-content: center; +} + +.values { + font-size: 20px; + margin-top: 5px; + font-weight: bold; +} + +/* ============================== + ACTION BUTTONS +================================*/ + +.actions { + margin-top: 10px; + display: flex; + justify-content: center; + gap: 15px; +} + +/* ============================== + MESSAGE (WIN/LOSE) +================================*/ + +#message { + font-size: 28px; + font-weight: bold; + margin-top: 15px; + min-height: 40px; + text-shadow: none; +} + +/* WIN EFFECT */ +.win { + color: #00ff55; + animation: glowWin 1s ease-in-out infinite alternate; +} + +@keyframes glowWin { + from { text-shadow: 0 0 10px #00ff55; } + to { text-shadow: 0 0 20px #55ff88; } +} + +/* LOSE EFFECT */ +.lose { + color: #ff3333; + animation: glowLose 1s ease-in-out infinite alternate; +} + +@keyframes glowLose { + from { text-shadow: 0 0 10px #ff3333; } + to { text-shadow: 0 0 20px #ff7777; } +} + +/* TIE (no class = normal text) */ + +footer { + margin-top: 20px; + text-align: center; + opacity: .8; + font-size: 14px; +} diff --git a/ody git.js b/ody git.js index c63272f..241e76e 100644 --- a/ody git.js +++ b/ody git.js @@ -1,171 +1,237 @@ - // Simple Blackjack implementation - const SUITS = ['♠','♥','♦','♣']; - const RANKS = ['A','2','3','4','5','6','7','8','9','10','J','Q','K']; +// SET MESSAGE (WIN/LOSE) +function setMessage(text, status){ + messageEl.textContent = text; + messageEl.className = status; // 'win', 'lose', atau '' (tie) +} - // DOM - const dealerHandEl = document.getElementById('dealer-hand'); - const playerHandEl = document.getElementById('player-hand'); - const dealerValueEl = document.getElementById('dealer-value'); - const playerValueEl = document.getElementById('player-value'); - const balanceEl = document.getElementById('balance'); - const betInput = document.getElementById('bet-input'); - const betBtn = document.getElementById('bet-btn'); - const currentBetEl = document.getElementById('current-bet'); - const hitBtn = document.getElementById('hit'); - const standBtn = document.getElementById('stand'); - const doubleBtn = document.getElementById('double'); - const newRoundBtn = document.getElementById('new-round'); - const messageEl = document.getElementById('message'); +// Simple Blackjack implementation +const SUITS = ['♠','♥','♦','♣']; +const RANKS = ['A','2','3','4','5','6','7','8','9','10','J','Q','K']; - let deck = []; - let dealer = []; - let player = []; - let dealerHidden = true; - let balance = 1000; - let currentBet = 0; - let inRound = false; +// DOM +const dealerHandEl = document.getElementById('dealer-hand'); +const playerHandEl = document.getElementById('player-hand'); +const dealerValueEl = document.getElementById('dealer-value'); +const playerValueEl = document.getElementById('player-value'); +const balanceEl = document.getElementById('balance'); +const betInput = document.getElementById('bet-input'); +const betBtn = document.getElementById('bet-btn'); +const currentBetEl = document.getElementById('current-bet'); +const hitBtn = document.getElementById('hit'); +const standBtn = document.getElementById('stand'); +const doubleBtn = document.getElementById('double'); +const newRoundBtn = document.getElementById('new-round'); +const messageEl = document.getElementById('message'); - function makeDeck(){ - deck = []; - for(const s of SUITS){ - for(const r of RANKS){ - deck.push({suit:s,rank:r}); - } - } +let deck = []; +let dealer = []; +let player = []; +let dealerHidden = true; +let balance = 1000; +let currentBet = 0; +let inRound = false; + +function makeDeck(){ + deck = []; + for(const s of SUITS){ + for(const r of RANKS){ + deck.push({suit:s,rank:r}); + } + } +} + +function shuffle(){ + for(let i=deck.length-1;i>0;i--){ + const j = Math.floor(Math.random()*(i+1)); + [deck[i],deck[j]] = [deck[j],deck[i]]; + } +} + +function cardValue(card){ + const r = card.rank; + if(r==='A') return [1,11]; + if(['J','Q','K'].includes(r)) return [10]; + return [parseInt(r,10)]; +} + +function handValues(hand){ + let totals = [0]; + for(const c of hand){ + const vals = cardValue(c); + const newTotals = []; + for(const t of totals){ + for(const v of vals){ newTotals.push(t+v); } + } + totals = Array.from(new Set(newTotals)); + } + const valid = totals.filter(t=>t<=21); + if(valid.length) return Math.max(...valid); + return Math.min(...totals); +} + +function renderHand(el,hand,hideFirst=false){ + el.innerHTML=''; + hand.forEach((c,i)=>{ + const div = document.createElement('div'); + div.className='card'+(c.suit==='♥'||c.suit==='♦'?' red':''); + + if(hideFirst && i===0){ + div.className='card back'; + div.textContent='TERSEMBUNYI'; + } else { + const top = document.createElement('div'); + top.textContent = c.rank + ' ' + c.suit; + const bot = document.createElement('div'); + bot.style.alignSelf='flex-end'; + bot.textContent = c.rank + ' ' + c.suit; + div.appendChild(top); + div.appendChild(bot); } - function shuffle(){ - for(let i=deck.length-1;i>0;i--){ - const j = Math.floor(Math.random()*(i+1)); - [deck[i],deck[j]] = [deck[j],deck[i]]; - } + el.appendChild(div); + }); +} + +function updateUI(){ + renderHand(dealerHandEl,dealer,dealerHidden); + renderHand(playerHandEl,player,false); + dealerValueEl.textContent = dealerHidden ? '??' : 'Nilai: '+handValues(dealer); + playerValueEl.textContent = 'Nilai: '+handValues(player); + balanceEl.textContent = balance; + currentBetEl.textContent = currentBet; +} + +function startRound(){ + if(inRound) return; + + const bet = Number(betInput.value) || 0; + if(bet <=0 || bet > balance){ alert(' BANK TIDAK CUKUP! '); return; } + + currentBet = bet; + balance -= bet; + inRound=true; + dealerHidden=true; + + setMessage('', ''); // RESET MESSAGE + + makeDeck(); shuffle(); + dealer = [deck.pop(), deck.pop()]; + player = [deck.pop(), deck.pop()]; + + updateUI(); + + // NATURAL BLACKJACK + if(handValues(player)===21){ + dealerHidden=false; + updateUI(); + const dealerVal = handValues(dealer); + + if(dealerVal===21){ + balance += currentBet; + setMessage('Tie (seri).', ''); + } else { + const payout = Math.floor(currentBet * 2.5); + balance += payout; + setMessage('Blackjack! You Win!', 'win'); } - function cardValue(card){ - const r = card.rank; - if(r==='A') return [1,11]; - if(['J','Q','K'].includes(r)) return [10]; - return [parseInt(r,10)]; - } + inRound=false; + currentBet=0; + updateUI(); + } +} - function handValues(hand){ - // returns best value <=21 or smallest if bust - let totals = [0]; - for(const c of hand){ - const vals = cardValue(c); - const newTotals = []; - for(const t of totals){ - for(const v of vals){ newTotals.push(t+v); } - } - totals = Array.from(new Set(newTotals)); - } - // separate <=21 and >21 - const valid = totals.filter(t=>t<=21); - if(valid.length) return Math.max(...valid); - return Math.min(...totals); - } +function playerHit(){ + if(!inRound) return; - function renderHand(el,hand,hideFirst=false){ - el.innerHTML=''; - hand.forEach((c,i)=>{ - const div = document.createElement('div'); - div.className='card'+(c.suit==='♥'||c.suit==='♦'?' red':''); - if(hideFirst && i===0){ div.className='card back'; div.textContent='TERSEMBUNYI'; } - else{ - const top = document.createElement('div'); top.textContent = c.rank + ' ' + c.suit; // top-left - const bot = document.createElement('div'); bot.style.alignSelf='flex-end'; bot.textContent = c.rank + ' ' + c.suit; // bottom-right - div.appendChild(top); div.appendChild(bot); - } - el.appendChild(div); - }); - } + player.push(deck.pop()); + updateUI(); - function updateUI(){ - renderHand(dealerHandEl,dealer,dealerHidden); - renderHand(playerHandEl,player,false); - dealerValueEl.textContent = dealerHidden ? '??' : 'Nilai: '+handValues(dealer); - playerValueEl.textContent = 'Nilai: '+handValues(player); - balanceEl.textContent = balance; - currentBetEl.textContent = currentBet; - } + if(handValues(player) > 21){ + dealerHidden=false; + setMessage('Bust! You Lose!', 'lose'); + inRound=false; + currentBet=0; + updateUI(); + } +} - function startRound(){ - if(inRound) return; - const bet = Number(betInput.value) || 0; - if(bet <=0 || bet > balance){ alert(' BANK TIDAK CUKUP! '); return; } - currentBet = bet; balance -= bet; inRound=true; dealerHidden=true; messageEl.textContent=''; +function playerStand(){ + if(!inRound) return; - makeDeck(); shuffle(); - dealer = [deck.pop(), deck.pop()]; - player = [deck.pop(), deck.pop()]; + dealerHidden=false; - // Check for natural blackjack - updateUI(); - if(handValues(player)===21){ - dealerHidden=false; updateUI(); - const dealerVal = handValues(dealer); - if(dealerVal===21){ // push - balance += currentBet; messageEl.textContent = 'Tie (seri). Taruhan dikembalikan.'; - } else { - // player blackjack 3:2 - const payout = Math.floor(currentBet * 2.5); - balance += payout; messageEl.textContent = 'Blackjack! You Win.'; - } - inRound=false; currentBet=0; updateUI(); - } else { - updateUI(); - } - } + while(handValues(dealer)<17){ + dealer.push(deck.pop()); + } - function playerHit(){ - if(!inRound) return; player.push(deck.pop()); updateUI(); - const val = handValues(player); - if(val>21){ // bust - dealerHidden=false; messageEl.textContent='Bust! Dealer Win!'; inRound=false; currentBet=0; updateUI(); - } - } + const pv = handValues(player); + const dv = handValues(dealer); - function playerStand(){ - if(!inRound) return; dealerHidden=false; // reveal dealer - // dealer plays - while(handValues(dealer)<17){ dealer.push(deck.pop()); } - const pv = handValues(player); const dv = handValues(dealer); - if(dv>21 || pv>dv){ // player wins - const payout = currentBet*2; balance += payout; messageEl.textContent='You Win!'; - } else if(pv===dv){ // push - balance += currentBet; messageEl.textContent='Tie (seri).'; - } else { messageEl.textContent='Dealer Win!'; } - inRound=false; currentBet=0; updateUI(); - } + if(dv>21 || pv>dv){ + balance += currentBet*2; + setMessage('You Win!', 'win'); - function playerDouble(){ - if(!inRound) return; - if(balance < currentBet){ alert('Bank tidak cukup untuk double.'); return; } - // double: take exactly one card then stand - balance -= currentBet; currentBet = currentBet*2; player.push(deck.pop()); updateUI(); - const val = handValues(player); - if(val>21){ dealerHidden=false; messageEl.textContent='Bust setelah double. Dealer Win!'; inRound=false; currentBet=0; updateUI(); return; } - playerStand(); - } + } else if(pv===dv){ + balance += currentBet; + setMessage('Tie (seri).', ''); - // Events - betBtn.addEventListener('click', startRound); - hitBtn.addEventListener('click', playerHit); - standBtn.addEventListener('click', playerStand); - doubleBtn.addEventListener('click', playerDouble); - newRoundBtn.addEventListener('click', ()=>{ - // reset everything - if(inRound){ if(!confirm('Masih dalam ronde. Ingin reset?')) return; } - balance = 1000; currentBet=0; inRound=false; dealer=[]; player=[]; deck=[]; dealerHidden=true; messageEl.textContent='Bank di-reset.'; updateUI(); - }); + } else { + setMessage('You Lose!', 'lose'); + } - // keyboard shortcuts - window.addEventListener('keydown', e=>{ - if(e.key==='h') playerHit(); - if(e.key==='s') playerStand(); - if(e.key==='d') playerDouble(); - if(e.key==='Enter') startRound(); - }); + inRound=false; + currentBet=0; + updateUI(); +} - // initial UI - updateUI(); \ No newline at end of file +function playerDouble(){ + if(!inRound) return; + if(balance < currentBet){ alert('Bank tidak cukup untuk double.'); return; } + + balance -= currentBet; + currentBet *= 2; + + player.push(deck.pop()); + updateUI(); + + if(handValues(player)>21){ + dealerHidden=false; + setMessage('Bust! You Lose!', 'lose'); + inRound=false; + currentBet=0; + updateUI(); + return; + } + + playerStand(); +} + +// EVENTS +betBtn.addEventListener('click', startRound); +hitBtn.addEventListener('click', playerHit); +standBtn.addEventListener('click', playerStand); +doubleBtn.addEventListener('click', playerDouble); + +newRoundBtn.addEventListener('click', ()=>{ + if(inRound && !confirm('Masih dalam ronde. Reset?')) return; + balance = 1000; + currentBet=0; + inRound=false; + dealer=[]; + player=[]; + deck=[]; + dealerHidden=true; + setMessage('Bank di-reset.', ''); + updateUI(); +}); + +// KEYBOARD +window.addEventListener('keydown', e=>{ + if(e.key==='h') playerHit(); + if(e.key==='s') playerStand(); + if(e.key==='d') playerDouble(); + if(e.key==='Enter') startRound(); +}); + +updateUI();