首页 > 解决方案 > 如何实现一个计时器以在 2 秒后处理每张牌?

问题描述

我有这个功能,它将一张牌发给玩家,然后发给庄家,然后发给玩家,然后发给庄家。

我试过使用setTimeout(function, milliseconds);,但它不起作用。例如,如果我设置 2 秒,它会等待 4 秒,然后将 2 张牌发给玩家,然后直接发给庄家 2 张牌,或者等待 8 秒,然后将所有牌一次发完。

这是我的方法:

const dealOneCardToPlayer = () => {
    // Take a card from the top deck to be assigned to tempcard.
    tempCard = deck.cards.splice(0, 1);
    //console.log(tempCard);
    player.cards.push(tempCard);

    if (player.cards.length === 5) {
        player.canHit = false;
    }

    if (player.canHit) {
        $("#btnHit").show();
    } else {
        $("#btnHit").hide();
    }

    player.handValue = countHandValue(player.cards);
    makeCardPlayer(tempCard[0]);
}

const dealOneCardToDealer = (holeCard) => {
    // Take a card from the top deck to be assigned to tempcard.
    tempCard = deck.cards.splice(0, 1);
    dealer.cards.push(tempCard);

    if (dealer.cards.length === 5) {
        dealer.canHit = false;
    }

    if (dealer.canHit) {
        $("#btnHit").show();
    } else {
        $("#btnHit").hide();
    }

    dealer.handValue = countHandValue(dealer.cards);
    makeCardDealer(tempCard[0],holeCard);
}

const deal = () => {
    debugger;
    newDeck();

    // Option: to burn first card before deal a card
    // to the first player
    burnOneCard;

    dealOneCardToPlayer();
    dealOneCardToDealer(false);
    dealOneCardToPlayer();

    // true for hole card
    dealOneCardToDealer(true);

    showGameButtons(true);
    checkEndGame1();
    checkGameOver();
}

<link href="check.css" rel="stylesheet" />
<style>
    body{
        font-size: 2em;
    }

    h3, h5 {
        text-align: center;
    }

    h5{
        margin-top:-40px;
    }

    /*debugging purpose*/
    div#oneDeck {
        border: 1px solid green;
        margin: 10px;
        padding: 10px;
    }

    /*debugging purpose*/
    div#playerCards {
        border: 1px solid blue;
        margin: 10px;
        padding: 10px;
    }

    /*debugging purpose*/
    div#dealerCards {
        border: 1px solid red;
        margin: 10px;
        padding: 10px;
    }

    #mainContainer {
        max-width: 600px;
        margin: 0 auto;
    }

    fieldset {
        margin-top: 30px;
        border: 1px solid #999;
        border-radius: 8px;
        box-shadow: 0 0 10px #999;
    }

    legend {
        background: #fff;
    }

    #cardContainerPlayer {
        display: flex;
        flex-wrap: wrap;
    }

    .card {
        display: inline-block;
        vertical-align: top; /*float: left;*/
        text-align: center;
        margin: 5px;
        padding: 10px;
        width: 70px;
        height: 100px;
        font-size: 26px;
        background-color: black;
        border: solid 1px black;
        color: white;
        border-radius: 10px;
    }

    .holeCard {
        /*visibility: hidden;*/
        border: solid 1px black;
        background: repeating-linear-gradient( 45deg, #606dbc, #606dbc 10px, #465298 10px, #465298 20px );
    }

    .red {
        background-color: red;
        border: solid 1px #8C001A;
    }

    .templatePlayer, .templateDealer {
        display: none;
    }

    #btnGame {
        margin: 10px;
    }

    .winner {
        border: solid 5px #7ac142;
    }

    .btnGame {
        background-color: dodgerblue; /* Green */
        border: none;
        color: white;
        padding: 15px 32px;        
        /*border-radius:10px;*/
        text-align: center;
        text-decoration: none;
        display: inline-block;
        font-size: 16px;
        cursor: pointer;
        -webkit-transition-duration: 0.4s; /* Safari */
        transition-duration: 0.4s;
        box-shadow: 0 8px 16px 0 rgba(0,0,0,0.2), 0 6px 20px 0 rgba(0,0,0,0.19);
    }

    #btnHit {
        margin-right: 20px;
    }

    .flex-container {
        padding: 0;
        margin: 0;
        display: flex;
        justify-content: space-between;
        max-width: 100%;
        overflow: auto;
        /*border: 1px solid red*/
    }

</style>
<h3>Simple Javascript BlackJack Game</h3>
<h5>developed by Steve Ngai</h5>
<div id="mainContainer">
    <div id="btnDevelopment">
        <input type='button' value='Create new Deck' onclick='newDeck();' />
        <input type='button' value='Burn a card' onclick='burnOneCard();' />
        <input type='button' value='Refresh Deck' onclick='showDeck();' />
        <input type='button' value='Deal a card to Player' onclick='dealOneCardToPlayer();' />
        <input type='button' value='Deal a card to Dealer' onclick='dealOneCardToDealer();' />
        <input type='button' value='Show hand value' onclick='showHandValue();' />
        <input type='button' value='Check end game' onclick='checkEndGame();' />
        <input type='button' value='Refresh deck remaining cards count' onclick='getDeckCardCount();' />
    </div>

    <fieldset id="deck">
        <legend>Remaining cards in the Deck: <span id="deckCardCount"></span></legend>
        <div id="oneDeck"></div>
    </fieldset>

    <fieldset id="containerDealer">
        <legend>Dealer (Hand Value: <span id="handValueDealer"></span>)</legend>
        <div style="width:30px">
            <svg class="checkmarkDealer" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 52 52">
                <circle class="checkmark__circle" cx="26" cy="26" r="25" fill="none" />
                <path class="checkmark__check" fill="none" d="M14.1 27.2l7.1 7.2 16.7-16.8" />
            </svg>
        </div>
        <div id="dealerCards"></div>
        <div id="cardContainerDealer">
            <div class="card templateDealer">
                <span class="dealerCardFace"></span>
                <span class="dealerCardSuit"></span>
            </div>
        </div>
        <div id="dealerCardsHandValue"></div>
    </fieldset>

    <div id="btnGame">
        <div class="flex-container">
            <div class="btn">
                <input type='button' class="btnGame" id="btnDeal" value='Deal' onclick='deal();' />
            </div>
            <div class="btn">
                <input type='button' class="btnGame" id="btnHit" value='Hit' onclick='hit();' />            
                <input type='button' class="btnGame" id="btnStand" value='Stand' onclick='stand();' />
            </div>            
        </div>
    </div>

    <fieldset id="containerPlayer">
        <legend>Player (Hand Value: <span id="handValuePlayer"></span>)</legend>
        <div style="width:30px">
            <svg class="checkmarkPlayer" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 52 52">
                <circle class="checkmark__circle" cx="26" cy="26" r="25" fill="none" />
                <path class="checkmark__check" fill="none" d="M14.1 27.2l7.1 7.2 16.7-16.8" />
            </svg>
        </div>
        <div id="playerCards"></div>
        <div id="cardContainerPlayer">
            <div class="card templatePlayer">
                <span class="playerCardFace"></span>
                <span class="playerCardSuit"></span>
            </div>
        </div>
        <div id="playerCardsHandValue"></div>
    </fieldset>

    <fieldset id="result">
        <legend>Game Result</legend>
        <div id="gameResult"></div>
    </fieldset>
</div>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script>
    "use strict";

    // Variable/Object declaration and initialization - Start
    const isDebug = false;
    const DELAY = 2000;
    var gameOver = false;
    const deck = {
        cards: []
    }

    var tempCard;
    const player = {
        cards: [],
        handValue: 0,
        isWinner: false,
        canHit: true
    }

    const dealer = {
        cards: [],
        handValue: 0,
        isWinner: false,
        canHit: true
    }

    var result = document.getElementById("gameResult");

    const cardSuit = ["hearts", "diams", "clubs", "spades"];
    const cardFace = ["2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A"];

    $(".checkmarkDealer").hide();
    $(".checkmarkPlayer").hide();
    $("#handValueDealer").hide();
    //Variable/Object declaration and initialization - End

    if (!isDebug) {
        document.getElementById("btnDevelopment").style.display = "none";
        document.getElementById("deck").style.display = "none";
        document.getElementById("oneDeck").style.display = "none";
        document.getElementById("playerCards").style.display = "none";
        document.getElementById("dealerCards").style.display = "none";
        //document.getElementById("result").style.display = "none";
    } else {
        document.getElementById("btnDevelopment").style.display = "block";
        document.getElementById("deck").style.display = "block";
        document.getElementById("oneDeck").style.display = "block";
        document.getElementById("playerCards").style.display = "block";
        document.getElementById("dealerCards").style.display = "block";
        //document.getElementById("result").style.display = "block";
    }

    const showGameButtons = (cardDealt) => {
        if (cardDealt) {            
            $("#btnDeal").hide();
            $("#btnHit").show();
            $("#btnStand").show();

            //document.getElementById("btnDeal").disabled = true;
            //document.getElementById("btnHit").disabled = false;
            //document.getElementById("btnStand").disabled = false;
        } else {            
            $("#btnDeal").show();
            $("#btnHit").hide();
            $("#btnStand").hide();

            //document.getElementById("btnDeal").disabled = false;
            //document.getElementById("btnHit").disabled = true;
            //document.getElementById("btnStand").disabled = true;
        }

        if (player.isWinner === true) {
            document.getElementById("containerDealer").classList.remove("winner");
            document.getElementById("containerPlayer").classList.add("winner");

            $("#handValueDealer").show();
            $(".checkmarkPlayer").show();
            $(".checkmarkDealer").hide();
        } else if (dealer.isWinner === true) {
            document.getElementById("containerPlayer").classList.remove("winner");
            document.getElementById("containerDealer").classList.add("winner");

            $("#handValueDealer").show();
            $(".checkmarkPlayer").hide();
            $(".checkmarkDealer").show();
        } else {
            
            
           
        }
    }
    showGameButtons(false);


    // In JavaScript, functions are objects.
    // You can work with functions as if they were objects.
    function card(suit, face) {
        this.suit = suit;
        this.face = face;

        switch (face) {
            case "A":
                this.faceValue = 11;
                break;
            case "J":
            case "Q":
            case "K":
                this.faceValue = 10;
                break;
            default:
                this.faceValue = parseInt(face);
                break;
        }
    };



    const createDeck = () => {
        deck.cards = [];
        deck.cards.length = 0;
        cardSuit.forEach(function (suit) {
            cardFace.forEach(function (face) {
                deck.cards.push(new card(suit, face));
            });
        });
    }

    const shuffleDeck = () => {
        // Fisher–Yates shuffle algorithm
        let temp, i, rnd;
        for (i = 0; i < deck.cards.length; i++) {
            rnd = Math.floor(Math.random() * deck.cards.length);
            temp = deck.cards[i];
            deck.cards[i] = deck.cards[rnd];
            deck.cards[rnd] = temp;
        }
    }

    const newDeck = () => {
        createDeck();
        shuffleDeck();
        document.getElementById("oneDeck").innerHTML = "";

        player.cards = [];
        player.handValue = 0;

        dealer.cards = [];
        dealer.handValue = 0;

        var myNode = document.getElementById("cardContainerPlayer");
        var fc = myNode.firstChild.firstChild;

        while (fc) {
            myNode.removeChild(fc);
            fc = myNode.firstChild;
        }

        var myNodeDealer = document.getElementById("cardContainerDealer");
        var fcDealer = myNodeDealer.firstChild.firstChild;

        while (fcDealer) {
            myNodeDealer.removeChild(fcDealer);
            fcDealer = myNodeDealer.firstChild;
        }

        document.getElementById("playerCards").innerHTML = "";
        document.getElementById("dealerCards").innerHTML = "";

        document.getElementById("oneDeck").innerHTML = JSON.stringify(deck);
    }

    const burnOneCard = () => {
        // Remove the top deck to burn
        deck.cards.splice(0, 1);
    }

    const showDeck = () => {
        document.getElementById("oneDeck").innerHTML = JSON.stringify(deck);
    }

    const dealOneCardToPlayer = () => {
        return new Promise(function (resolve) {
            setTimeout(function () {
                // Take a card from the top deck to be assigned to tempcard.
                tempCard = deck.cards.splice(0, 1);
                //console.log(tempCard);
                player.cards.push(tempCard);

                if (player.cards.length === 5) {
                    player.canHit = false;
                }

                if (player.canHit) {
                    $("#btnHit").show();
                } else {
                    $("#btnHit").hide();
                }

                //player.cards.push(new card("Spades","A"));
                //player.cards.push(new card("Spades","10"));
                document.getElementById("playerCards").innerHTML = JSON.stringify(player);
                player.handValue = countHandValue(player.cards);
                document.getElementById("handValuePlayer").innerHTML = player.handValue;
                makeCardPlayer(tempCard[0]);
                resolve();
            }, DELAY);
        });
        
    }

    const dealOneCardToDealer = (holeCard) => {
        return new Promise(function (resolve) {
            setTimeout(function () {
                // Take a card from the top deck to be assigned to tempcard.
                tempCard = deck.cards.splice(0, 1);
                dealer.cards.push(tempCard);

                if (dealer.cards.length === 5) {
                    dealer.canHit = false;
                }

                if (dealer.canHit) {
                    $("#btnHit").show();
                } else {
                    $("#btnHit").hide();
                }

                document.getElementById("dealerCards").innerHTML = JSON.stringify(dealer);
                dealer.handValue = countHandValue(dealer.cards);
                document.getElementById("handValueDealer").innerHTML = dealer.handValue;
                makeCardDealer(tempCard[0], holeCard);
                resolve();
            }, DELAY);
        });        
    }

    const hasAceInHand = (cardsOnHand) => {
        for (let key in cardsOnHand) {
            let arr = cardsOnHand[key];
            for (let i = 0; i < arr.length; i++) {
                let obj = arr[i];
                for (let prop in obj) {
                    if (prop === "face") {
                        if (obj[prop] === "A") {
                            return true;
                        }
                    }
                }
            }
        }
        return false;
    }

    const countHandValue = (cardsOnHand) => {
        //console.log(hasAceInHand(cardsOnHand));
        let sum = 0;
        for (let key in cardsOnHand) {
            let arr = cardsOnHand[key];
            for (let i = 0; i < arr.length; i++) {
                let obj = arr[i];
                for (let prop in obj) {
                    if (prop === "faceValue") {
                        //console.log(prop + " = " + obj[prop]);
                        sum = sum + obj[prop];
                        debugger;
                        if (sum > 21 && hasAceInHand(cardsOnHand)) {
                            // Transfer Ace's face value from 11 to 1
                            sum = sum - 11; 
                            sum = sum + 1;
                        }
                    }
                }
            }
        }
        
        return sum;
    }

    const showHandValue = () => {
        document.getElementById("playerCardsHandValue").innerHTML = player.handValue;
        document.getElementById("dealerCardsHandValue").innerHTML = dealer.handValue;
    }

    const getDeckCardCount = () => {
        document.getElementById("deckCardCount").innerHTML = deck.cards.length;
    }

    const checkGameOver = () => {
        if (gameOver) {
            $(".holeCard > :nth-child(1)").show();
            $(".holeCard > :nth-child(2)").show();

            $(".holeCard").removeClass("holeCard");
            $("#handValueDealer").show();

            showGameButtons(false);
        }

        
    }

    const checkEndGame1 = () => {
        gameOver = true;
        if (player.handValue === 21 && dealer.handValue !== 21) {
            result.innerHTML = "BlackJack! Player won.";
            player.isWinner = true;
        } else if (player.handValue !== 21 && dealer.handValue === 21) {
            result.innerHTML = "BlackJack! Dealer won.";
            dealer.isWinner = true;
        } else if (player.handValue === 21 && dealer.handValue === 21) {
            result.innerHTML = "Push.";
        } else {
            gameOver = false;
        }
    }

    const checkEndGame2 = () => {
        if (player.cards.length <= 5 && player.handValue > 21) {
            result.innerHTML = "Bust! Dealer won.";
            dealer.isWinner = true;
            gameOver = true;
        }
    }

    const checkEndGame3 = () => {

        if (player.cards.length <= 5 && dealer.cards.length <= 5) {
            // Check bust
            if (player.handValue <= 21 && dealer.handValue > 21) {
                result.innerHTML = "Bust! Player won.";
                player.isWinner = true;
            } else if (player.handValue === 21 && dealer.handValue !== 21) {
                result.innerHTML = "BlackJack! Player won.";
                player.isWinner = true;
            } else if (player.handValue !== 21 && dealer.handValue === 21) {
                result.innerHTML = "BlackJack! Dealer won.";
                dealer.isWinner = true;

            } else if (player.handValue === dealer.handValue) {
                result.innerHTML = "Push.";
            } else if (player.handValue > dealer.handValue) {
                result.innerHTML = "Player won.";
                player.isWinner = true;
            } else if (player.handValue < dealer.handValue) {
                result.innerHTML = "Dealer won.";
                dealer.isWinner = true;
            } else {
                result.innerHTML = "Error";
            }
        } else {
            result.innerHTML = "Error";
        }
        gameOver = true;
    }

    // This function use JQuery lib
    function makeCardPlayer(_card) {
        // .card is created in the template card css class
        var card = $(".card.templatePlayer").clone();

        card.removeClass("templatePlayer");

        // .cardFace is created in the template card css class
        // It will search for this css class and add the content aka innerHTML
        card.find(".playerCardFace").html(_card.face);

        // .suit is created in the template card css class
        // It will search for this css class and add the content aka innerHTML
        card.find(".playerCardSuit").html("&" + _card.suit + ";");
        // &spades; -> ♠, &clubs; -> ♣, &hearts; -> ♥, &diams; -> ♦
        // more char, https://www.w3schools.com/charsets/ref_utf_symbols.asp

        // hearts and diamonds are red color. otherwise, default black color.
        if (_card.suit === "hearts" || _card.suit === "diams") {
            card.addClass("red");
        }

        // option: replace previous card with new card (show one card all the time)
        $("#cardContainerPlayer").append(card);
    }

    // This function use JQuery lib
    function makeCardDealer(_card, _holeCard) {
        // .card is created in the template card css class
        var card = $(".card.templateDealer").clone();

        card.removeClass("templateDealer");

        // .cardFace is created in the template card css class
        // It will search for this css class and add the content aka innerHTML
        card.find(".dealerCardFace").html(_card.face);

        // .suit is created in the template card css class
        // It will search for this css class and add the content aka innerHTML
        card.find(".dealerCardSuit").html("&" + _card.suit + ";");
        // &spades; -> ♠, &clubs; -> ♣, &hearts; -> ♥, &diams; -> ♦
        // more char, https://www.w3schools.com/charsets/ref_utf_symbols.asp

        // hearts and diamonds are red color. otherwise, default black color.
        if (_card.suit === "hearts" || _card.suit === "diams") {
            card.addClass("red");
        }

        if (_holeCard) {
            card.addClass("holeCard");            
        }

        // option: replace previous card with new card (show one card all the time)
        $("#cardContainerDealer").append(card);

        $(".holeCard > :nth-child(1)").hide();
        $(".holeCard > :nth-child(2)").hide();
        
    }

    

    const deal = () => {
        debugger;
        newDeck();

        // Option: to burn first card before deal a card
        // to the first player
        burnOneCard;

        dealOneCardToPlayer()
            .then(dealOneCardToDealer)
            .then(dealOneCardToPlayer)
            .then(dealOneCardToDealer(true));

        //dealOneCardToPlayer();
        //dealOneCardToDealer(false);
        //dealOneCardToPlayer();

        //// true for hole card
        //dealOneCardToDealer(true);

        showGameButtons(true);
        checkEndGame1();
        checkGameOver();
    }

    const hit = () => {
        dealOneCardToPlayer();
        checkEndGame2();
        checkGameOver();
    }

    const stand = () => {
        // Recalculate dealer's hand value
        //dealer.handValue = countHandValue(dealer.cards);

        

        debugger;
        

        // Simple AI to automate dealer's decision to hit or stand
        if (dealer.handValue >= 17) {
            checkEndGame3();
        } else {
            // Hit until dealer's hand value is more than 16
            while (dealer.handValue < 17) {
                dealOneCardToDealer();
                checkEndGame3();
            }
        }
        checkGameOver();
    }
</script>

标签: javascript

解决方案


我认为正确的方法是承诺:

const DELAY = 2000;

function dealCardToPlayer() {
  return new Promise(function(resolve) { 
    setTimeout(function() {
      console.log('Dealing card to player');
      resolve();
    }, DELAY);
  });
}


function dealCardToDealer() {
  return new Promise(function(resolve) { 
    setTimeout(function() {
      console.log('Dealing card to dealer');
      resolve();
    }, DELAY);
  });
}

dealCardToPlayer()
  .then(dealCardToDealer)
  .then(dealCardToPlayer)
  .then(dealCardToDealer);


推荐阅读