BlackJack算法

时间:2011-09-02 09:05:12

标签: c++ algorithm blackjack

BlackJack游戏的一般alogirthm是什么? 我正在用c ++编写一个,如果语句破坏整个事情,最终会有太多的错误。

该项目是一个win32 GUI应用程序,我发布消息循环以及检查游戏状态的程序部分 发布完整的代码将使它变得非常庞大,所以这里是所有文件的链接: Full Source Code

消息循环

LRESULT CALLBACK WndProc( HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam ){
  switch(Msg)
  {
  case WM_PAINT:
  {
      PAINTSTRUCT PS;
      HDC hDC = BeginPaint(hWnd, &PS);
      You.Draw(hDC);
      Dealer.Draw(hDC);
      EndPaint(hWnd, &PS);
      if(Bet.Enabled){
          Bet.GetFocus();
          Bet.Select(0,Bet.Length());
      }
  }
  return 0;
  case WM_CTLCOLORSTATIC:
  {
      SetBkMode((HDC)wParam, TRANSPARENT);
  }
  return (INT_PTR)(HBRUSH)GetStockObject(NULL_BRUSH);
  case WM_CREATE:
  {
      //Create edit control
      Bet.Create(hWnd, 10, 550, 100, 25, "0");
      //Create labels
      char Buffer[30];
      sprintf(Buffer, "%d", You.HandValue());
      BetLabel.Create(hWnd, 10, 500, 100, 40, "Enter Bet Amount");
      GameControls.Create(hWnd, 10, 375, 100, 40, "Game Controls");
      PlayerLabels.Create(hWnd, 10, 10, 100, 20, "You:");
      PlayerLabels.Create(hWnd, 10, 150, 100, 20, "Dealer:");
      HandValueLabel.Create(hWnd, (int)You.x[You.cards] + 85, (int)You.y[You.cards] + 25, 100, 20, Buffer);
      YourMoney.Create(hWnd, 125, 500, 100, 40, "Your money: ");
      sprintf(Buffer, "%d", You.money);
      MoneyValue.Create(hWnd, 125, 525, 100, 40, Buffer);
      //Create buttons
      Ok.Create(hWnd, 10, 600, 100, 50, "Ok");
      Hit.Create(hWnd, 10, 425, 100, 50, "Hit");
      Stand.Create(hWnd, 120, 425, 100, 50, "Stand");
      //Select Text
      Bet.Select(0,3);
  }
  return 0;
  case WM_CLOSE:
    exit(0);
    break;
  case WM_COMMAND:
  {
      switch(HIWORD(wParam))
      {
      case BN_CLICKED:
      {
          switch(LOWORD(wParam))
          {
          case ID_OK:
          {
              //Place bet
              int bet = 0;
              bet = StringToNumber(Bet.Text());
              You.money -= bet;
              char Buffer[30];
              sprintf(Buffer, "%d", You.money);
              MoneyValue.SetText(Buffer);
              //Update the window
              InvalidateRect(hWnd, 0, TRUE);
              You.Bet = YES;
              Ok.Disable();
              Bet.Disable();
              You.DealCard();
              You.DealCard();
              Dealer.DealCard();
              Dealer.DealCard();
              You.win = false;
              You.bust = false;
              You.playing = YES;
              Dealer.win = NO;
              Dealer.bust = NO;
              Dealer.playing = YES;
          }
          break;
          case ID_HIT:
          {
             if(You.HandValue() < 21 && You.playing && !You.bust){
                 //Deal a card to the player, if he hasn't won or lost
                 You.DealCard();
             }
             if((Dealer.HandValue() <= 17 || Dealer.HandValue() < You.HandValue()) && Dealer.playing)
                       {
                         Dealer.DealCard();
                       }
            //Update Hand Value
            char Buffer[30];
            sprintf(Buffer, "%d", You.HandValue());
            HandValueLabel.SetText(Buffer);
            InvalidateRect(hWnd,0,TRUE);
            MoveWindow(HandValueLabel.Handle, (int)You.x[You.cards] + 80, (int)You.y[You.cards] + 25, 100, 20, TRUE);
            RedrawWindow(hWnd, NULL, NULL, RDW_INVALIDATE | RDW_INTERNALPAINT);
          }
          break;
          case ID_STAND:
              if(Hit.Enabled){
                  //Don't deal more cards
                  Hit.Disable();
                  You.playing = false;
              }
              if((Dealer.HandValue() <= 17 || Dealer.HandValue() < You.HandValue()) && Dealer.playing){
                  //Deal a card to the dealer
                  Dealer.DealCard();
              }
          }

StatusChecker

void ProcessStatus(HWND hWnd){
     if(Dealer.HandValue() > 17){
          if(Dealer.HandValue() > You.HandValue() && Dealer.playing){
              Dealer.playing = false;
            }
          else if(!You.playing && Dealer.HandValue() <= You.HandValue() && Dealer.playing){
              Dealer.DealCard();
            }
        }
      else if(Dealer.HandValue() <= 17 && Dealer.HandValue() <= You.HandValue() && !You.playing && Dealer.playing){
          Dealer.DealCard();
        }
      if(EvaluateStatus() != 0){
          status = OVER;
        }
     if(EvaluateStatus() == -1){
         switch(MessageBoxA(hWnd, "You Lost! \n Keep Playing ?", "You Lost!", MB_YESNO | MB_ICONQUESTION))
         {
         case IDYES:
             Reset();
             break;
         case IDNO:
             exit(0);
             break;
         }
     }
     else if(EvaluateStatus() == 1){
         switch(MessageBoxA(hWnd, "You Won! \n Keep Playing ?", "You Won!", MB_YESNO | MB_ICONQUESTION))
         {
         case IDYES:
             Reset();
             break;
         case IDNO:
             exit(0);
             break;
         }
     }
    }
int EvaluateStatus()
{
  if(You.HandValue() > 21 && You.playing)
    {
      You.bust = true;
      Dealer.win = true;
      You.playing = NO;
      return -1;
    }
  if(You.HandValue() == 21)
    {
      You.win = true;
      return 1;
    }
  if(Dealer.HandValue() > 21)
    {
      Dealer.bust = true;
      You.win = true;
      return 1;
    }
  if(Dealer.HandValue() == 21)
    {
      Dealer.win = true;
      return -1;
    }
  if(!You.playing && Dealer.HandValue() > You.HandValue() &&!Dealer.bust)
    {
      Dealer.win = true;
      return -1;
    }
  if(You.HandValue() > Dealer.HandValue() && (!You.playing && (!Dealer.playing || Dealer.bust)))
    {
      You.win = true;
      return 1;
    }
  if(You.HandValue() == Dealer.HandValue() && (!You.playing || !Dealer.playing))
    {
      You.win = true;
      return 1;
    }

3 个答案:

答案 0 :(得分:2)

作为第一步:我可能不会混合游戏逻辑和GUI逻辑......将它们分成不同的模块。

如果你只有两名球员,你只需要一个布尔来决定赢得哪一名。你不需要两个玩家Bust和Won变量。

答案 1 :(得分:1)

Google搜索在BlackJack算法上显示this PDF paper。我敢肯定,如果您使用Google进行更多研究,您也可以找到它。

要弄清楚如何计算游戏需要完成的实际步骤,在纸上计算游戏的不同步骤,然后决定如何创建代表游戏部分和功能的类。用于执行游戏不同步骤的类。'

这可能是一个迭代的事情,你经历它,然后创建一些类,函数等,现在你可以回去看看你做了什么是有意义的,改进设计等。

也许还会玩游戏,看看做了什么,如何将其翻译成代码。

答案 2 :(得分:0)

我修改了程序处理邮件的方式,并将其作为单独的答案发布。 由于轻微的打嗝,它仍然被打破,但我认为一般的想法是坚实的。评论将不胜感激

cards.h

/*
 * cards.h
 *
 *  Created on: Aug 31, 2011
 *      Author: Viraj
 */
#ifndef CARDS_H_
#define CARDS_H_
#include <iostream>
#include <algorithm>
#define STARTED true
#define OVER false
#define YES true
#define NO false
using namespace std;
HINSTANCE hApplication;
HBITMAP Bitmap;
char Buffer[30];
class Deck{
public:
    int deck[53];
    Deck(){
        for(int suit = 1; suit <= 4; suit++){
            for(int card = 1; card <= 13; card++){
                deck[((suit-1)*13)+card] = card;
            }
        }
        deck[0] = 0;
    }
};
Deck deck;
class Cards{
private:
    int card_seed;
    int suit_seed;
public:
    int card[11];
    int cards;
    int value[11];
    Cards(){
        fill(card, card + 10, 0);
        fill(value, value + 10, 0);
        cards = 0;
    }
    void DealCard()
    {
        cards++;
        while(!deck.deck[card[cards]]){
            card_seed = rand()%13 + 1;
            suit_seed = rand()%4 + 1;
            card[cards] = (suit_seed - 1)*13 + card_seed;
        }
        deck.deck[card[cards]] = 0;
        if(card_seed > 1 && card_seed < 11){
             value[cards] = card_seed;
        }
        else if(card_seed >= 11 && card_seed <= 13){
            value[cards] = 10;
        }
        else if(card_seed == 1){
            value[cards] = 11;
        }
    }
};
class Player : public Cards {
public:
    float x[11];
    float y[11];
    bool playing;
    bool bust;
    bool win;
    int money;
    Player(const char* Type){
        srand(time(NULL));
        playing = true;
        if(Type == "Dealer"){
            for(int card = 1; card <= 10; card++){
                x[card] = 10 + (card-1)*75;
                y[card] = 200;
            }
        }
        else{
            for(int card = 1; card <= 10; card++){
                x[card] = 10 + (card-1)*75;
                y[card] = 35;
                money = 1000;
            }
        }
    }
    void Reset(){
        cards = 0;
        fill(card, card + 10, 0);
        fill(value, value + 10, 0);
        playing = true;
    }
    int HandValue(){
        int sum = 0;
        for(int current_card = 1; current_card <= cards; current_card++){
            sum += value[current_card];
          }
        if(sum > 21){
            for(int current_card = 1; current_card <= cards; current_card++){
                if(value[current_card] == 11 && sum > 21){
                    value[current_card] = 1;
                    sum = HandValue();
                    break;
                  }
              }
          }
        return sum;
    }
    void Draw(HDC hDC){
        HDC MemoryDevice;
        for(int CardToLoad = 1; CardToLoad <= cards; CardToLoad++){
            Bitmap = LoadBitmap(hApplication, MAKEINTRESOURCE(card[CardToLoad]));
            MemoryDevice = CreateCompatibleDC(hDC);
            SelectObject(MemoryDevice, Bitmap);
            BitBlt(hDC, (int)x[CardToLoad], (int)y[CardToLoad], 75, 100, MemoryDevice, 0, 0, SRCCOPY);
        }
        DeleteDC(MemoryDevice);
    }
};
class CONTROL{
public:
    HWND Handle;
    char* ClassName;
    char* Caption;
    DWORD ClassStyle;
    DWORD ExtendedStyle;
    int x;
    int y;
    int Width;
    int Height;
    int ID;
    bool Enabled;
    void Create(HWND ParentHandle, int x, int y, int Width, int Height, char* Caption){
        Handle = CreateWindowExA(ExtendedStyle, ClassName, Caption, ClassStyle, x, y, Width, Height, ParentHandle, (HMENU)ID, NULL, NULL);
        Enabled = true;
        CONTROL::Caption = Caption;
        CONTROL::x = x;
        CONTROL::y = y;
        CONTROL::Width = Width;
        CONTROL::Height = Height;
    }
    void GetFocus(){
        SetFocus(Handle);
    }
    void Disable(){
        EnableWindow(Handle, FALSE);
        Enabled = false;
    }
    void Enable(){
        EnableWindow(Handle, TRUE);
        Enabled = true;
    }
    void SetText(char* String){
        SetWindowTextA(Handle, String);
    }
};
class BUTTON : public CONTROL {
public:
    BUTTON(int Identifier){
        ClassStyle = BS_PUSHBUTTON | WS_VISIBLE | WS_CHILD;
        ID = Identifier;
        ClassName = "BUTTON";
        ExtendedStyle = 0;
    }
};
class EDIT : public CONTROL {
public:
    EDIT(int Identifier){
        ClassStyle = ES_NUMBER | WS_VISIBLE | ES_CENTER | WS_CHILD | ES_NOHIDESEL;
        ExtendedStyle = WS_EX_CLIENTEDGE;
        ID = Identifier;
        ClassName = "EDIT";
    }
    void Select(int first, int last){
        Edit_SetSel(Handle, first, last);
    }
    int Length(){
        return Edit_GetTextLength(Handle);
    }
    const char* Text(){
        char Buffer[Length() + 1];
        Edit_GetText(Handle, (LPTSTR)&Buffer, Length() + 1);
        string String = Buffer;
        return String.c_str();
    }
};
class STATIC : public CONTROL {
public:
    STATIC() {
        ClassStyle = WS_VISIBLE | SS_CENTER | WS_CHILD;
        ID = 0;
        ClassName = "STATIC";
        ExtendedStyle = 0;
    }
};
Player You("You"), Dealer("Dealer");
BUTTON Ok(ID_OK), Hit(ID_HIT), Stand(ID_STAND);
EDIT Bet(ID_BET);
STATIC BetLabel, GameControls, PlayerLabels, HandValueLabel, YourMoney, MoneyValue, Bust;
class Game{
public:
    bool started;
    Game(){
        started = false;
    }
    void Stop(){
        started = false;
    }
    void ResetGame(HWND hWnd){
        //Reset Players
        You.Reset();
        Dealer.Reset();
        //Reset Controls
        Ok.Enable();
        Bet.Enable();
        Hit.Enable();
        //Reset Hand value
        sprintf(Buffer, "%d", You.HandValue());
        HandValueLabel.SetText(Buffer);
        //Reset deck
        deck = Deck();
        //Stop the game
        started = false;
        //Update the Display
        InvalidateRect(hWnd, 0, TRUE);
        RedrawWindow(hWnd, NULL, NULL, RDW_INVALIDATE | RDW_INTERNALPAINT);
    }
    int SendMessage(HWND hWnd, int ButtonID, unsigned int MESSAGE, int Information, char* _Information){
        return ProcessMessage(hWnd, ButtonID, MESSAGE, Information, _Information);
    }
    int ProcessMessage(HWND hWnd, int ButtonID, unsigned int MESSAGE, int Information, char* _Information){
        switch(MESSAGE)
        {
        case START_GAME:
            //Place Bet
            You.money -= Information;
            started = YES;
            sprintf(Buffer, "%d", You.money);
            //Update Controls
            MoneyValue.SetText(Buffer);
            Ok.Disable();
            Bet.Disable();
            //Deal two cards to player and dealer
            You.DealCard();
            You.DealCard();
            Dealer.DealCard();
            Dealer.DealCard();
            //Update the Hand Value Label
            sprintf(Buffer, "%d", You.HandValue());
            HandValueLabel.SetText(Buffer);
            //Move the label
            MoveWindow(HandValueLabel.Handle, (int)You.x[You.cards] + 80, (int)You.y[You.cards] + 25, 100, 20, TRUE);
            //Send PAINT message
            InvalidateRect(hWnd,0, TRUE);
            RedrawWindow(hWnd, NULL, NULL, RDW_INVALIDATE | RDW_INTERNALPAINT);
            //Check for BlackJacks
            if(You.HandValue() == 21){
                SendMessage(hWnd, 0, INTERNAL, YOU_WIN, "");
            }
            else if(Dealer.HandValue() == 21){
                SendMessage(hWnd, 0, INTERNAL, DEALER_WIN, "");
            }
            break;
        case STAND:
            if(started){
                Hit.Disable();
                You.playing = false;
            }
            break;
        case INTERNAL:
            switch(Information)
            {
            case DEALER_WIN:
                return MessageBoxA(hWnd, "You Loose! \n Play Again ?", "Game Over", MB_YESNO | MB_ICONINFORMATION);
            case YOU_WIN:
                return MessageBoxA(hWnd, "You Win! \n Keep Playing ?", "Game Over", MB_YESNO | MB_ICONINFORMATION);
            }
        break;
        case IDLE:
            if(started){
                //Check for BlackJacks
                if(Dealer.HandValue() == 21){
                    started = false;
                    switch(SendMessage(hWnd, 0, INTERNAL, DEALER_WIN, ""))
                    {
                    case IDYES:
                        ResetGame(hWnd);
                        return 0;
                    case IDNO:
                        exit(0);
                        return 0;
                    }
                }
                if(!You.playing && Dealer.playing && Dealer.HandValue() < You.HandValue())
                    Dealer.DealCard();
                    //Update the Window
                    InvalidateRect(hWnd,0, TRUE);
                    RedrawWindow(hWnd, NULL, NULL, RDW_INVALIDATE | RDW_INTERNALPAINT);
                    //Check for a Bust
                    if(Dealer.HandValue() > 21){
                        switch(SendMessage(hWnd, 0, INTERNAL, YOU_WIN, ""))
                        {
                        case IDYES:
                            ResetGame(hWnd);
                            return 0;
                        case IDNO:
                            exit(0);
                            return 0;
                        }
                    }
                    if(Dealer.HandValue() == 21){
                        switch(SendMessage(hWnd, 0, INTERNAL, YOU_WIN, ""))
                        {
                        case IDYES:
                            ResetGame(hWnd);
                            return 0;
                        case IDNO:
                            exit(0);
                            return 0;
                        }
                    }

                }
        break;
        case HIT:
            //Check to see who's still playing and deal a card to them
            if(started){
            if(You.playing){
                You.DealCard();
                //Update the Hand Value Label
                sprintf(Buffer, "%d", You.HandValue());
                HandValueLabel.SetText(Buffer);
                //Move the label and update the screen
                MoveWindow(HandValueLabel.Handle, (int)You.x[You.cards] + 80, (int)You.y[You.cards] + 25, 100, 20, TRUE);
                InvalidateRect(hWnd, 0, TRUE);
                RedrawWindow(hWnd, NULL, NULL, RDW_INVALIDATE | RDW_INTERNALPAINT);
                //Check for a BlackJack
                if(You.HandValue() == 21){
                    started = false;
                    switch(SendMessage(hWnd, 0, INTERNAL, YOU_WIN, ""))
                    {
                    case IDYES:
                        ResetGame(hWnd);
                        return 0;
                    case IDNO:
                        exit(0);
                        return 0;
                    }
                }
                //Check for a bust
                if(You.HandValue() > 21){
                    started = false;
                    switch(SendMessage(hWnd, 0, INTERNAL, YOU_WIN, ""))
                    {
                    case IDYES:
                        ResetGame(hWnd);
                        return 0;
                    case IDNO:
                        exit(0);
                        return 0;
                    }
                }
            }
            if(Dealer.playing){
                Dealer.DealCard();
                InvalidateRect(hWnd, 0, TRUE);
                RedrawWindow(hWnd, NULL, NULL, RDW_INVALIDATE | RDW_INTERNALPAINT);
                //Check for BlackJack
                if(Dealer.HandValue() == 21){
                    started = false;
                    switch(SendMessage(hWnd, 0, INTERNAL, DEALER_WIN, ""))
                    {
                    case IDYES:
                        ResetGame(hWnd);
                        return 0;
                    case IDNO:
                        exit(0);
                        return 0;
                    }
                }
                //Check for Bust
                if(Dealer.HandValue() > 21){
                    started = false;
                    switch(SendMessage(hWnd, 0, INTERNAL, YOU_WIN, ""))
                    {
                    case IDYES:
                        ResetGame(hWnd);
                        return 0;
                    case IDNO:
                        exit(0);
                        return 0;
                    }

                }
            }
            }
            break;
        }
        return 0;
    }
};
Game game;
#endif

消息循环

 switch(Msg)
  {
  case WM_PAINT:
  {
      PAINTSTRUCT PS;
      HDC hDC = BeginPaint(hWnd, &PS);
      You.Draw(hDC);
      Dealer.Draw(hDC);
      EndPaint(hWnd, &PS);
      if(Bet.Enabled){
          Bet.GetFocus();
          Bet.Select(0,Bet.Length());
      }
  }
  return 0;
  case WM_CTLCOLORSTATIC:
  {
      SetBkMode((HDC)wParam, TRANSPARENT);
  }
  return (INT_PTR)(HBRUSH)GetStockObject(NULL_BRUSH);
  case WM_CREATE:
  {
      //Create edit control
      Bet.Create(hWnd, 10, 550, 100, 25, "0");
      //Create labels
      char Buffer[30];
      sprintf(Buffer, "%d", You.HandValue());
      BetLabel.Create(hWnd, 10, 500, 100, 40, "Enter Bet Amount");
      GameControls.Create(hWnd, 10, 375, 100, 40, "Game Controls");
      PlayerLabels.Create(hWnd, 10, 10, 100, 20, "You:");
      PlayerLabels.Create(hWnd, 10, 175, 100, 20, "Dealer:");
      HandValueLabel.Create(hWnd, (int)You.x[You.cards] + 85, 60, 100, 20, Buffer);
      YourMoney.Create(hWnd, 125, 500, 100, 40, "Your money: ");
      sprintf(Buffer, "%d", You.money);
      MoneyValue.Create(hWnd, 125, 525, 100, 40, Buffer);
      //Create buttons
      Ok.Create(hWnd, 10, 600, 100, 50, "Ok");
      Hit.Create(hWnd, 10, 425, 100, 50, "Hit");
      Stand.Create(hWnd, 120, 425, 100, 50, "Stand");
      //Select Text
      Bet.Select(0,3);
  }
  return 0;
  case WM_CLOSE:
    exit(0);
    break;
  case WM_COMMAND:
  {
      switch(HIWORD(wParam))
      {
      case BN_CLICKED:
      {
          switch(LOWORD(wParam))
          {
          case ID_OK:
          {
              //Place bet
              int bet = 0;
              bet = StringToNumber(Bet.Text());
              game.SendMessage(hWnd, ID_OK, START_GAME, bet, "");
          }
          break;
          case ID_HIT:
          {
              //Tell the game that the player wants another card
              game.SendMessage(hWnd, ID_HIT, HIT, 0, "");
          }
          break;
          case ID_STAND:
              game.SendMessage(hWnd, ID_STAND, STAND, 0, "");
          }
      }
      break;
      }
    }
  break;
    default:
    //Default:
    game.SendMessage(hWnd, 0, IDLE, 0, "");
    return DefWindowProcA(hWnd, Msg, wParam, lParam);
    }
  return 0;
}