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 (10)

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
 
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" ] ] ] 
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)))