DEV Community

dev.to staff
dev.to staff

Posted on

Daily Challenge #198 - 21 Blackjack

Implement a function that determines the score of a hand in the card game 21 Blackjack.

The function will receive an array filled with strings that represent each card in the hand. Your function should return the score of the hand as an integer.

Number cards count as their face value (2 through 10). Jack, Queen and King count as 10. An Ace can be counted as either 1 or 11.

Return the highest score of the cards that is less than or equal to 21. If there is no score less than or equal to 21 return the smallest score more than 21.

Examples

["A"] ==> 11
["5", "4", "3", "2", "A", "K"] ==> 25

Tests

["A", "J"]

["A", "10", "A"]

["5", "3", "7"]


This challenge comes from jodymgustafson on CodeWars. Thank you to CodeWars, who has licensed redistribution of this challenge under the 2-Clause BSD License!

Want to propose a challenge idea for a future post? Email yo+challenge@dev.to with your suggestions!

Top comments (11)

Collapse
 
centanomics profile image
Cent

Javascript

This solution doesn't consider the fact that an ace could be both a 1 and an 11 (2+ aces in a hand). But this solution does solve all of the tests


const blackJack = (cards) => {
  let total = [0, 0]
  cards.forEach((card) => {
    switch(card) {
      case "2":
      case "3":
      case "4":
      case "5":
      case "6":
      case "7":
      case "8":
      case "9":
      case "10":
        total[0] += parseInt(card);
        total[1] += parseInt(card);
        break;
      case "J":
      case "Q":
      case "K":
        total[0] += 10;
        total[1] += 10;
        break;
      case "A":
        total[0] += 1;
        total[1] += 11;
        break;
    }
  })

  return Math.max(...total) <= 21 ? Math.max(...total) : Math.min(...total)
}

Enter fullscreen mode Exit fullscreen mode

Codepen

Collapse
 
kerldev profile image
Kyle Jones

In Python:

import sys

FACE_CARDS = ['J', 'Q', 'K']


def score_hand(hand):
    '''
    Calculate the total score of the hand.
    '''
    hand_score = 0

    for card in hand:
        if card in FACE_CARDS:
            hand_score += 10
            continue

        if card == 'A':
            hand_score += 1
            if hand_score < 12:
                hand_score += 10
            continue
        try:
            hand_score += int(card)
            continue
        except ValueError:
            print('Invalid card in hand: {}'.format(card))
        except TypeError:
            print('Card is an invalid type: {}'.format(type(card)))
    return hand_score


print(str(score_hand(['A'])))
print(str(score_hand(['5', '4', '3', '2', 'A', 'K'])))
print(str(score_hand(['5', '3', '7'])))
print(str(score_hand(['A', 'J'])))
print(str(score_hand(['A', '10', 'A'])))
Enter fullscreen mode Exit fullscreen mode
Collapse
 
not_jffrydsr profile image
@nobody

Clojure ✌🏿

(ns dailyChallenge.one-ninety-eight)

(defn scoreHand [hand]
  (let [WIN 21
        CARDS {:2 2, :3 3, :4 4, :5 5, 
               :6 6 :7 7, :8 8, :9 9, 
               [:J :Q :K] 10, :A [1 11]}] ;;this is why I ♥ Clojure
    (for [card hand]
         (apply + (CARDS card))...To be continued (need to save somewhere)))
Collapse
 
savagepixie profile image
SavagePixie • Edited

Elixir

Some recursion

defmodule Cards do
  def blackjack(list), do: _blackjack(0, 0, list)

  defp _blackjack(n, a, []), do: n + _get_as(n, a)
  defp _blackjack(n, a, [ head | tail ]) do
    cond do
      head == "A" -> _blackjack(n, a + 1, tail)
      Enum.member?([ "J", "Q", "K" ], head) -> _blackjack(n + 10, a, tail)
      true -> _blackjack(n + String.to_integer(head), a, tail)
    end
  end

  defp _get_as(_n, 0), do: 0
  defp _get_as(n, a) when n + a - 1 < 11, do: a + 10
  defp _get_as(_n, a), do: a
end
Collapse
 
scrabill profile image
Shannon Crabill

In Ruby. Iterate over each card and total as you go. If it's a face card, count is as 10. If it's a number card, count is as what it is. If it's an ace and the current score is below 21 and counting an ace as a 11 wouldn't push it over 21, count is as 11. Otherwise, count is a 1.

def total(array)
  count = 0
  face_cards = ["J","Q","K"]

  array.each do |card|
    if face_cards.include?(card)
      count = count + 10
    elsif card == "A"
      count = count + 1
    else
      count = count + card.to_i
    end
  end

  if count < 21 && array.include?("A")
    if count + 10 <= 21
      count = count + 10
    end
  end

  count

end

The examples

total(["A"]) # ==> 11
total(["5", "4", "3", "2", "A", "K"]) # ==> 25
total(["A", "J"]) # ==> 21
total(["A", "10", "A"]) # ==> 12
total(["5", "3", "7"]) # ==> 21

A possible flaw is that you should be seeing cards one at a time, instead of as a whole then deciding on how to handle aces.

A .map or .inject method could clean this up in Ruby.

Collapse
 
maskedman99 profile image
Rohit Prasad • Edited

Isn't (["5", "3", "7"]) # ==> 21 wrong.

Collapse
 
maskedman99 profile image
Rohit Prasad

Python

var = input("Enter the string: ")
var = var.split(' ')

sum = 0;
a = 0
for i in var:
        if i == 'K' or i == 'J' or i == 'Q':
                sum += 10
        elif i == 'A':
                a += 1
        else:
                sum += int(i)

if sum + a*11 <= 21:
        sum += a*11
elif sum + a <= 21:
        sum += a
else:
        for i in range(a):
                if sum <= 21:
                        sum += 11
                else:
                        sum += a-i  
                        break

print(sum)
Collapse
 
vidit1999 profile image
Vidit Sarkar • Edited

C++

int scoreHand(vector<string> cards){
    unordered_map<string,int> scoreCount; // holds the score of each card
    for(int i=2;i<=10;i++){
        scoreCount[to_string(i)] = i;
    }
    scoreCount["A"] = 1; // store the score of A as 1 (minimum)
    scoreCount["J"] = 10;
    scoreCount["K"] = 10;
    scoreCount["Q"] = 10;

    unordered_map<string, int> cardCount; // holds the number of times cards are apperaing
    int score = 0; // minimum score (i.e. score with A as 1)
    for(string s : cards){
        score += scoreCount[s];
        cardCount[s]++;
    }

    // if score is 21 return 21
    if(score == 21)
        return score;

    // if score < 21 try to maximize it
    // but keep it less than or equal to 21
    if(score < 21){
        for(int i=0;i<cardCount["A"];i++){
            if(score > 11){
                return score;
            }
            // add score of A to score
            // score = score - 1 + 11
            score += 10;
        }
    }

    // no need to write the case when score > 21
    // because we are always starting from minimum score possible
    return score;
}

Code can be optimized by caculating scoreCount seperately and then passing
it as an argument in the function.

Collapse
 
vidit1999 profile image
Vidit Sarkar • Edited

Test cases --

cout << scoreHand({"A"}) << "\n";
cout << scoreHand({"5", "4", "3", "2", "A", "K"}) << "\n";
cout << scoreHand({"A", "J"}) << "\n";
cout << scoreHand({"A", "10", "A"}) << "\n";
cout << scoreHand({"5", "3", "7"}) << "\n";
cout << scoreHand({"5", "5", "A"}) << "\n";
cout << scoreHand({"A", "A", "A"}) << "\n";
cout << scoreHand({"A", "A"}) << "\n";
cout << scoreHand({"5", "4", "3", "10", "K"}) << "\n";

Output --

11
25
21
12
15
21
13
12
32
Collapse
 
aminnairi profile image
Amin • Edited

Elm

From what I understood about the game, the cards are revealed at each draw. I may have implemented a wrong version though.

module BlackJack exposing (score)

import List exposing (foldl)
import String exposing (toInt)
import Maybe exposing (withDefault)


cardToScore : String -> Int -> Int
cardToScore card accumulatedScore =
  case card of
    "A" ->
      if accumulatedScore + 11 > 21 then
        accumulatedScore + 1

      else
        accumulatedScore + 11

    otherCard ->
        accumulatedScore + ( otherCard |> toInt |> withDefault 10 )


score : List String -> Int
score cards =
  foldl cardToScore 0 cards

Tests

module BlackJackTest exposing (suite)

import Expect exposing (Expectation, equal)
import Test exposing (Test, describe, test)
import BlackJack exposing (score)


suite : Test
suite =
  describe "BlackJack.elm"
    [ describe "score"
      [ test "It should return 11" <| \_ ->
          equal 11 <| score [ "A" ]
      , test "It should return 25" <| \_ ->
          equal 25 <| score [ "5", "4", "3", "2", "A", "K" ]
      , test "It should return 21" <| \_ ->
          equal 21 <| score [ "A", "J" ]
      , test "It should return 22" <| \_ ->
          equal 22 <| score [ "A", "10", "A" ]
      , test "It should return 15" <| \_ ->
          equal 15 <| score [ "5", "3", "7" ]
      ]
    ]