Home > Software design >  Black Jack, adding card values together problem
Black Jack, adding card values together problem

Time:10-08

I have a problem with my function that should add card values together. When i call the function with these arguments it logs 21 as it should.

score([{ suit: 'HEARTS', value: 1 }, { suit: 'SPADES', value: 11 }]) //Logs 21 as it should

But when i call the function with the same values but reversed it logs 11

score([{ suit: 'HEARTS', value: 11 }, { suit: 'SPADES', value: 1 }]) // Logs 11 but should log 21

I dont get how i should make it work, maybe someone can guide me in the right direction. Code below:

let score = function (cardObject) {
  let getScore = 0;

  for (let i = 0; i < cardObject.length; i  ) {
    let cardValue = cardObject[i].value;
    if (cardValue >= 10 && cardValue <= 13) {
      getScore  = 10;
    } else if (cardValue >= 2 && cardValue <= 9) {
      getScore  = cardValue;
    } else if (cardValue === 1) { //Ace
      getScore  = 11;
      if (getScore   cardValue > 21) {
        getScore -= 10;
      }
    }
  }
  return getScore;
}
    score([{ suit: 'HEARTS', value: 11 }, { suit: 'SPADES', value: 1 }]) // Logs 11 but should log 21
    
    score([{ suit: 'HEARTS', value: 1 }, { suit: 'SPADES', value: 11 }]) //Logs 21 as it should
    
    score([{ suit: 'HEARTS', value: 1 }, { suit: 'SPADES', value: 1 }, { suit: 'SPADES', value: 1 }, { suit: 'SPADES', value: 10 }]) //Logs 23 but should log 13
    
    score([{ suit: 'HEARTS', value: 10 }, { suit: 'SPADES', value: 1 }, { suit: 'SPADES', value: 1 }, { suit: 'SPADES', value: 1 }]) //Logs 13 as it should

CodePudding user response:

The problem is that you still add the Ace's value to the total to compare it with 21, at a moment you had already increased the score to account for that Ace. A second problem will occur when the Ace comes early, is counted as 11, and then subsequent cards still bust the 21 ceiling.

Here is a possible solution:

let score = function (cardObject) {
  let getScore = 0;
  let hasAce = false;

  for (const {value} of cardObject) {
    getScore  = Math.min(10, value); // Count Ace as 1
    hasAce ||= value == 1; // Remember if there was an Ace
  }
  // Only at the end consider whether an Ace could count as 11
  return hasAce && getScore <= 11 ? getScore   10 : getScore;
}

console.log(score([{ suit: 'HEARTS', value: 11 }, { suit: 'SPADES', value: 1 }])) // should log 21

console.log(score([{ suit: 'HEARTS', value: 1 }, { suit: 'SPADES', value: 11 }])) // should logs 21

console.log(score([{ suit: 'HEARTS', value: 1 }, { suit: 'SPADES', value: 1 }, { suit: 'SPADES', value: 1 }, { suit: 'SPADES', value: 10 }])) // should log 13

console.log(score([{ suit: 'HEARTS', value: 10 }, { suit: 'SPADES', value: 1 }, { suit: 'SPADES', value: 1 }, { suit: 'SPADES', value: 1 }])) // should logs 13

Some explanation about the code:

  • The for..of loop syntax is more suitable here, as you don't need the index in the array, only the object.

  • {value} immediately takes the value property of the object that is visited in the array. This is called destructuring. It is suitable here because we don't need anything else from the object -- only the value.

  • Math.min(10, value) is a handy shortcut to convert the values 11,12 and 13 to 10. It doesn't change the value of 1, but that is intended.

  • The ||= assignment is short for hasAce = hasAce || value == 1 and so it makes sure that if ever an ace has been found this boolean can never return to false, but remains true.

  • At the end of the loop it is checked whether there was an ace, and whether the total score would allow for one ace to count as 11, and if so 10 more than the total is returned, otherwise that total is returned as-is. The conditional operator is used for this (? :).

CodePudding user response:

A bit late for the party as trincot already explained why your code doesn't work like you expected and provided you a solution. My solution is a bit more lengthy but I'm a sucker for array methods, so in case anyone is interested here it is:

const score = (cards) => {
  // add up all the cards
  const total = cards.reduce((acc, { value }) => {
    if (value > 9) {
      return acc   10;
    }

    return acc   value;
  }, 0);

  // check if there is ace in the cards
  const hasAce = cards.some(({ value }) => value === 1);

  // add 10 if cards contain and ace AND your result won't exceed 21
  return hasAce && total <= 11 ? total   10 : total;
};
  • Related