在BlackJack中组织JavaScript的最佳方法是什么,也许从空白开始?
具体领域:
Hand类中加入经销商的手以减少重复IFs我并不担心这个原型的投注金额/支出/芯片数量,但我当然会补充这一点。
代码:
BlackJack Early Prototype
.flex-row{
display: flex;
flex-flow: row wrap;
justify-content: space-around;
}
deal
const suits = [
{
digit: 'H',
word: 'hearts'
},
{
digit: 'C',
word: 'clubs'
},
{
digit: 'D',
word: 'diamonds'
},
{
digit: 'S',
word: 'spades'
}
]
const cardsWithoutSuits = [
{
numeric: 11,
word: 'ace',
digit: 'A'
},
{
numeric: 2,
word: 'two',
},
{
numeric: 3,
word: 'three',
},
{
numeric: 4,
word: 'four',
},
{
numeric: 5,
word: 'five',
},
{
numeric: 6,
word: 'six',
},
{
numeric: 7,
word: 'seven',
},
{
numeric: 8,
word: 'eight',
},
{
numeric: 9,
word: 'nine',
},
{
numeric: 10,
word: 'ten',
},
{
numeric: 10,
word: 'jack',
digit: 'J'
},
{
numeric: 10,
word: 'queen',
digit: 'Q'
},
{
numeric: 10,
word: 'king',
digit: 'K'
}
]
class Hand{
constructor(bet){
// assigning the bet value
this.bet = bet;
// default values, no cards dealt yet
this.cards = [];
this.value = 0;
this.blackjack = false;
this.soft = false;
this.bust = false;
this.winner = false;
this.aceQuantity = 0;
this.canHit = false;
this.canStay = false;
this.canSplit = false;
this.canDouble = false;
this.finished = false;
this.textResult = '';
this.payout = 0;
};
evaluate(){
this.aceQuantity = this.cards.filter(x => x.word === 'ace').length;
this.value = this.cards.filter(x => x.word !== 'ace').reduce((total, x) => +total + x.numeric, 0);
this.soft = false;
for (var i = 0; i < this.aceQuantity; i++) {
if (this.value + 11 > 21) this.value += 1;
else {
this.value +=11;
if (this.value !== 21) this.soft = true;
}
}
if (this.cards.length === 2) {
this.canDouble = true;
this.canSplit = this.cards[0].word === this.cards[1].word;
} else {
this.canSplit = false;
this.canDouble = false;
}
if (this.value > 21){
this.bust = true;
this.finished = true;
this.canHit = false;
this.canStay = false;
}
if(this.value === 21){
this.finished = true;
this.canHit = false;
if (this.cards.length === 2) {
this.blackjack = true;
}
}
if (this.bust) {
this.textResult = `Busted!`;
this.payout = 0;
} else if (this.blackjack) {
this.textResult = `BlackJack!`;
} else if (game.dealerFinished) {
if (this.finished) {
if (game.dealerValue > 21) {
this.textResult = `Winner!`;
} else if (this.value > game.dealerValue) {
this.textResult = `Winner!`;
} else if (this.value === game.dealerValue) {
this.textResult = `Push`;
} else if (this.value < game.dealerValue) {
this.textResult = `Loser`;
}
}
} else {
this.textResult = `Standing on ${this.value}`;
}
}
}
function createDeck(decks = 1){
let deck = [];
for (let i = 0; i < decks; i++) {
suits.forEach( x => {
cardsWithoutSuits.forEach( y => {
deck.push({
numeric: y.numeric,
word: y.word,
suit: x.word,
phrase: `${y.word} of ${x.word}`,
abbr: `${y.hasOwnProperty('digit') ? y.digit : y.numeric}${x.digit}`
})
})
})
}
return deck;
}
function shuffle(array){
let array2 = [];
while (array.length){
let index = Math.floor(Math.random() * array.length);
let card = array.splice(index, 1);
array2.push(card[0]);
}
return array2;
}
let game = {
state: 'start',
deck: [],
dealerCards: [],
dealerFinished: false,
dealerValue: 0,
hands: [],
shuffle: function(){
this.deck = shuffle(createDeck(4));
},
deal: function(){
this.hands.forEach(x => {
x.cards.push(this.deck.shift());
x.evaluate();
});
this.dealerCards.push(this.deck.shift());
this.hands.forEach(x => {
x.cards.push(this.deck.shift());
x.evaluate();
});
this.dealerCards.push(this.deck.shift());
},
tempCreateTestHands: function(){
this.hands.push(new Hand(5));
this.hands.push(new Hand(10));
this.hands.push(new Hand(25));
},
dealCard: function(hand){
if (hand === -1) {
this.dealerCards.push(this.deck.shift());
updateUI();
} else {
this.hands[hand].cards.push(this.deck.shift());
this.hands[hand].evaluate();
}
},
tempStart: function(){
game.dealerFinished = false;
game.hands = [];
game.dealerCards = [];
if (game.deck.length < 30) game.shuffle();
game.tempCreateTestHands();
game.deal();
updateUI();
},
dealerTurn: function(){
let aceQuantity = this.dealerCards.filter(x => x.word === 'ace').length;
let value = this.dealerCards.filter(x => x.word !== 'ace').reduce((total, x) => +total + x.numeric, 0);
for (var i = 0; i < aceQuantity; i++) {
if (value + 11 > 21) value += 1;
else {
value +=11;
}
}
this.dealerValue = value;
if (value < 17) {
this.dealCard(-1);
} else {
this.dealerFinished = true;
game.hands.forEach(x => x.evaluate());
updateUI();
}
}
}
game.tempStart();
function updateUI(){
const playersUI = [document.getElementById('hand1'), document.getElementById('hand2'), document.getElementById('hand3')];
const dealer = document.getElementById('dealer');
const handsRemaining = game.hands.filter(x => !x.finished).length;
if (handsRemaining) dealer.innerHTML = `<h2>Dealer</h2><p>Card Hidden</p><p>${game.dealerCards[1].phrase}</p><p>Showing ${game.dealerCards[1].numeric}</p>`;
else dealer.innerHTML = `<h2>Dealer</h2>` + game.dealerCards.map(x => `<p>${x.phrase}</p>`).join('') + `<p>Total: ${game.dealerValue}</p>`;
if (!handsRemaining && !game.dealerFinished) {
game.dealerTurn();
}
for (var i = 0; i < game.hands.length; i++) {
let buttons = '';
if (game.hands[i].finished){
buttons += `<div>`;
if (game.hands[i].busted) buttons +=`BUSTED`;
else {
buttons += game.hands[i].textResult;
}
buttons += `</div>`
} else {
buttons += `<div>
<button class='hit' onclick="buttonHandler(${i}, 'hit')">HIT</button>
<button class='stay' onclick="buttonHandler(${i}, 'stay')">STAY</button>
`;
if (game.hands[i].canDouble) buttons +=`<button class='double' onclick="buttonHandler(${i}, 'double')">DOUBLE</button>`;
if (game.hands[i].canSplit) buttons +=`<button class='split' onclick="buttonHandler(${i}, 'split')">SPLIT</button>`;
buttons += `</div>`;
}
playersUI[i].innerHTML = `<h2>Hand ${i + 1}</h2>` + game.hands[i].cards.map(x => `<p>${x.phrase}</p>`).join('') + `<p>Total: ${game.hands[i].soft ? 'Soft' : ''} ${game.hands[i].value}</p>${buttons}`;
}
}
function buttonHandler(playerHand, action){
switch (action) {
case 'stay':
game.hands[playerHand].finished = true;
break;
case 'hit':
game.dealCard(playerHand);
break;
case 'double':
game.dealCard(playerHand);
game.hands[playerHand].finished = true;
game.hands[playerHand].bet = game.hands[playerHand].bet * 2;
break;
case 'split':
console.log(`split function not setup yet...`);
break;
default:
console.log(`error, cannot find ${action} in the switch statement.`);
}
updateUI();
}
document.getElementById("deal").onclick = function() {
// alert("hello");
game.tempStart();
}发布于 2019-07-31 17:52:05
您可以看到我建议的改进这里。作为前一个人,我也偏向于一种更实用的风格。这就是我所做的:
this.bet = bet正在分配投注值。constructor(bet) {
// assigning the bet value
this.bet = bet;
// default values, no cards dealt yet
this.cards = [];
...
}*=运算符可以像foo *= 2一样使用,而不是foo = 2 * foo+操作符连接是没有意义的(注意,模板文字允许多行)。some,如果您想知道它们是多少(一个数字),则使用filter().length。在这种情况下,我们希望布尔值表示是否存在任何元素,并且我们不关心这些元素之外有多少元素。使用正确的一个可以提高可读性。const handsRemaining = game.hands.filter(x => !x.finished).length;至
const isHandsRemaining = game.hands.some(x => !x.finished);buttons += ``;
if (busted) {
buttons += `BUSTED`;
} else {
buttons += textResult;
}
buttons += ``;至
buttons += `${busted ? 'BUSTED' : textResult}`;players,但这通常来自服务器),而不是让它分散在标记和代码中的不同位置。Array.map而不是Array.forEach。const而不是let。另外,shuffle应该以您使用的洗牌算法命名,或者有一个注释来解释它是什么算法。
还有更多的改进需要做,但至少这是一个开始:)
编辑:打印
发布于 2019-03-03 12:05:56
注意:我倾向于一种更实用的风格
好:
坏:
通常,在可能的情况下使用更纯的函数来避免跟踪所有这些状态。将状态存储在普通的旧对象中。只有存储所需的状态,ui才能从状态中计算其结果。
一些启示:
state = intitialState
updateGame(event){
state = handleEvent(state, event)
state = updateState(state)
updateUi(state)
}
onButton(event){
updateGame(event)
}https://codereview.stackexchange.com/questions/214591
复制相似问题