0

I have made a little Blackjack game, and I'd like to make the computer wait between each card he pulls, however using System.Threading.Thread.Sleep(int x) does not make the program wait between cards, but makes it wait for x * amount of cards..
I also know that using Thread.Sleep is not a good way, so I'd rather learn a better way as I am creating this program entirely for educative purposes.
I'll add the code underneath which decides whether or not a card should be drawn, and the method that draws the card.

private void ComputerTurn()
{
    drawCard.Enabled = false;
    finishTurn.Enabled = false;

    while (computerTotalScore <= 11)
    {
        ComputerDrawCard();
    }

    drawAgain = true;
    while (drawAgain)
    {
        ComputerDrawCard();

        if (totalScore <= 21)
        {
            if (computerTotalScore > totalScore)
            {
                drawAgain = false;
            }
            else
            {
                drawAgain = true;
            }
        }
        else
        {
            if (computerTotalScore > 16)
            {
                drawAgain = false;
            }
            else
            {
                drawAgain = true;
            }
        }
    }
    DecideWinner();
}

public void ComputerDrawCard()
{
    cardAlreadyPulled = true;

    while (cardAlreadyPulled)
    {
        cardType = random.Next(0, 4);
        cardNumber = random.Next(0, 13);

        if (!pulledCards[cardType, cardNumber])
        {
            cardAlreadyPulled = false;
            pulledCards[cardType, cardNumber] = true;
        }
    }

    ComputerUpdateCardPictures();

    computerScore = cardScores[cardNumber];
    if (computerScore == 1)
    {
        if (computerTotalScore <= 10)
        {
            computerScore = 11;
        }
        else
        {
            computerScore = 1;
        }
    }
    computerTotalScore += computerScore;
    txtComputerCurrentScore.Text = computerScore.ToString();
    txtComputerTotalScore.Text = computerTotalScore.ToString();
    System.Threading.Thread.Sleep(random.Next(250, 750));
}
csharpwinphonexaml
  • 3,659
  • 10
  • 32
  • 63
anthonytimmers
  • 258
  • 1
  • 8

2 Answers2

0

I would add a last time drawn and time between draws members. Then before drawing a card, get the time between now and the last time pulled. If the time is greater than the allowed time between the draws its cool to draw.

private DateTime _lastWrite = DateTime.Now;
private TimeSpan _delay = TimeSpan.FromMilliseconds(100);

public void ComputerDrawCard() {
    var now = DateTime.Now;

    if (now - _lastWrite < _delay)
        return;

    _lastWrite = now;

    draw card...
}

Here's a gist of an example working correctly.

Neil Smith
  • 2,565
  • 1
  • 15
  • 18
  • Thank you for answering my question. When I try to use var's it does not recognize them as a datatype, any way to fix this? – anthonytimmers May 01 '14 at 17:37
  • @user3593590 Replace `var` with the real types like `DateTime now` instead of `var now`. (it's a C# 3.0 feature, see [what does “var” mean in C#?](http://stackoverflow.com/q/4307467/247702)) – user247702 May 01 '14 at 17:38
  • How do I put an int into the TimeSpan timeBetweenDraws? – anthonytimmers May 01 '14 at 17:44
  • You can do timeBetweenDraws = new TimeSpan(0, 0, 0); The first 0 is hours, the second is minutes, the third is seconds. – Neil Smith May 01 '14 at 17:49
  • Figured it out, using TimeSpan.FromMilliseconds(). It doesn't fix it, though. It freezes when the computer starts now. – anthonytimmers May 01 '14 at 17:50
  • Initialize lastTimeDrawn before getting timeSinceDraw. You can't subtract a null value from a datetime. – Neil Smith May 01 '14 at 17:51
  • I have changed the code a bit, which made the program not freeze anymore. However it still doesn't pause IN BETWEEN cards, but pauses all together and then shows all cards. Are you sure that using DateTime is a good way to keep track of something which is rather small (milliseconds)? – anthonytimmers May 01 '14 at 18:12
  • It's correctly waiting for 500 ms every card it draws, however it doesn't display any of the cards being drawed and then it draws all of them together. Anyone got any clue why it is doing this? – anthonytimmers May 01 '14 at 18:24
  • Sorry about that, found a little issue with my answer. I edited the answer and linked to a gist showing an example. Should be working now. – Neil Smith May 01 '14 at 18:26
  • It sadly still isn't working. It still puts all the delays that should be in between cards at the end making 1 big delay, before showing all cards.. :( – anthonytimmers May 01 '14 at 18:29
  • Did you leave the call to Sleep at the bottom of ComputerDrawCard? If not, it has to be something to do with whats going on inside your loop but after the call to ComputerDrawCard. It looks like you call DecideWinner and ComputerUpdateCardPictures in the loop. I'd need to see what those are doing. But it would make sense to not see any card until the loop is completely done if you left the call to Sleep in. – Neil Smith May 01 '14 at 18:34
  • I'm not sure what you mean with the Sleep. By the way, I already found a way to cause delays between loops/actions, however these were on Console.. Here are the 2 method's you asked for: Nevermind, it won't let me add it as it's too many characters. Any way I can show it? – anthonytimmers May 01 '14 at 18:38
  • I mean at the bottom of your ComputerDrawCard method you call: System.Threading.Thread.Sleep(random.Next(250, 750));. If that's still there, take it out and let me know if it's still not working. – Neil Smith May 01 '14 at 18:43
  • @Smith.h.Neil No, I have removed all System.Threading.Thread.Sleep(), just used Control-F to check if I missed any, and I didn't. – anthonytimmers May 01 '14 at 18:46
0

There are multiple ways to achieve something like this. I believe what you're attempting to do is simulate a human taking time to do things. I recommend using a combination of expected wait times and a timer to achieve what you want.

class Example
{
    public Example()
    {
        // create a stalled timer
        _pulse = new Timer(this.TakeAction);
    }

    TimeSpan _drawdelay = TimeSpan.FromSeconds(2);
    DateTime _lastAction = DateTime.MinValue;
    Timer _pulse;

    public void Start()
    {
        // start the timer by asking it to call the worker method ever 0.5 seconds
        _pulse.Change(0, 500); 
    }

    public void Stop()
    {
        // stop the timer by setting the next pulse to infinitely in the future
        _pulse.Change(Timeout.Infinite, Timeout.Infinite);
    }

    void TakeAction(object x)
    {
        lock (_pulse)
        {
            DateTime now = DateTime.Now;
            if(now - _lastAction > _drawdelay)
            {
                // do work ...
                _lastAction = now;
            }
        }
    }
}

That said, the above code will run into issues if the work being done takes longer than 500 milliseconds to complete. Add thread safety as necessary.

whoisj
  • 398
  • 1
  • 2
  • 10