2013-09-09 2 views
0

У меня есть код на C++, имеющий дело с карточной игрой, и это непоправимо, и я не могу понять, почему. Я попытался запустить его в MSVS 2012, чтобы получить более явную ошибку, и он бросил «Вектор не разменяем». Я пробовал делать некоторые исследования, но я потерялся, откуда исходит ошибка. Я предполагаю, что ошибка не в push_back, а скорее где-то еще, поскольку проблемная линия работает большую часть времени. Ошибка возникает в таблице :: hit(). Просмотрев код, я думаю, что ошибка может быть в Hand :: split(), но я не уверен, и я еще менее уверен, как это исправить. Благодаря!Segfault/«Вектор не является разыменованным» на std :: vector push_back

class Hand 
{  
public: 
std::vector<Card> hand; 
bool active, doubled, isBlackjack, busted; 

Hand() : active(true), doubled(false), isBlackjack(false), busted(false) { } 
Hand(const Hand& _hand); 

void removeCard(Card card) { hand.erase(hand.begin()); } 
Card split(); 
void clear(); 
int cards() const { return hand.size(); } 
int getHandValue() const; 
Card at(int pos) { return hand[pos]; } 

friend std::ostream& operator<< (std::ostream& out, const Hand& hand); 
friend std::ostream& operator<< (std::ostream& out, const std::vector<Hand>& hands); 
}; 

Hand::Hand(const Hand& _hand) 
: hand(_hand.hand), active(_hand.active), doubled(_hand.doubled), isBlackjack(_hand.isBlackjack), busted(_hand.busted) 
{ } 

Card Hand::split() 
{ //COULD THE BELOW CODE BE CAUSING ISSUES? 
Card card = hand[0]; 

hand.erase(hand.begin()); 

return card;  
} 

void Hand::clear() 
{ 
active = true; 
hand.clear(); 
} 

int Hand::getHandValue() const 
{ 
int value(0), aces(0); 

for(std::vector<Card>::const_iterator it = hand.cbegin(); it != hand.cend(); ++it) 
{ 
    value += getCardValue(it->getRank()); 
    if(it->getRank() == ACE) 
     ++aces; 
} 

while(aces > 0 && value > 21) 
{ 
    value -= 10; 
    --aces; 
} 

return value; 
} 

std::ostream& operator<< (std::ostream& out, const Hand& hand) 
{ 
for(std::vector<Card>::const_iterator it = hand.hand.begin(); it != hand.hand.end(); ++it) 
{ 
    out << *it << " "; 
} 

out << hand.getHandValue(); 

return out; 
} 

std::ostream& operator<< (std::ostream& out, const std::vector<Hand>& hands) 
{ 
for(std::vector<Hand>::const_iterator it = hands.begin(); it != hands.end(); ++it) 
{ 
    out << *it << " "; 
} 

return out; 
} 

class Table 
{ 
protected: 
Shoe shoe; 
Strategy strat; 
Hand dealer; 
std::vector<Hand> player; 

double balance, blackjackPayoff; 
bool hitSoft17; 

void deal(); 

void hit(int split=0); 

void split(int split=0); 

double stand(); 

Action getUserAction(); 

bool isCurrentGame(); 

public: 
Table(int decks, int _balance); 

double bet; 

void play(); 

void print(); 

void simulate(std::string fileName, int hands); 
}; 

Table::Table(int decks, int _balance) 
: shoe(decks), balance(_balance), blackjackPayoff(1.5), hitSoft17(true), bet(10) 
{} 

bool Table::isCurrentGame() 
{ 
for(std::vector<Hand>::iterator it = player.begin(); it != player.end(); ++it) 
{ 
    if(it->active) 
     return true; 
} 

return false; 
} 

void Table::deal() 
{ 
dealer.clear(); 
player.clear(); 

dealer.addCard(shoe.pullCard(true)); 
dealer.addCard(shoe.pullCard()); 

player.push_back(Hand()); 

player[0].addCard(shoe.pullCard()); 
player[0].addCard(shoe.pullCard()); 

if(player[0].getHandValue() == 21 && dealer.getHandValue() == 21) 
{ 
    player[0].active = false; 
} 
else if(player[0].getHandValue() == 21) 
{ 
    player[0].active = false; 
} 
else if(dealer.getHandValue() == 21) 
{ 
    player[0].active = false; 
} 

} 

void Table::hit(int split) 
{ 
player[split].hand.push_back(shoe.pullCard()); //SEGFAULT HERE 

if(player[split].getHandValue() > 21) 
{ 
    player[split].active = false; 
} 
} 

void Table::split(int split) 
{ 
player.push_back(Hand()); 
player[player.size() - 1].hand.push_back(player[split].split()); 
player[split].hand.push_back(shoe.pullCard()); 
player[player.size() - 1].hand.push_back(shoe.pullCard()); 

if(player[split].getHandValue() == 21) 
{ 
    player[split].active = false; 
} 
else if(player[player.size() - 1].getHandValue() == 21) 
{ 
    player[player.size() - 1].active = false; 
} 

} 

double Table::stand() 
{ 
double winnings(0.0); 
bool allNats(true); 
//dealer.push_back(shoe.pullCard()); 
for(std::vector<Hand>::iterator it = player.begin(); it != player.end(); ++it) 
{ 
    if(it->cards() == 2 && it->getHandValue() == 21) 
    { 
     winnings += bet * blackjackPayoff; 
     it->isBlackjack = true; 
    } 
    else 
    { 
     allNats = false; 
     if(it->getHandValue() > 21) 
      it->busted = true; 
    } 
} 

if(!allNats) 
{ 
    while(dealer.getHandValue() <= 17) 
    { 
     if(dealer.getHandValue() == 17) 
     { 
      //dealer has 17 and doesnt hit soft 17s so hes not going to draw anymore cards 
      if(!hitSoft17 || dealer.cards() != 2 || !(dealer.hand.at(0) == ACE || dealer.hand.at(1) == ACE)) 
       break; 
     } 

     dealer.addCard(shoe.pullCard()); 
    } 
} 

for(std::vector<Hand>::iterator it = player.begin(); it != player.end(); ++it) 
{ 
    if(!it->isBlackjack) 
    { 
     if(it->busted) 
     { 
      if(it->doubled) 
       winnings -= 2.0 * bet; 
      else 
       winnings -= bet; 
     } 
     else if(dealer.getHandValue() > 21 || dealer.getHandValue() < it->getHandValue()) 
     { 
      if(it->doubled) 
       winnings += 2.0 * bet; 
      else 
       winnings += bet; 
     } 
     else if(dealer.getHandValue() > it->getHandValue()) 
     { 
      if(it->doubled) 
       winnings -= 2.0 * bet; 
      else 
       winnings -= bet; 
     } 
    } 
} 
//only other scenario is a push which we dont do anythign for 

return winnings; 
} 

void Table::simulate(std::string fileName, int hands) 
{ 
int i(0), countHL; 
double trueCountHL; 
std::ofstream ofs(fileName); 

Action action; 

while(i < hands) 
{ 
    deal(); 
    VisibleCards vc(player[0].at(0), player[0].at(1), dealer.at(0)); 
    while(isCurrentGame()) 
    { 
     int j(0), q(1); 
     countHL = shoe.getCountHL(); 
     trueCountHL = shoe.getTrueCountHL(); 

     for(int l = 0; l < q; ++l) 
     { 
      while(player[l].active) 
      { 

       if(player[l].cards() == 2) 
        action = getBasicStrategy(player[l].getHandValue(), dealer.at(0).getCardValue(), 
           player[l].at(0).getCardValue(), player[l].at(1).getCardValue()); 
       else 
        action = getBasicStrategy(player[l].getHandValue(), dealer.at(0).getCardValue()); 

       switch(action) 
       { 
       case HIT: 
        hit(j); 
        break; 
       case DOUBLE: 
        hit(j); 
        if(player[l].cards() == 3) 
        { 
         player[l].doubled = true; 
         player[l].active = false; 
        } 
        break; 
       case SPLIT: 
        if(player.size() <= 4) 
        { 
         split(j); 
         ++q; 
        } 
        else 
         hit(j); 

        break; 
       case STAND: 
        player[l].active = false; 
        break; 
       } 

       ++j; 
      } 
     } 
    } 

    double winnings = stand(); 
    balance += winnings; 

    ofs << std::endl << std::fixed << vc << "," << winnings << "," << std::setprecision(2) << trueCountHL 
     << "," << balance << "," << std::setprecision(0) << countHL << "," << shoe.getRemainingDecks(); 
    ofs << std::endl << 1; 
    //BlackjackData bjd(winnings, balance, shoe.getTrueCountHL(), shoe.getCountHL(), HIT);  
    //strat.addData(vc, bjd); 
    ++i; 
} 

strat.print(fileName); 
} 
+3

Полная программа с входами, которая демонстрирует проблему, была бы идеальной. –

ответ

2

Похоже, вы пытаетесь получить первую карту из hand с hand[0] и hand.erase(hand.begin()) без предварительной проверки, что есть первая карта. Если hand пуст (как в случае с новым созданным Hand от конструктора), это вызывает неопределенное поведение, которое может проявиться в результате сбоя в более позднее время.

+0

Это определенно потенциальная проблема, с которой мне нужно обратиться, но, похоже, это не проблема, я попытался проверить, была ли каждая пустая, но это не так. Далее я отлаживался в MSVS, и, похоже, был действительный объект карты (имел ранг и костюм), пытающийся быть отброшен обратно в вектор прямо перед сбоем. – user2183336

0

Я смотрел на это в течение дня и не мог понять, вышел и понял, что у меня есть старая переменная «j», которую я использовал для доступа к вектору вместо «l», когда я звонил в " нажмите "функцию .... Спасибо всем за помощь.

Смежные вопросы