Skip to content

Instantly share code, notes, and snippets.

@gurjeet
Created December 2, 2017 15:45
Show Gist options
  • Save gurjeet/771e9493b744963c0a6b72086f924775 to your computer and use it in GitHub Desktop.
Save gurjeet/771e9493b744963c0a6b72086f924775 to your computer and use it in GitHub Desktop.
Bet on Coin Flip
<div class='coin-flip'>
<!-- The tail starts out hidden; we don't want to wait until CSS rule evaluation to hide this image -->
<div id='coin-tails' style='display:none'>
<img src='https://upload.wikimedia.org/wikipedia/commons/thumb/d/da/US_One_Cent_Rev.png/240px-US_One_Cent_Rev.png'>
</div>
<div id='coin-heads'>
<img src='https://upload.wikimedia.org/wikipedia/commons/thumb/2/2e/US_One_Cent_Obv.png/240px-US_One_Cent_Obv.png'>
</div>
</div>
<div id='controls'>
Balance <div id='div-balance'></div>
<div id='buttons'>
<button id='btn-heads' onclick=flip('heads')>Heads</button>
<button id='btn-tails' onclick=flip('tails')>Tails</button>
</div>
<div id='div-result'></div>
</div>
<div id='div-debuginfo'></div>
/*
DONE:
1. Build basic UI for a coin-flipping game
1. Buy honestcasino.com
==========================================================
TODO:
1. Customer feedback mechanism
1. Announce on forums (Reddit/poker, Show HN, others)
1. NoSleep for phone browsers
0. Keyboard shortcuts (h,H=>Heads, t,T=> Tails)
2. Flipping Sound
3. Winning sound
*/
var result = 'heads';
var chosen = result;
var headClass = 'coin-heads';
var tailClass = 'coin-tails';
var balance;
var coinState;
const betUnit = 25;
const DGEBI = document.getElementById.bind(document);
var imgHead = DGEBI(headClass);
var imgTail = DGEBI(tailClass);
var btnHeads = DGEBI('btn-heads');
var btnTails = DGEBI('btn-tails');
var divResult = DGEBI('div-result');
var divBalance = DGEBI('div-balance');
var divDebugInfo = DGEBI('div-debuginfo');
/* Init game state; this function is intentionally unnamed, executed using IIFE */
(function(){
balance = 2500;
coinState = 'stopped';
divBalance.innerHTML = balance;
})();
function serverGetRandomByte(callback) {
var val = randomIntInc(0,255); // mimic NodeJS' `crypto.randomBytes(1)`
setTimeout(function() {callback(val)}, 1000 * randomIntInc(1,3))
}
// Returns a random number in range [low,high]; that is, both ends of the range are inclusive
function randomIntInc (low, high) {
return Math.floor(Math.random() * (high - low + 1) + low);
}
function flip(p) {
chosen = p
startSpinning();
}
/*function toggleSpinning(){if(coinState==='spinning')stopSpinning();}else{startSpinning();}}*/
document.onkeypress = function(e){detectKeyPress(e)};
function detectKeyPress(e) {
const key = e.key;
if (key === 'h' || key === 'H') {
flip('heads')
} else if (key === 't' || key === 'T') {
flip('tails')
} else if (key === 'd') {
divDebugInfo.style.display = 'none';
} else if (key === 'D') {
divDebugInfo.style.display = 'block';
}
}
function updateResult() {
divResult.innerHTML = result;
if (debug) {
divDebugInfo.innerHTML = debugText;
} else {
divDebugInfo.innerHTML = '';
}
}
function startSpinning() {
if (coinState === 'spinning')
return;
coinState = 'spinning';
balance = balance - betUnit;
result = '?'
updateResult();
divBalance.innerHTML = balance;
btnHeads.disabled = btnTails.disabled = true;
imgHead.classList.add(headClass);
imgTail.classList.add(tailClass);
imgHead.style.display = imgTail.style.display = 'block';
serverGetRandomByte(stopSpinning);
}
function stopSpinning(val) {
if (coinState === 'stopped')
return;
coinState = 'stopped';
btnHeads.disabled = btnTails.disabled = false;
imgHead.classList.remove(headClass);
imgTail.classList.remove(tailClass);
if (val % 51 === 0) {
/* The coin landed on edge; This is also the house-edge. */
result = "edge";
} else if (val % 2 === 0) {
result = "heads";
} else {
result = "tails";
}
if (result === "edge") {
divResult.innerHTML = 'Edge!!!';
} else if (result == chosen) {
balance = balance + (2 * betUnit);
divResult.innerHTML = 'You won!!!';
} else {
divResult.innerHTML = 'You lost :-(';
}
divBalance.innerHTML = balance;
if (result === 'edge') {
imgTail.style.display = 'none';
imgHead.style.display = 'none';
} else if (result === "heads") {
imgTail.style.display = 'none';
} else {
imgHead.style.display = 'none';
}
// Debugging code
if (debug) {
iter = iter + 1;
if (balance < lowBalance) lowBalance = balance;
if (balance > highBalance) highBalance = balance;
if (result === 'edge') edges = edges + 1;
else if (result === 'heads') heads = heads + 1;
else if (result === 'tails') tails = tails + 1;
if (result === chosen) correctGuesses = correctGuesses +1;
else wrongGuesses = wrongGuesses +1;
debugText = `<table id='debuginfo'>`
+`<tr><td>Random value</td><td>${val}</td></tr>`
+`<tr><td>Total flips</td><td>${iter}</td></tr>`
+`<tr><td>Landed on edge</td><td>${edges}</td></tr>`
+`<tr><td>Landed on heads</td><td>${heads}</td></tr>`
+`<tr><td>Landed on tails</td><td>${tails}</td></tr>`
+`<tr><td>Correct guesses</td><td>${correctGuesses}</td></tr>`
+`<tr><td>Wrong guesses</td><td>${wrongGuesses}</td></tr>`
+`<tr><td>Low balance</td><td>${lowBalance}</td></tr>`
+`<tr><td>High balance</td><td>${highBalance}</td></tr>`
+`</table>`;
updateResult();
//setTimeout(function(){btnTails.click()}, 500)
}
}
var debug = false;
var debugText = '';
var iter = 0;
var edges = 0;
var heads = 0;
var tails = 0;
var correctGuesses = 0;
var wrongGuesses = 0;
var lowBalance = balance;
var highBalance = balance;
body {
/* Seerat picked this colour (using arbitrary values for RGB), and I like it! */
background-color: rgb(255,100,90);
overflow: hidden;
}
.coin-flip {
/* border: 1px solid red; */
position: absolute;
margin: auto;
width: 100px;
height: 100px;
left: 0;
right: 0;
transform-style: preserve-3d;
animation: - 1.5s ease-in-out 0s infinite alternate;
}
#controls {
/* border: 1px solid blue; */
position: absolute;
text-align: center;
margin: auto;
top: 110px;
/* TODO: Figure out how to auto-center this div, rather than the 3-line hack that follows */
width: 130px;
left: 0;
right: 0;
}
#div-debuginfo{
top: 170px;
position: absolute;
margin: auto;
width: 250px;
left: 0;
right: 0;
}
#div-balance {
display: inline-block;
}
.coin-flip img {
width: 100px;
}
.coin-heads, .coin-tails {
backface-visibility: hidden;
position: absolute;
top: 0;
left: 0;
}
.coin-heads{
animation: flip-head .1s linear 0s infinite alternate;
}
.coin-tails{
animation: flip-tail .1s linear 0s infinite alternate;
}
@keyframes fly {
0% { top: 100%; }
100% { top: 0%; }
}
@keyframes flip-head {
0%, 100% { transform: rotateX(0deg); }
50% { transform: rotateX(180deg); }
}
@keyframes flip-tail {
0%, 100% { transform: rotateX(180deg); }
50% { transform: rotateX(0deg); }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment