diff --git a/config.json b/config.json index 01ec79ac..50b981aa 100644 --- a/config.json +++ b/config.json @@ -65,6 +65,18 @@ "booleans" ], "status": "wip" + }, + { + "slug": "blackjack", + "name": "Blackjack", + "uuid": "f76b5124-6627-47a2-b39b-acec27c0a67f", + "concepts": [ + "switch" + ], + "prerequisites": [ + "conditionals" + ], + "status": "wip" } ], "practice": [ diff --git a/exercises/concept/blackjack/.docs/hints.md b/exercises/concept/blackjack/.docs/hints.md new file mode 100644 index 00000000..b5296c36 --- /dev/null +++ b/exercises/concept/blackjack/.docs/hints.md @@ -0,0 +1 @@ +# Hints diff --git a/exercises/concept/blackjack/.docs/instructions.md b/exercises/concept/blackjack/.docs/instructions.md new file mode 100644 index 00000000..1fa89d2e --- /dev/null +++ b/exercises/concept/blackjack/.docs/instructions.md @@ -0,0 +1,57 @@ +# Instructions + +In this exercise we will simulate the first turn of a [Blackjack](https:#en.wikipedia.org/wiki/Blackjack) game. + +You will receive two cards and will be able to see the face up card of the dealer. All cards are represented using a string such as "ace", "king", "three", "two", etc. The values of each card are: + +| card | value | card | value | +| :---: | :---: | :-----: | :---: | +| ace | 11 | eight | 8 | +| two | 2 | nine | 9 | +| three | 3 | ten | 10 | +| four | 4 | jack | 10 | +| five | 5 | queen | 10 | +| six | 6 | king | 10 | +| seven | 7 | *other* | 0 | + +**Note**: Commonly, aces can take the value of 1 or 11 but for simplicity we will assume that they can only take the value of 11. + +Depending on your two cards and the card of the dealer, there is a strategy for the first turn of the game, in which you have the following options: + +- Stand (S) +- Hit (H) +- Split (P) +- Automatically win (W) + +Although not optimal yet, you will follow the strategy your friend Alex has been developing, which is as follows: + +- If you have a pair of aces you must always split them. +- If you have a Blackjack (two cards that sum up to a value of 21), and the dealer does not have an ace, a figure or a ten then you automatically win. If the dealer does have any of those cards then you'll have to stand and wait for the reveal of the other card. +- If your cards sum up to a value within the range [17, 20] you should always stand. +- If your cards sum up to a value within the range [12, 16] you should always stand unless the dealer has a 7 or higher, in which case you should always hit. +- If your cards sum up to 11 or lower you should always hit. + +## 1. Calculate the value of any given card. + +Implement a function `parse_card` to calculate the numerical value of a card: + +```R +parse_card("ace") +# => 11 +``` + +## 2. Implement the decision logic for the first turn. + +Write a function `first_turn` that implements the decision logic as described above: + +```R +first_turn(card1, card2, dealer_card) +``` + +Here are some examples for the expected outcomes: + +```R +first_turn("ace", "ace", "jack") == "P" +first_turn("ace", "king", "ace") == "S" +first_turn("five", "queen", "ace") == "H" +``` \ No newline at end of file diff --git a/exercises/concept/blackjack/.docs/introduction.md b/exercises/concept/blackjack/.docs/introduction.md new file mode 100644 index 00000000..76e30975 --- /dev/null +++ b/exercises/concept/blackjack/.docs/introduction.md @@ -0,0 +1,24 @@ +# Introduction + +The `switch()` function can be a concise replacement for a long series of `if` ... `else if` tests. +The variable being switched on is most commonly a string, and if so the quotes can be omitted from the selector. + +```R +star <- function(type) { + switch(type, + M = , # will "fall through" if no value given + K = "red dwarf", + G = "Earth-like", + "bigger star" # only correct for O,B,A,F + ) +} + +> star("M") +[1] "red dwarf" +``` + +Note that options will only fall through if the value is left blank, as with `M` in the example above. +There is no need to include `break` statements as with some other languages. + +With character types, the final value can be a default, as here, or a `stop()` to throw an error if the conditions are intended to be exhaustive. +Switching on an integer is slightly different: for these the default is always `NULL`. diff --git a/exercises/concept/blackjack/.meta/config.json b/exercises/concept/blackjack/.meta/config.json new file mode 100644 index 00000000..37fb790c --- /dev/null +++ b/exercises/concept/blackjack/.meta/config.json @@ -0,0 +1,11 @@ +{ + "authors": ["colinleach"], + "contributors": [], + "files": { + "solution": ["blackjack.R"], + "test": ["test_blackjack.R"], + "exemplar": [".meta/exemplar.R"] + }, + "forked_from": ["go/blackjack"], + "blurb": "Learn about switch and conditionals by playing blackjack" +} diff --git a/exercises/concept/blackjack/.meta/design.md b/exercises/concept/blackjack/.meta/design.md new file mode 100644 index 00000000..2c81303e --- /dev/null +++ b/exercises/concept/blackjack/.meta/design.md @@ -0,0 +1,26 @@ +# Design + +## Goal + +The goal of this exercise is to teach the student the use of `switch()` in R, as well as practicing conditional branching learned previously. + +## Learning objectives + +- Know the syntax of a `switch()`. +- Know that this is most often used with string values, where the quotes can be omitted. +- Know that a default is possible when switching on strings, but this is always `NULL` when switching on integers. + +## Out of scope + +Nothing relevant to R was deliberately excluded, as this topic is relatively self-contained. + +## Concepts + +The Concepts this exercise unlocks are: + +- `loops` + +## Prerequisites + +- `conditionals` + diff --git a/exercises/concept/blackjack/.meta/exemplar.R b/exercises/concept/blackjack/.meta/exemplar.R new file mode 100644 index 00000000..efa8ff7e --- /dev/null +++ b/exercises/concept/blackjack/.meta/exemplar.R @@ -0,0 +1,33 @@ +parse_card <- function(card) { + switch(card, + ace = 11, + two = 2, + three = 3, + four = 4, + five = 5, + six = 6, + seven = 7, + eight = 8, + nine = 9, + ten = , + jack = , + queen = , + king = 10, + 0 + ) +} + +first_turn <- function(card1, card2, dealer_card) { + hand_score <- parse_card(card1) + parse_card(card2) + dealer_score <- parse_card((dealer_card)) + if (hand_score == 22) { + return("P") + } + if (hand_score == 21) { + return(ifelse(dealer_score < 10, "W", "S")) + } + if (hand_score >= 17 || (hand_score >= 12 && dealer_score < 7)) { + return("S") + } + "H" +} diff --git a/exercises/concept/blackjack/blackjack.R b/exercises/concept/blackjack/blackjack.R new file mode 100644 index 00000000..b1c0078f --- /dev/null +++ b/exercises/concept/blackjack/blackjack.R @@ -0,0 +1,5 @@ +parse_card <- function(card) { +} + +first_turn <- function(card1, card2, dealer_card) { +} diff --git a/exercises/concept/blackjack/test_blackjack.R b/exercises/concept/blackjack/test_blackjack.R new file mode 100644 index 00000000..b76febb2 --- /dev/null +++ b/exercises/concept/blackjack/test_blackjack.R @@ -0,0 +1,190 @@ +source("./blackjack.R") +library(testthat) + +# 1) parse_card + +test_that("parse ace", { + expect_equal(parse_card("ace"), 11) +}) + +test_that("parse two", { + expect_equal(parse_card("two"), 2) +}) + +test_that("parse three", { + expect_equal(parse_card("three"), 3) +}) + +test_that("parse four", { + expect_equal(parse_card("four"), 4) +}) + +test_that("parse five", { + expect_equal(parse_card("five"), 5) +}) + +test_that("parse six", { + expect_equal(parse_card("six"), 6) +}) + +test_that("parse seven", { + expect_equal(parse_card("seven"), 7) +}) + +test_that("parse eight", { + expect_equal(parse_card("eight"), 8) +}) + +test_that("parse nine", { + expect_equal(parse_card("nine"), 9) +}) + +test_that("parse ten", { + expect_equal(parse_card("ten"), 10) +}) + +test_that("parse jack", { + expect_equal(parse_card("jack"), 10) +}) + +test_that("parse queen", { + expect_equal(parse_card("queen"), 10) +}) + +test_that("parse king", { + expect_equal(parse_card("king"), 10) +}) + +test_that("parse other", { + expect_equal(parse_card("joker"), 0) +}) + +# first_turn + +test_that("pair of aces", { + expect_equal(first_turn("ace", "ace", "ace"), "P") +}) + +test_that("pair of jacks", { + expect_equal(first_turn("jack", "jack", "ace"), "S") +}) + +test_that("pair of kings", { + expect_equal(first_turn("king", "king", "ace"), "S") +}) + +test_that("pair of twos", { + expect_equal(first_turn("two", "two", "ace"), "H") +}) + +test_that("pair of fives", { + expect_equal(first_turn("five", "five", "ace"), "H") +}) + +test_that("blackjack with ace for dealer", { + expect_equal(first_turn("ace", "jack", "ace"), "S") +}) + +test_that("blackjack with queen for dealer", { + expect_equal(first_turn("king", "ace", "queen"), "S") +}) + +test_that("blackjack with five for dealer", { + expect_equal(first_turn("ace", "ten", "five"), "W") +}) + +test_that("blackjack with nine for dealer", { + expect_equal(first_turn("ace", "king", "nine"), "W") +}) + +test_that("score of 20", { + expect_equal(first_turn("ten", "king", "ace"), "S") +}) + +test_that("score of 19", { + expect_equal(first_turn("ten", "nine", "ace"), "S") +}) + +test_that("score of 18", { + expect_equal(first_turn("ten", "eight", "ace"), "S") +}) + +test_that("score of 17", { + expect_equal(first_turn("seven", "king", "ace"), "S") +}) + +test_that("score of 16 with six for dealer", { + expect_equal(first_turn("ten", "six", "six"), "S") +}) + +test_that("score of 16 with seven for dealer", { + expect_equal(first_turn("ten", "six", "seven"), "H") +}) + +test_that("score of 16 with ace for dealer", { + expect_equal(first_turn("ten", "six", "ace"), "H") +}) + +test_that("score of 15 with six for dealer", { + expect_equal(first_turn("ten", "five", "six"), "S") +}) + +test_that("score of 15 with seven for dealer", { + expect_equal(first_turn("ten", "five", "seven"), "H") +}) + +test_that("score of 15 with king for dealer", { + expect_equal(first_turn("ten", "five", "king"), "H") +}) + +test_that("score of 14 with six for dealer", { + expect_equal(first_turn("ten", "four", "six"), "S") +}) + +test_that("score of 14 with seven for dealer", { + expect_equal(first_turn("ten", "four", "seven"), "H") +}) + +test_that("score of 14 with queen for dealer", { + expect_equal(first_turn("ten", "four", "queen"), "H") +}) + +test_that("score of 13 with six for dealer", { + expect_equal(first_turn("ten", "three", "six"), "S") +}) + +test_that("score of 13 with seven for dealer", { + expect_equal(first_turn("ten", "three", "seven"), "H") +}) + +test_that("score of 13 with queen for dealer", { + expect_equal(first_turn("ten", "three", "queen"), "H") +}) + +test_that("score of 12 with six for dealer", { + expect_equal(first_turn("ten", "two", "six"), "S") +}) + +test_that("score of 12 with seven for dealer", { + expect_equal(first_turn("ten", "two", "seven"), "H") +}) + +test_that("score of 12 with queen for dealer", { + expect_equal(first_turn("ten", "two", "queen"), "H") +}) + +test_that("score of 11 with queen for dealer", { + expect_equal(first_turn("nine", "two", "queen"), "H") +}) + +test_that("score of 10 with two for dealer", { + expect_equal(first_turn("eight", "two", "two"), "H") +}) + +test_that("score of 5 with queen for dealer", { + expect_equal(first_turn("three", "two", "queen"), "H") +}) + +test_that("score of 4 with five for dealer", { + expect_equal(first_turn("two", "two", "five"), "H") +})