Last active
August 11, 2017 13:01
-
-
Save yoongi0428/bb9a65d8c75ced4128e60f698c9c17a7 to your computer and use it in GitHub Desktop.
Bytesjack App.js with Korean comments
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* BytesJack <https://github.com/EtienneLem/bytesjack> | |
* | |
* Dev Etienne Lemay <http://twitter.com/#!/EtienneLem> | |
* Design Tristan L'abbé <http://twitter.com/#!/_Tristan> | |
* | |
* Special thanks to rafBM <http://twitter.com/#!/rafbm> for some JS tricks! | |
*/ | |
// Static class hack (auto init) | |
// 페이지 Document Object Model (DOM)이 준비가 되어 JS가 실행 될 때 처음 한번 실행 | |
// window 객체의 App이라는 속성으로 'App' 객체를 instantiate 한다. | |
$(document).ready(function(){ window.App = new App() }); | |
// Class | |
// App 객체는 App 객체가 갖고있는 initialize 메소드를 (App 자신과, 객체들)을 인자로 던져 실행한다. | |
var App = function() { this.initialize.apply(this, arguments) }; | |
// App 객체의 프로토타입 | |
App.prototype = (function() { var pro = {}; // pro 라는 빈 객체 | |
// Contants | |
var ANIM_DELAY = 300, //(추측) Animation delay 300 | |
KEY_SPACE = 32, // 각 키에 해당하는 코드 | |
KEY_S = 83, | |
KEY_D = 68, | |
KEY_1 = 49, | |
KEY_2 = 50, | |
KEY_3 = 51, | |
PATTERNS = [ // 카드 갯수에 따른 rotate 패턴배열 (배열의 i번째는 카드가 i+1개일 때, 순서대로 i+1개의 카드 rotate css를 나타난다) | |
[{deg: 0, top: 0}], | |
[{deg: 5, top: 0}, {deg: -5, top: 0}], | |
[{deg: 5, top: 15}, {deg: -1, top: 0}, {deg: -5, top: 15}], | |
[{deg: 9, top: 20}, {deg: 4, top: 0}, {deg: -4, top: 0}, {deg: -9, top: 15}], | |
[{deg: 12, top: 50}, {deg: 8, top: 10}, {deg: -4, top: 0}, {deg: -12, top: 15}, {deg: -16, top: 40}], | |
[{deg: 14, top: 40}, {deg: 8, top: 10}, {deg: -2, top: 5}, {deg: -5, top: 15}, {deg: -8, top: 40}, {deg: -14, top: 70}], | |
[{deg: 14, top: 70}, {deg: 8, top: 30}, {deg: 4, top: 10}, {deg: 0, top: 5}, {deg: -4, top: 20}, {deg: -8, top: 40}, {deg: -16, top: 70}] | |
]; | |
// Variables | |
var types = ['clubs', 'diamonds', 'hearts', 'spades'], // 카드 문양 | |
cards = [], // 판에 놓인 카드들 (1~11) | |
cardsIndex = 0, // | |
isPlaying = false, // 게임 진행중 | |
gameDealed = false, // 게임이 적어도 한번 이상 play 됐다. | |
dealNav = $('#deal'), // html에서 id="deal"을 가져온다. (deal 버튼) | |
actionsNav = $('#actions'), // html에서 id="actions"을 가져온다. (hit, stand, double 버튼) | |
doubleBtn = $('#double'), // html에서 id="double" 를 가져온다 (double 버튼) | |
pCardsContainer = $('#player-cards'), // player 카드들 | |
dCardsContainer = $('#dealer-cards'), // dealer 카드들 | |
playerTotal = $('#player-total'), // player 점수 총합 | |
playerCards = [], // player 카드 | |
playerAces = 0, // player 'A' 갯수 | |
dealerTotal = $('#dealer-total'), // dealer 점수 총합 | |
dealerCards = [], // dealer 카드 | |
dealerAces = 0, // dealer 'A' 갯수 | |
chips = $('#chips'), // id = "chips" div (칩 div 3개를 감싸고 있다) | |
allChips = $('.chip'), // chip 클래스를 가진 3 div들 ( chips안에 allChips가 들어있다 ) | |
bank = 100, // 잔고 | |
bankroll = $('#bankroll'), // 잔고 표시 부분 <div> | |
doubled = false, // double을 했는가 | |
currentBet = allChips.first().data('value'), // 현재 베팅 금액 (항상 현재 베팅 금액이 chip 클래스 중 첫번째다) | |
resizeTimer = null, // 카드 패를 0.1초 뒤에 중앙 정렬 하는 타이머함수 | |
canDoAction = true, // 행동 가능 | |
isStanding = false, // Stand 중인가 | |
gameEnded = false, // 게임 끝 | |
html = $('html'); // html 통째로 가져오기 | |
// public (실제로 접근이 가능한 메소드, App.deal(), App.hit()...) | |
pro.initialize = function(opts) { initialize() }; // pro 객체의 intialize = App.prototype.initialize() | |
pro.deal = function() { deal() }; // pro 객체의 deal = App.prototype.deal() | |
pro.hit = function() { hit() }; // pro 객체의 hit = App.prototype.hit() | |
pro.stand = function() { stand() }; // pro 객체의 stand = App.prototype.stand() | |
pro.doubledown = function() { doubledown() }; // pro 객체의 doubledown = App.prototype.doubledown() | |
// private (실제로 접근이 불가능한 감춰진 메소드) | |
// App.prototype 은 이 긴 함수 표현식의 실행된 결과를 갖게되는데 큰 틀에서 보면 | |
// 결국 표현식은 마지막에 return pro를 하고 App.prototype은 pro 객체를 갖게된다. | |
// pro객체의 메소드는 위의 5개고 실제로 저것들만이 App을 상속받는 객체의 메소드가 된다. | |
var initialize = function() | |
{ | |
$('a[href="#"]').bind('click', function(e){ e.preventDefault(); }); // a태그 중 href="#"인 모든 태그를 클릭하되 페이지 이동을 하지 않도록 한다. | |
initBet(); // Bet 초기화 | |
initResize(); // 화면 초기화 | |
initKeyboardKeys(); // | |
setTimeout(function(){ | |
window.scrollTo(0, 1) | |
}, 500); | |
} | |
// Resize management | |
var initResize = function() | |
{ | |
$(window).bind('resize', onWindowResize); | |
onWindowResize(null); | |
}; | |
var onWindowResize = function ( e ) | |
{ | |
clearTimeout(resizeTimer); // resizeTimer를 중지시킨다. | |
resizeTimer = setTimeout(function(){ // 0.1초 뒤 centerContainers() 실행하는 타이머 resizeTimer | |
centerContainers(); | |
}, 100); | |
}; | |
// Keyboard managment | |
var initKeyboardKeys = function() { | |
$(document).bind('keydown', onKeyDown); // key를 눌렀을 때 | |
$(document).bind('keyup', onKeyUp); // key를 뗐을 때 | |
}; | |
var onKeyDown = function ( e ) // 키보드 눌렸을 때 | |
{ | |
switch ( e.keyCode ) { | |
case KEY_SPACE : | |
( isPlaying ) | |
? actionsNav.children('li:first-child').children('a').addClass('active') // 플레이 중이면 첫번째 li(hit)의 a 태그에 active 클래스 추가 | |
: dealNav.children('a').addClass('active'); // 플레이 중이 아니면 deal 의 a 태그에 active 클래스 추가 | |
break; | |
case KEY_S : actionsNav.children('li:nth-child(2)').children('a').addClass('active'); break; // 두번째 li(stand)의 a태그에 active 클래스 추가 | |
case KEY_D : actionsNav.children('li:nth-child(3)').children('a').addClass('active'); break; // 세번째 li(double)의 a태그에 active 클래스 추가 | |
case KEY_1 : selectChip(0); break; // 100b 선택 | |
case KEY_2 : selectChip(1); break; // 500b 선택 | |
case KEY_3 : selectChip(2); break; // 1k 선택 | |
} | |
}; | |
var onKeyUp = function ( e ) // 키보드 뗐을 때 | |
{ | |
e.preventDefault(); // 브라우저의 기본 동작 중지 | |
switch ( e.keyCode ) { | |
case KEY_SPACE : | |
if ( isPlaying ) { | |
hit(); | |
actionsNav.children('li:first-child').children('a').removeClass('active') | |
} else { | |
deal(); | |
dealNav.children('a').removeClass('active'); | |
} | |
case KEY_S : | |
stand(); | |
actionsNav.children('li:nth-child(2)').children('a').removeClass('active'); | |
break; | |
case KEY_D : | |
doubledown(); | |
actionsNav.children('li:nth-child(3)').children('a').removeClass('active'); | |
break; | |
case KEY_1 : selectChip(0); break; | |
case KEY_2 : selectChip(1); break; | |
case KEY_3 : selectChip(2); break; | |
} | |
}; | |
var selectChip = function ( index ) | |
{ | |
if ( isPlaying || gameEnded ) return; // 플레이 중 이거나 게임이 끝났으면 함수 종료 | |
allChips.eq(index).trigger('click'); // index 번째 chip click 이벤트 발생 (이 말은 allChips 는 항상 100b 500b 1k 순 이라는 말?) | |
}; | |
// Cards management | |
var initDeck = function() | |
{ | |
for ( var i = 0; i < types.length; i++ ) { | |
for ( var j = 1; j <= 13; j++ ) { | |
var value = ( j > 10 ) ? 10 : j; | |
cards.push({ card:j, value: value, type: types[i] }); | |
}; | |
} // 모든 종류의 카드를 cards에 넣고 | |
cards.shuffle(); // 섞어 | |
}; | |
// side - 'front' 'back' 앞 뒤 | |
// player - 'player' 'dealer' | |
// callback - 콜백 | |
var addCard = function ( side, player, callback ) | |
{ | |
var cardData = cards[cardsIndex], // ? | |
container = ( player == 'player' ) ? pCardsContainer : dCardsContainer, // 플레이어 or 딜러 카드 컨테이너(div) 선택 | |
card = buildCard(cardsIndex, cardData.type, cardData.card, side), // cardsIndex번째 카드, type문양, card 숫자, side(앞,뒤) | |
zIndex = 0; | |
cardsIndex++; | |
canDoAction = false; // 동작 불가 | |
// 카드 스타일 css | |
card.css({ | |
'top' : '-150%', | |
'left' : '100%' | |
}); | |
// card를 패에 추가 | |
container.append(card); | |
zIndex = ( player == 'player' ) ? card.index() : 50-card.index(); // z-index ? | |
card.css('z-index', zIndex); | |
setTimeout(function(){ | |
card.css({ | |
'top' : '0%', | |
'left' : 10 * card.index() + '%' | |
}); | |
rotateCards(container, (player == 'player')); // 카드를 보기 좋게 rotate | |
setTimeout(function(){ | |
centerContainer(container); // 패를 중앙에 | |
if ( player == 'player' ) addToPlayerTotal(cardData.value); // 새로 추가한 카드를 플레이어 수의 더함. | |
else addToDealerTotal(cardData.value); | |
canDoAction = true; // 이제부터 다시 동작 가능 | |
if ( callback != undefined ) callback.call(); // callback이 있으면 실행 | |
}, ANIM_DELAY + 100); // ANIM_DELAY + 0.1초가 지난 후 animation 실행 | |
}, 10); // 0.01초 delay 후 outer setTimeOut 실행 | |
}; | |
var rotateCards = function ( container, isPlayer ) | |
{ | |
var cards = container.children('.card'), //컨테이너 안에 card div들 | |
numCards = cards.size() - 1, // 배열 길이 - 1 = 카드 수 - 1 = 마지막 카드의 index | |
increment = ( isPlayer ) ? -1 : 1, // player 카드면 -1, dealer 카드면 1 | |
pattern = ( PATTERNS[numCards] ) ? PATTERNS[numCards] : PATTERNS[PATTERNS.length-1]; | |
// 카드 수에 맞는 패턴이 있으면 그걸로 하고 아니면 맨 마지막 패턴 (제일 많은 경우로) | |
cards.each(function(i){ | |
var deg = ( i < pattern.length ) ? pattern[i].deg : pattern[pattern.length-1].deg, | |
offset = ( i < pattern.length ) ? pattern[i].top : pattern[pattern.length-1].top + (20 * (i - pattern.length + 1)); | |
$(this).css({ | |
'-webkit-transform' : 'rotate('+ deg * increment +'deg)', | |
'-khtml-transform' : 'rotate('+ deg * increment +'deg)', | |
'-moz-transform' : 'rotate('+ deg * increment +'deg)', | |
'-ms-transform' : 'rotate('+ deg * increment +'deg)', | |
'transform' : 'rotate('+ deg * increment +'deg)', | |
'top' : offset * -increment + 'px' | |
}); | |
}); | |
}; | |
var centerContainers = function() | |
{ | |
centerContainer(pCardsContainer); | |
centerContainer(dCardsContainer); | |
}; | |
var centerContainer = function ( container ) | |
{ | |
var lastCard = container.children('.card:last-child'), // lastCard 는 container의 card클래스 중 마지막 | |
totalWidth = 0; // | |
if ( lastCard.size() == 0 ) return; // lastCard가 없으면 종료 | |
totalWidth = lastCard.position().left + lastCard.width(); // 마지막 카드의 width(?) 왜 total 이지 | |
if ( html.attr('browser') == 'Safari' ) // 사파리 브라우저 | |
container.css('-webkit-transform', 'translate3d('+ -totalWidth / 2 +'px,0,0)'); | |
else // 그외 | |
container.css('margin-left', -totalWidth / 2 + 'px'); // container의 left margin 조정 | |
}; | |
var buildCard = function (id, type, value, side) // value - 카드 값 | |
{ | |
var card; | |
if ( side == 'back' ) card = $('<div data-id="'+id+'" class="card back"></div>'); // 뒷면일 경우 | |
else { | |
var cardValue = ( value == 1 ) ? 'A' : ( value == 11 ) ? 'J' : ( value == 12 ) ? 'Q' : ( value == 13 ) ? 'K' : value, // value 가 문자면 문자 숫자면 숫자 | |
cardIcon = ( type == 'hearts' ) ? '♥' : ( type == 'diamonds' ) ? '♦' : ( type == 'spades' ) ? '♠' : '♣', // 문양 | |
corner = '<div><span>'+cardValue+'</span><span>'+cardIcon+'</span></div>', // 왼쪽 위 코너 표시 값 | |
icons = ''; | |
// 10 이하는 문양 x 값 | |
if ( value <= 10 ) { | |
for ( var i=1, l=value; i <= l; i++ ) { | |
icons += '<span>'+cardIcon+'</span>'; | |
} | |
} else icons = ( value == 11 ) ? '<span>♝</span>' : ( value == 12 ) ? '<span>♛</span>' : ( value == 13 ) ? '<span>♚</span>' : ''; | |
// 11 이상 J,Q,K는 해당 문양 | |
card = $('<div data-id="'+id+'" class="card value'+cardValue+' '+type+'">'+corner+'<div class="icons">'+icons+'</div>'+corner+'</div>'); | |
} | |
// 카드 div 리턴 | |
return card; | |
}; | |
// Game management | |
var deal = function() | |
{ | |
// 이미 플레이중이거나, action이 불가능하거나, 게임이 끝났으면 아무것도 return하지 않는다. | |
if ( isPlaying || !canDoAction || gameEnded ) return; | |
isPlaying = true; // Play 중 | |
if ( gameDealed ) { // 처음 시작이 아니라면 초기화 | |
doubleBtn.removeClass('desactivate'); | |
playerTotal.html(''); // playerTotal 의 html을 ''로 설정 | |
dealerTotal.html(''); // dealerTotal 의 html을 ''로 설정 | |
playerAces = 0; | |
dealerAces = 0; | |
playerCards = []; | |
dealerCards = []; | |
cards = []; | |
cardsIndex = 0; | |
doubled = false; | |
canDoAction = true; | |
isStanding = false; | |
$('#message').remove(); // message 문구 제거 | |
} | |
pCardsContainer.html(''); | |
dCardsContainer.html(''); | |
initDeck(); // Deck 초기화 | |
changeBankroll(-1); // 베팅금액 차감 | |
ditributeCards(); // 카드 분배 | |
gameDealed = true; | |
}; | |
var hit = function() | |
{ | |
if ( !isPlaying || !canDoAction || isStanding || gameEnded ) return; // 플레이 중이 아니거나 액션을 할 수 없거나 스탠드 중이거나 게임이 끝나면 종료 | |
doubleBtn.addClass('desactivate'); // 규칙상 hit을 하면 double을 할 수 없으므로 desactivate class 추가 | |
addCard('front', 'player', function(){ // 카드 추가 | |
if ( playerCards.sum() > 21 ) lose('lose-busted'); // 카드 합이 21이 넘으면 lose | |
}); | |
}; | |
var stand = function() | |
{ | |
if ( !isPlaying || !canDoAction || isStanding || gameEnded ) return; // 플레이 중이 아니거나 액션을 할 수 없거나 스탠드 중이거나 게임이 끝나면 종료 | |
isStanding = true; // stand 중 (hit에는 이런 불리안이 없는데 그 이유는 hit은 한번 하고 끝나지 않으면 또 선택 가능하지만 stand는 누르는 순간 결과를 기다릴 뿐이기 때문) | |
revealDealerCard(); // 딜러 카드 공개 | |
setTimeout(function(){ | |
if ( dealerCards.sum() < 17 ) dealerTurn(); // 딜러 카드가 17보다 작으면 딜러 한번 더 | |
else end(); // 아니면 끝 | |
}, ANIM_DELAY); // ANIM_DELAY 이후에 실행 | |
}; | |
var dealerTurn = function() | |
{ | |
addCard('front', 'dealer', function(){ // 딜러에게 카드 한장 추가 | |
dealerTotal.html(calculateDealerScore()); // 딜러 결과 합산 | |
if ( dealerCards.sum() < 17 ) dealerTurn(); // 그래도 17 이하이면 다시 | |
else end(); // 끝 | |
}); | |
}; | |
var doubledown = function() | |
{ | |
if ( !isPlaying || !canDoAction || isStanding || doubleBtn.hasClass('desactivate') || gameEnded ) return; | |
// 플레이 중이 아니거나 액션을 할 수 없거나 더블을 할 수 없거나 스탠드 중이거나 게임이 끝나면 종료 | |
changeBankroll(-1); // 돈 한번 더 차감 | |
doubled = true; // 더블 중 | |
addCard('front', 'player', function(){ // 카드 한 장 더 | |
if ( playerCards.sum() > 21 ) lose('lose-busted'); // 21 넘는다 = LOSE | |
else stand(); // 안넘는다 -> 딜러 차례 기다린다. | |
}); | |
}; | |
var push = function ( msg ) // 무승부 | |
{ | |
showMessage(msg); | |
var increment = ( doubled ) ? 2 : 1; // 돈 원상 복구 | |
changeBankroll(increment); | |
stopGame(); | |
}; | |
var win = function ( msg ) | |
{ | |
showMessage(msg); // 메세지 보이기 | |
var increment = ( doubled ) ? 4 : 2; // 더블 했으면 베팅의 4배, 아니면 2배 | |
changeBankroll(increment); // increment배 증감 | |
stopGame(); | |
}; | |
var lose = function ( msg ) | |
{ | |
showMessage(msg); | |
changeBankroll(0); // 돈 변동 X : 그럼에도 하는 이유는 html text 갱신 | |
stopGame(); | |
}; | |
var showMessage = function ( status ) | |
{ | |
var msg = document.createElement('div'), | |
content = '', | |
message = $('#message'); | |
if ( message.size() > 0 ) message.remove(); // message가 이미 있으면 제거 | |
msg.className = status; // 메세지의 'status' 클래스 추가 | |
msg.id = 'message'; // 아이디 | |
switch ( status ) { | |
case 'win': content = 'You win'; break; | |
case 'win-blackjack': content = 'You win<span>Blackjack</span>'; break; | |
case 'win-dealer-busted': content = 'You win<span>Dealer busted</span>'; break; | |
case 'lose': content = 'You lose'; break; | |
case 'lose-blackjack': content = 'You lose<span>Blackjack</span>'; break; | |
case 'lose-busted': content = 'You lose<span>Busted</span>'; break; | |
case 'push': content = 'Push<span>No winner</span>'; break; | |
case 'game-over': content = 'Game over'; break; | |
default: content = '<span>Something broke, don’t know what happened...</span>'; break; | |
} | |
msg.innerHTML = content; | |
pCardsContainer.after(msg); // 플레이어 카드 컨테이너 다음에 msg div 삽입 | |
}; | |
var end = function() // 게임 종료 및 결과 산출 | |
{ | |
var pScore = playerCards.sum(), // 점수 | |
dScore = dealerCards.sum(); // | |
// 플레이어가 21이 넘는 경우는 end 까지 오기전에 끝난다(?) | |
if ( dScore > 21 ) win('win-dealer-busted'); // 딜러 > 21 : 플레이어 승리 | |
else if ( dScore > pScore ) lose('lose'); // 딜러 > 플레이어 : 패배 | |
else if ( pScore > dScore ) win('win'); // 플레이어 > 딜러 : 승리 | |
else if ( pScore == dScore ) push('push'); // 플레이어 = 딜러 : 무승부 | |
}; | |
var endGame = function() // 게임 끝 (아예 게임 오버) | |
{ | |
showMessage('game-over'); | |
gameEnded = true; | |
var overlay = document.createElement('div'); // overlay : 게임오버가 되면 전체 화면이 어두워지는데 이를 위한 div | |
overlay.id = 'overlay'; | |
$('body').append(overlay); // html body 맨 뒤에 추가한다. | |
}; | |
var stopGame = function() | |
{ | |
isPlaying = false; // 플레이 중 아님 | |
dealNav.show(); // deal 버튼 보여 | |
actionsNav.hide(); // 행동 버튼 숨기기 | |
chips.removeClass('disabled'); // 칩 선택 가능 | |
allChips.each(function(i){ | |
var chip = $(this); // 칩 하나 | |
if ( chip.data('value') > bank ) { //칩이 잔고보다 크면 | |
chip.addClass('desactivate'); // 칩이 잔고보다 크면 desactivate | |
var chipsAvailable = allChips.removeClass('bet').not('.desactivate'); // bet을 지우고 desactivate 아닌것 들 | |
if ( chipsAvailable.size() == 0 ) endGame(); // 사용 가능 한 것이 없으면 게임 end | |
else { | |
var newChip = chipsAvailable.last(); | |
newChip.addClass('bet'); // 마지막 가능 칩에 bet 추가 | |
changeBet(newChip.data('value')); // new칩 | |
chips.prepend(newChip); // chips 앞에다가 newChip추가 | |
} | |
} else if ( chip.hasClass('desactivate') ) chip.removeClass('desactivate'); // 가능한데 desactivate 있으면 제거 | |
}); | |
}; | |
var ditributeCards = function() | |
{ | |
canDoAction = false; // 동작 차단. | |
addCard('front', 'player', function(){ | |
addCard('front', 'dealer', function(){ | |
addCard('front', 'player', function(){ | |
addCard('back', 'dealer', function(){ // 번갈아가며 카드 추가 / 블랙잭 체크 | |
checkBlackjack(); | |
}); | |
}); | |
}); | |
}); | |
dealNav.hide(); // deal 버튼 감추기 | |
actionsNav.show(); // 행동 버튼 보이기 | |
chips.addClass('disabled'); // 칩들 고를 수 없게 | |
}; | |
var checkBlackjack = function() | |
{ | |
var pScore = playerCards.sum(), | |
dScore = dealerCards.sum(); | |
if ( pScore == 21 && dScore == 21 ) push('Push - No winner'); | |
else if ( pScore == 21 ) win('win-blackjack'); | |
else if ( dScore == 21 ) { | |
lose('lose-blackjack'); | |
revealDealerCard(); | |
} | |
}; | |
// Player management | |
var addToPlayerTotal = function ( value ) | |
{ | |
if ( value == 1 ) { | |
value = 11; | |
playerAces++; | |
} // 1 (A)이면 11을 일단 넣고 Ace 수를 증가시킨다. | |
playerCards.push(value); // 카드에 숫자 추가 | |
playerTotal.html(calculatePlayerScore()); // 플레이어 점수 표시 | |
}; | |
var calculatePlayerScore = function() | |
{ | |
var score = playerCards.sum(); // 점수 합산 | |
if ( score > 21 && playerAces > 0 ) { // 21이 넘었는데 A가 있다 | |
playerCards.splice(playerCards.indexOf(11), 1, 1); // 11을 1로 바꿔본다 | |
playerAces--; // Ace 숫자 감소 | |
score = calculatePlayerScore(); // 다시 계산 (재귀) | |
} | |
return score; //리턴 | |
}; | |
// Dealer management | |
var revealDealerCard = function() | |
{ | |
var card = $('.back'), // 뒷면 카드 ( 딜러의 두번째 크다 ) | |
id = card.data('id'), // 그 카드의 index | |
data = cards[id], // 카드 data | |
newCard = buildCard(id, data.type, data.value, 'front'); // 앞면으로 카드를 만듬 | |
newCard.css({ | |
'left' : 10 * card.index() + '%', | |
'z-index' : 50-card.index() | |
}); | |
card.after(newCard).remove(); // 뒷면 카드 뒤에 newCard를 넣고 뒷면 카드를 지운다 | |
dealerTotal.html(calculateDealerScore()); // | |
}; | |
var addToDealerTotal = function ( value ) | |
{ | |
if ( value == 1 ) { | |
value = 11; | |
dealerAces++; | |
} | |
dealerCards.push(value); // 플레이어와 같지만 점수 표시 하는 것 하나만 다르다 (같은 동작이 필요하면 범용 함수로) | |
}; | |
var calculateDealerScore = function() | |
{ | |
var score = dealerCards.sum(); // 합한다 | |
if ( score > 21 && dealerAces > 0 ) { // 21이 넘었는데 Ace가 있다면 | |
dealerCards.splice(dealerCards.indexOf(11), 1, 1); // Ace를 1로 바꾸고 | |
dealerAces--; // Ace수를 줄이고 하나 | |
score = calculateDealerScore(); // 다시 계산 | |
} | |
return score; | |
}; | |
// Bet management | |
var initBet = function() | |
{ | |
allChips.bind('click', function(e){ | |
var chip = $(this); // 클릭 된 chip | |
if ( isPlaying || chip.hasClass('desactivate') ) return; // 실행중이거나 chip(allChips)이 desactivate 클래스를 가지고 있으면 종료 | |
allChips.removeClass('bet'); // 모든 chip 에서 bet 클래스 제거 | |
chip.addClass('bet'); // chip (아마 100b) 에 bet 클래스 추가 (현재 bet인 칩에 bet클래스를 넣는 듯 하다) | |
changeBet(chip.data('value')); // currentBet 를 chip의 value로 갱신 | |
chips.prepend(chip); //chips 앞에 chip을 추가한다. (bet이 추가된 chip) | |
}); | |
}; | |
//현재 베팅 금액을 바꾼다. | |
var changeBet = function ( newValue ) { | |
if ( isPlaying ) return; | |
currentBet = newValue; | |
}; | |
//잔고를 현재 배팅금액의 increment배 한다. | |
var changeBankroll = function ( increment ) { | |
bank += increment * currentBet; // 계좌에서 currentBet 차감 | |
bankroll.html((bank / 10) + 'k'); // 화면 갱신 | |
}; | |
return pro })(); | |
/* | |
* Array shuffle <http://snipplr.com/view/535> | |
* Array sum <http://snipplr.com/view/533> | |
*/ // i : 카드배열 길이, i가 0보다 클 때 까지, j = 0~i-1중 하나, this[j] 와 this[i] swap | |
Array.prototype.shuffle = function() { for(var j, x, i = this.length; i; j = Math.floor(Math.random() * i), x = this[--i], this[i] = this[j], this[j] = x); } | |
Array.prototype.sum = function() { for(var s = 0, i = this.length; i; s += this[--i]); return s; }; // 배열 수 총합합 | |
/* | |
* Browser Detect <http://teev.io/blog/text/13423292> | |
*/ | |
var BrowserDetect = { | |
init: function () { | |
this.browser = this.searchString(this.dataBrowser) || "An unknown browser"; | |
this.version = this.searchVersion(navigator.userAgent) | |
|| this.searchVersion(navigator.appVersion) | |
|| "an unknown version"; | |
this.OS = this.searchString(this.dataOS) || "an unknown OS"; | |
var b = document.documentElement; | |
b.setAttribute('browser', this.browser); | |
b.setAttribute('version', this.version ); | |
b.setAttribute('os', this.OS); | |
}, | |
searchString: function (data) { | |
for (var i=0;i<data.length;i++) { | |
var dataString = data[i].string; | |
var dataProp = data[i].prop; | |
this.versionSearchString = data[i].versionSearch || data[i].identity; | |
if (dataString) { | |
if (dataString.indexOf(data[i].subString) != -1) | |
return data[i].identity; | |
} | |
else if (dataProp) | |
return data[i].identity; | |
} | |
}, | |
searchVersion: function (dataString) { | |
var index = dataString.indexOf(this.versionSearchString); | |
if (index == -1) return; | |
return parseFloat(dataString.substring(index+this.versionSearchString.length+1)); | |
}, | |
dataBrowser: [ | |
{ | |
string: navigator.userAgent, | |
subString: "Chrome", | |
identity: "Chrome" | |
}, | |
{ string: navigator.userAgent, | |
subString: "OmniWeb", | |
versionSearch: "OmniWeb/", | |
identity: "OmniWeb" | |
}, | |
{ | |
string: navigator.vendor, | |
subString: "Apple", | |
identity: "Safari", | |
versionSearch: "Version" | |
}, | |
{ | |
prop: window.opera, | |
identity: "Opera", | |
versionSearch: "Version" | |
}, | |
{ | |
string: navigator.vendor, | |
subString: "iCab", | |
identity: "iCab" | |
}, | |
{ | |
string: navigator.vendor, | |
subString: "KDE", | |
identity: "Konqueror" | |
}, | |
{ | |
string: navigator.userAgent, | |
subString: "Firefox", | |
identity: "Firefox" | |
}, | |
{ | |
string: navigator.vendor, | |
subString: "Camino", | |
identity: "Camino" | |
}, | |
{ // for newer Netscapes (6+) | |
string: navigator.userAgent, | |
subString: "Netscape", | |
identity: "Netscape" | |
}, | |
{ | |
string: navigator.userAgent, | |
subString: "MSIE", | |
identity: "Explorer", | |
versionSearch: "MSIE" | |
}, | |
{ | |
string: navigator.userAgent, | |
subString: "Gecko", | |
identity: "Mozilla", | |
versionSearch: "rv" | |
}, | |
{ // for older Netscapes (4-) | |
string: navigator.userAgent, | |
subString: "Mozilla", | |
identity: "Netscape", | |
versionSearch: "Mozilla" | |
} | |
], | |
dataOS : [ | |
{ | |
string: navigator.platform, | |
subString: "Win", | |
identity: "Windows" | |
}, | |
{ | |
string: navigator.platform, | |
subString: "Mac", | |
identity: "Mac" | |
}, | |
{ | |
string: navigator.userAgent, | |
subString: "iPhone", | |
identity: "iPhone/iPod" | |
}, | |
{ | |
string: navigator.platform, | |
subString: "Linux", | |
identity: "Linux" | |
} | |
] | |
}; | |
BrowserDetect.init(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment