0
votes

I am writing a mini card game for my RPG. Rules are simple: 2 cards are drawn randomly and highest card wins. Cards have ranks (2 - 14, where 14 is Ace) and suits (1-4 where 4 is highest spades)) However, if player is about to lose, player luck stats kick in which will help.

For testing purposes player luck value is set to 5, which will give max increase to card rank +4 (e.g if I had 2 of hearts, I will get 6 of hearts), however max rank can be 10. if cards of same rank drawn, then cards will be swapped so that player has highest rank.

While testing, I am observing very inconsistent behavior:

  1. On many occasions for loop will fail to locate an adjusted card in array
  2. On one occasion I had SAME (same rank, same suit) card drawn twice from deck (10 of spades) despite of having splice().

Problem 1 happens way more often that problem 2 and I am at a loss.

Here is the code:

var gamingParlor = {

  cards: {
s2: {suit: 4, rank: 2, name: '2 of spades'},
s3: {suit: 4, rank: 3, name: '3 of spades'},
s4: {suit: 4, rank: 4, name: '4 of spades'},
s5: {suit: 4, rank: 5, name: '5 of spades'},
s6: {suit: 4, rank: 6, name: '6 of spades'},
s7: {suit: 4, rank: 7, name: '7 of spades'},
s8: {suit: 4, rank: 8, name: '8 of spades'},
s9: {suit: 4, rank: 9, name: '9 of spades'},
s10: {suit: 4, rank: 10, name: '10 of spades'},
s11: {suit: 4, rank: 11, name: 'Jack of spades'},
s12: {suit: 4, rank: 12, name: 'Queen of spades'},
s13: {suit: 4, rank: 13, name: 'king of spades'},
s14: {suit: 4, rank: 14, name: 'Ace of spades'},

h2: {suit: 3, rank: 2, name: '2 of hearts'},
h3: {suit: 3, rank: 3, name: '3 of hearts'},
h4: {suit: 3, rank: 4, name: '4 of hearts'},
h5: {suit: 3, rank: 5, name: '5 of hearts'},
h6: {suit: 3, rank: 6, name: '6 of hearts'},
h7: {suit: 3, rank: 7, name: '7 of hearts'},
h8: {suit: 3, rank: 8, name: '8 of hearts'},
h9: {suit: 3, rank: 9, name: '9 of hearts'},
h10: {suit: 3, rank: 10, name: '10 of hearts'},
h11: {suit: 3, rank: 11, name: 'Jack of hearts'},
h12: {suit: 3, rank: 12, name: 'Queen of hearts'},
h13: {suit: 3, rank: 13, name: 'king of hearts'},
h14: {suit: 3, rank: 14, name: 'Ace of hearts'}

},

  playGame: function(stakeValue){
    var cardDeck = [];
    for (var key in gamingParlor.cards){
    cardDeck.push(gamingParlor.cards[key]);
    }
console.log('Deck length is: ' +cardDeck.length);
var playerCard = cardDeck[Math.floor(Math.random()*cardDeck.length)];
  console.log('player: ' +playerCard.name);
  var playerCardIndex = cardDeck.indexOf(playerCard);
  console.log('Player card index is' +playerCardIndex);
  cardDeck.splice(playerCardIndex, 1);
  console.log(cardDeck.length);      
var oponentCard = cardDeck[Math.floor(Math.random()*cardDeck.length)];
  console.log('opponent: ' +oponentCard.name);

if (playerCard.rank > oponentCard.rank){ // (1) No action needed - player wins naturally
        console.log('Player wins on highest rank naturally');

}else if (playerCard.rank < oponentCard.rank) { // player will lose if luck does not kick in
  if (player.stats.luck.counter > 1){ //player luck kicks in and there might be card adjustment

    if (playerCard.rank < gameConfig.bonus.maxCardRank){ //there is space for further rank increase and adjustment will be made
      playerCard.rank = playerCard.rank + gameConfig.bonus.cardRankIncrease;
      console.log('player got initial card rank increase. rank before adjustment is: ' + playerCard.rank);
      console.log('player card rank now is ' + playerCard.rank);
      if (playerCard.rank > gameConfig.bonus.maxCardRank){ //ensure that rank after increase does not exceed max allowed value
        playerCard.rank = gameConfig.bonus.maxCardRank
        console.log('Rank exceeded, adjusting to maxRank: ' + playerCard.rank);
        console.log('suit is:' +playerCard.suit);
      }
      if (playerCard.rank === oponentCard.rank && playerCard.suit === oponentCard.suit ){ //check if there is card collision after adjustment. 
        console.log('Player loses. There is card collision after adjustment');
        console.log('Player card is: ' + playerCard.name);
        console.log('Oponent card is: ' + oponentCard.name);

      } else { //no card collision
          console.log('No card collision after adjustment. Will update card and resove game now');
          for (var i=0; i < cardDeck.length; i++){
            if (cardDeck[i].rank === playerCard.rank && cardDeck[i].suit === playerCard.suit){ //locate new card in the deck
              playerCard.name = cardDeck[i].name; //update player card property. URL goes here.
              console.log('After foor loop - Player card is: ' + playerCard.name);
            } else {
              console.log('foor loop - card not found! ERROR!');

            }

          }

          if (playerCard.rank > oponentCard.rank){
            console.log('Player wins naturally due to higher after adjustment');
            console.log('Player card is: ' + playerCard.name);
            console.log('Opponent card is: ' + oponentCard.name);    

          } else if (playerCard.rank < oponentCard.rank){
            console.log('Oponent wins naturally due to higher rank after adjustment');
            console.log('Player card is: ' + playerCard.name);
            console.log('Opponent card is: ' + oponentCard.name);    

          } else { //ranks are the same but suits are not.
            if (playerCard.suit > oponentCard.suit){
              console.log('Player wins due to higher suit');
              console.log('Player card is: ' + playerCard.name);
              console.log('Opponent card is: ' + oponentCard.name);    

            } else {
              console.log('Opponent wins due to higher suit');
              console.log('Player card is: ' + playerCard.name);
              console.log('Opponent card is: ' + oponentCard.name);                      
            }              
          }
      }

    }else { //rank cannot be increased as player already got a card >= 10
      console.log('Player looses. Although luck kicks in, player already has a high enough card');
    }

  }else { //player does not have sufficient luck to affect ranking
      console.log('Player loses -  insufficient luck to affect ranking');
  }

}else { // ranks are the same      
  if (playerCard.suit > oponentCard.suit){ // player wins naturally due to highest suit
      console.log('Player wins due to highest suit');
  }else { // player will lose if luck does not kick in
    if(player.stats.luck.counter > 0) { // player luck kicks in
      console.log('Ranks are same and player got a lower suit, but player has luck and cards will be swapped');
      var tmp = playerCard; //swap reference to objects   
      playerCard = oponentCard;
      oponentCard = tmp;
      console.log('Player wins. Card is now: ' + playerCard.name);
      console.log('Opponent loses. Card is now: ' + oponentCard.name);                       
    }else { // player luck does not kick in              
      console.log('Player loses. Ranks are same but player is out of luck and got lower suit');         
    } 
  }    
} 

  console.log('Cards are now graphically dealt, revealed and removed one after another');



  } //function end
}; 

And here is a log of a real test I did where FOR loop failed:

city.js:143 Deck length is: 26Deck length is: 26
city.js:145 player: 3 of hearts
city.js:147 Player card index is14
city.js:149 25
city.js:151 opponent: 5 of spades
city.js:161 player got initial card rank increase. rank before adjustment is: 7
city.js:162 player card rank now is 7
city.js:174 No card collision after adjustment. Will update card and resove game now
city.js:149 25
city.js:180 foor loop - card not found! ERROR!
city.js:187 Player wins naturally due to higher after adjustment
city.js:188 Player card is: 3 of hearts
city.js:189 Opponent card is: 5 of spades
city.js:235 Cards are now graphically dealt, revealed and removed one after another
1
I don't think this line is doing what you think it's doing: cardDeck[i].rank === playerCard.rank && cardDeck[i].suit === playerCard.suit){Cooper Buckingham
@CH Buckingham yes, obviously at times this line fails to locate card in an array. I expect this line to pick up a card with a new rank while keeping the original suite. I noticed that when I begin testing this problem does not happen, however, the further I test the more instances i see, so my though was that the actual array containing cards is affected somehow. Is anyone able to reproduce this behavior? The maxRang variable is 10 and cardRankIncrease is 4.Vadimster
Indeed something is happening to the array. I debug further and print in console all cards int the Foor loop. Here is an example of what is happening: 1. Player card is 5 of spades (rank 5, suit 4) 2. Choice is adjusted to 9 of spades (rank 9, suit 4) 3. In the foor loop, it appears that 9 of spades is missing in the array of objects, instead I have 2 x 10 of spades. Script searches for rank 9, suit 4 card but obviously fails:Vadimster
city.js:176 Element5rank is: 8 | city.js:177 Element5suit is: 4 | city.js:182 foor loop - card not found! ERROR! | city.js:176 Element6rank is: 10 <----- !!!! | city.js:177 Element6suit is: 4 | city.js:182 foor loop - card not found! ERROR! | city.js:176 Element7rank is: 10 <----- !!!! | city.js:177 Element7suit is: 4 | city.js:182 foor loop - card not found! ERROR! | city.js:176 Element8rank is: 11 | city.js:177 Element8suit is: 4 | city.js:182 foor loop - card not found! ERROR! |Vadimster
Right, deeper review showed that by the time the for loop runs the array is really messed up. Some objects are missing and others are duplicated instead. I will consider alternative handling of array, will try to construct it outside the function just in case.Vadimster

1 Answers

0
votes

problem detected and solved.

Since var playerCard is a reference to an object, this original object get adjusted whenever var playerCard is adjusted.

Thus, the deck after every adjustment is composed of modified cards. The foor loop fails.