From 5b5048233bdb62bc24b4835373473e4afb427692 Mon Sep 17 00:00:00 2001 From: Ronaldo Ferreira de Lima Date: Fri, 5 Sep 2025 11:35:42 -0300 Subject: [PATCH] * add practice exercise: poker --- config.json | 8 + .../poker/.docs/instructions.append.md | 7 + .../practice/poker/.docs/instructions.md | 7 + exercises/practice/poker/.meta/config.json | 19 ++ exercises/practice/poker/.meta/example.sql | 291 ++++++++++++++++++ exercises/practice/poker/.meta/tests.toml | 131 ++++++++ exercises/practice/poker/create_fixture.sql | 10 + .../practice/poker/create_test_table.sql | 55 ++++ exercises/practice/poker/data.csv | 37 +++ exercises/practice/poker/poker.sql | 7 + exercises/practice/poker/poker_test.sql | 49 +++ 11 files changed, 621 insertions(+) create mode 100644 exercises/practice/poker/.docs/instructions.append.md create mode 100644 exercises/practice/poker/.docs/instructions.md create mode 100644 exercises/practice/poker/.meta/config.json create mode 100644 exercises/practice/poker/.meta/example.sql create mode 100644 exercises/practice/poker/.meta/tests.toml create mode 100644 exercises/practice/poker/create_fixture.sql create mode 100644 exercises/practice/poker/create_test_table.sql create mode 100644 exercises/practice/poker/data.csv create mode 100644 exercises/practice/poker/poker.sql create mode 100644 exercises/practice/poker/poker_test.sql diff --git a/config.json b/config.json index bac53ab..93d0e8a 100644 --- a/config.json +++ b/config.json @@ -450,6 +450,14 @@ "prerequisites": [], "difficulty": 8 }, + { + "slug": "poker", + "name": "Poker", + "uuid": "b9ec94e1-8c20-4095-b627-889b614e2a99", + "practices": [], + "prerequisites": [], + "difficulty": 8 + }, { "slug": "protein-translation", "name": "Protein Translation", diff --git a/exercises/practice/poker/.docs/instructions.append.md b/exercises/practice/poker/.docs/instructions.append.md new file mode 100644 index 0000000..196dae4 --- /dev/null +++ b/exercises/practice/poker/.docs/instructions.append.md @@ -0,0 +1,7 @@ +# SQLite-specific instructions + +## JSON documentation + +See [JSON Functions And Operators][json-docs] for SQLite JSON functions. + +[json-docs]: https://www.sqlite.org/json1.html diff --git a/exercises/practice/poker/.docs/instructions.md b/exercises/practice/poker/.docs/instructions.md new file mode 100644 index 0000000..107cd49 --- /dev/null +++ b/exercises/practice/poker/.docs/instructions.md @@ -0,0 +1,7 @@ +# Instructions + +Pick the best hand(s) from a list of poker hands. + +See [Wikipedia][poker-hands] for an overview of poker hands. + +[poker-hands]: https://en.wikipedia.org/wiki/List_of_poker_hands diff --git a/exercises/practice/poker/.meta/config.json b/exercises/practice/poker/.meta/config.json new file mode 100644 index 0000000..8423860 --- /dev/null +++ b/exercises/practice/poker/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "jimmytty" + ], + "files": { + "solution": [ + "poker.sql" + ], + "test": [ + "poker_test.sql" + ], + "example": [ + ".meta/example.sql" + ] + }, + "blurb": "Pick the best hand(s) from a list of poker hands.", + "source": "Inspired by the training course from Udacity.", + "source_url": "https://www.udacity.com/course/design-of-computer-programs--cs212" +} diff --git a/exercises/practice/poker/.meta/example.sql b/exercises/practice/poker/.meta/example.sql new file mode 100644 index 0000000..040f8f6 --- /dev/null +++ b/exercises/practice/poker/.meta/example.sql @@ -0,0 +1,291 @@ +DROP TABLE IF EXISTS ranking; +CREATE TEMPORARY TABLE ranking ( + id INTEGER PRIMARY KEY, + name TEXT NOT NULL +); +INSERT INTO ranking (id, name) +VALUES + (10, 'straight flush' ), + (20, 'four of a kind' ), + (30, 'full house' ), + (40, 'flush' ), + (50, 'straight' ), + (60, 'three of a kind'), + (70, 'two pair' ), + (80, 'one pair' ), + (90, 'high card' ) +; + +DROP TABLE IF EXISTS tmp; +CREATE TABLE tmp ( + hand TEXT PRIMARY KEY, + deck TEXT, + name TEXT +); +INSERT INTO tmp (hand) +SELECT DISTINCT(j.value) + FROM poker, JSON_TREE(hands) j + WHERE j.type = 'text' +; + +UPDATE tmp + SET deck = ( + WITH to_cards (rank, suite) AS ( + WITH RECURSIVE to_cards (hand, card) AS ( + VALUES (hand || ' ', NULL) + UNION ALL + SELECT + SUBSTR(hand, INSTR(hand, ' ') + 1), + SUBSTR(hand, 1, INSTR(hand, ' ') - 1) + FROM to_cards + WHERE hand <> '' + LIMIT 10 + ) + SELECT SUBSTR(card, 1, LENGTH(card) - 1) AS rank, + SUBSTR(card, -1) AS suite + FROM to_cards + WHERE card NOTNULL + ) + SELECT JSON_GROUP_ARRAY(JSON(card)) + FROM ( + SELECT JSON_ARRAY(rank, suite) card + FROM ( + SELECT + CASE rank + WHEN 'A' THEN 14 + WHEN 'J' THEN 11 + WHEN 'Q' THEN 12 + WHEN 'K' THEN 13 + ELSE rank + END * 1 AS rank, + suite + FROM to_cards + ) + ORDER BY rank DESC, suite ASC + ) + ) +; + +ALTER TABLE tmp ADD COLUMN is_sequential BOOLEAN; +UPDATE tmp + SET is_sequential = + (SELECT JSON_ARRAY_LENGTH(ranks) = 5 + AND JSON_EXTRACT(ranks, '$[0]') = + JSON_EXTRACT(ranks, '$[4]') + 4 + FROM (SELECT + JSON_GROUP_ARRAY( + DISTINCT(JSON_EXTRACT(j.value, '$[0]'))) AS ranks + FROM JSON_EACH(deck) j)) + OR + (SELECT JSON_ARRAY_LENGTH(ranks) = 5 + AND JSON_EXTRACT(ranks, '$[0]') = + JSON_EXTRACT(ranks, '$[4]') + 4 + FROM ( + SELECT JSON_GROUP_ARRAY(rank) AS ranks + FROM ( + SELECT IIF(rank = 14, 1, rank) rank + FROM ( + SELECT DISTINCT(JSON_EXTRACT(j.value, '$[0]')) AS rank + FROM JSON_EACH(deck) j + ) + ORDER BY rank DESC + ) + ) + ) +; + +ALTER TABLE tmp ADD COLUMN same_suite BOOLEAN; +UPDATE tmp + SET same_suite = ( + SELECT JSON_ARRAY_LENGTH(suites) = 1 + FROM ( + SELECT JSON_GROUP_ARRAY( + DISTINCT(JSON_EXTRACT(j.value, '$[1]')) + ) AS suites + FROM JSON_EACH(deck) j + ) + ) +; + +UPDATE tmp + SET name = 'straight flush' + WHERE is_sequential AND same_suite + AND name ISNULL +; + +UPDATE tmp + SET name = 'four of a kind' + WHERE (SELECT 1 + FROM ( + SELECT JSON_EXTRACT(j.value, '$[0]') rank + FROM JSON_EACH(deck) j + ) + GROUP BY rank + HAVING COUNT(*) = 4 + ) + AND name ISNULL +; + +UPDATE tmp + SET name = 'full house' + WHERE (SELECT GROUP_CONCAT(dup) = '3,2' + FROM ( + SELECT dup + FROM ( + SELECT COUNT(*) dup + FROM ( + SELECT JSON_EXTRACT(j.value, '$[0]') rank + FROM JSON_EACH(deck) j + ) + GROUP BY rank + ) + ORDER BY dup DESC + ) + ) + AND name ISNULL +; + +UPDATE tmp + SET name = 'flush' + WHERE same_suite + AND name ISNULL +; + +UPDATE tmp + SET name = 'straight' + WHERE is_sequential + AND name ISNULL +; + +UPDATE tmp + SET name = 'three of a kind' + WHERE (SELECT 1 + FROM ( + SELECT JSON_EXTRACT(j.value, '$[0]') rank + FROM JSON_EACH(deck) j + ) + GROUP BY rank + HAVING COUNT(*) = 3 + ) + AND name ISNULL +; + +UPDATE tmp + SET name = 'two pair' + WHERE (SELECT GROUP_CONCAT(dup) = '2,2,1' + FROM ( + SELECT dup + FROM ( + SELECT COUNT(*) dup + FROM ( + SELECT JSON_EXTRACT(j.value, '$[0]') rank + FROM JSON_EACH(deck) j + ) + GROUP BY rank + ) + ORDER BY dup DESC + ) + ) + AND name ISNULL +; + +UPDATE tmp + SET name = 'one pair' + WHERE (SELECT 1 + FROM ( + SELECT JSON_EXTRACT(j.value, '$[0]') rank + FROM JSON_EACH(deck) j + ) + GROUP BY rank + HAVING COUNT(*) = 2 + ) + AND name ISNULL +; + +UPDATE tmp + SET name = 'high card' + WHERE name ISNULL +; + +ALTER TABLE tmp ADD COLUMN ranks_id INTEGER; +UPDATE tmp + SET ranks_id = + CASE + WHEN name NOT IN ('four of a kind', 'three of a kind', 'full house') + THEN ( + (SELECT GROUP_CONCAT(rank, '') + FROM ( + SELECT IIF(rank = '14' AND + LIKE('straight%', name) AND + JSON_EXTRACT( + deck, '$[0][0]', '$[1][0]') = JSON_ARRAY(14,5), + 1, + rank + ) rank + FROM ( + SELECT PRINTF('%02d', JSON_EXTRACT(j.value, '$[0]')) rank + FROM JSON_EACH(deck) j + ) + ORDER BY rank DESC + ) + ) + ) + ELSE ( + WITH + by_rank AS ( + SELECT JSON_EXTRACT(j.value, '$[0]') rank, j.* + FROM JSON_EACH(deck) j + ), + dup (rank) AS ( + SELECT rank + FROM by_rank + GROUP BY rank + ORDER BY COUNT(*) DESC + LIMIT 1 + ), + same (rank) AS ( + SELECT PRINTF('%02d', by_rank.rank) + FROM by_rank, dup + WHERE by_rank.rank = dup.rank + ), + kickers (rank) AS ( + SELECT PRINTF('%02d', by_rank.rank) + FROM by_rank, dup + WHERE by_rank.rank != dup.rank + ORDER BY by_rank.rank DESC + ) + SELECT GROUP_CONCAT(rank, '') + FROM ( + SELECT rank FROM same + UNION ALL + SELECT rank FROM kickers + ) + ) + END +; + + + +UPDATE poker + SET result = ( + WITH + analysis AS ( + SELECT j.value hand, tmp.name, tmp.deck, ranking.id, tmp.ranks_id + FROM JSON_TREE(hands) j, tmp, ranking + WHERE j.value = tmp.hand + AND tmp.name = ranking.name + AND j.type = 'text' + ), + winners AS ( + SELECT hand, ranks_id + FROM analysis WHERE id = (SELECT MIN(id) FROM analysis) + ), + tiebreaker AS ( + SELECT winners.hand + FROM winners + WHERE ranks_id = (SELECT MAX(ranks_id) FROM winners) + ) + SELECT JSON_GROUP_ARRAY(hand) + FROM (SELECT hand FROM tiebreaker ORDER BY hand) + ) +; diff --git a/exercises/practice/poker/.meta/tests.toml b/exercises/practice/poker/.meta/tests.toml new file mode 100644 index 0000000..2e654ef --- /dev/null +++ b/exercises/practice/poker/.meta/tests.toml @@ -0,0 +1,131 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[161f485e-39c2-4012-84cf-bec0c755b66c] +description = "single hand always wins" + +[370ac23a-a00f-48a9-9965-6f3fb595cf45] +description = "highest card out of all hands wins" + +[d94ad5a7-17df-484b-9932-c64fc26cff52] +description = "a tie has multiple winners" + +[61ed83a9-cfaa-40a5-942a-51f52f0a8725] +description = "multiple hands with the same high cards, tie compares next highest ranked, down to last card" + +[da01becd-f5b0-4342-b7f3-1318191d0580] +description = "winning high card hand also has the lowest card" + +[f7175a89-34ff-44de-b3d7-f6fd97d1fca4] +description = "one pair beats high card" + +[e114fd41-a301-4111-a9e7-5a7f72a76561] +description = "highest pair wins" + +[b3acd3a7-f9fa-4647-85ab-e0a9e07d1365] +description = "both hands have the same pair, high card wins" + +[935bb4dc-a622-4400-97fa-86e7d06b1f76] +description = "two pairs beats one pair" + +[c8aeafe1-6e3d-4711-a6de-5161deca91fd] +description = "both hands have two pairs, highest ranked pair wins" + +[88abe1ba-7ad7-40f3-847e-0a26f8e46a60] +description = "both hands have two pairs, with the same highest ranked pair, tie goes to low pair" + +[15a7a315-0577-47a3-9981-d6cf8e6f387b] +description = "both hands have two identically ranked pairs, tie goes to remaining card (kicker)" + +[f761e21b-2560-4774-a02a-b3e9366a51ce] +description = "both hands have two pairs that add to the same value, win goes to highest pair" + +[fc6277ac-94ac-4078-8d39-9d441bc7a79e] +description = "two pairs first ranked by largest pair" + +[21e9f1e6-2d72-49a1-a930-228e5e0195dc] +description = "three of a kind beats two pair" + +[c2fffd1f-c287-480f-bf2d-9628e63bbcc3] +description = "both hands have three of a kind, tie goes to highest ranked triplet" + +[eb856cc2-481c-4b0d-9835-4d75d07a5d9d] +description = "with multiple decks, two players can have same three of a kind, ties go to highest remaining cards" +include = false + +[26a4a7d4-34a2-4f18-90b4-4a8dd35d2bb1] +description = "with multiple decks, two players can have same three of a kind, ties go to highest remaining cards" +reimplements = "eb856cc2-481c-4b0d-9835-4d75d07a5d9d" + +[a858c5d9-2f28-48e7-9980-b7fa04060a60] +description = "a straight beats three of a kind" + +[73c9c756-e63e-4b01-a88d-0d4491a7a0e3] +description = "aces can end a straight (10 J Q K A)" + +[76856b0d-35cd-49ce-a492-fe5db53abc02] +description = "aces can start a straight (A 2 3 4 5)" + +[e214b7df-dcba-45d3-a2e5-342d8c46c286] +description = "aces cannot be in the middle of a straight (Q K A 2 3)" + +[6980c612-bbff-4914-b17a-b044e4e69ea1] +description = "both hands with a straight, tie goes to highest ranked card" + +[5135675c-c2fc-4e21-9ba3-af77a32e9ba4] +description = "even though an ace is usually high, a 5-high straight is the lowest-scoring straight" + +[c601b5e6-e1df-4ade-b444-b60ce13b2571] +description = "flush beats a straight" + +[4d90261d-251c-49bd-a468-896bf10133de] +description = "both hands have a flush, tie goes to high card, down to the last one if necessary" +include = false + +[e04137c5-c19a-4dfc-97a1-9dfe9baaa2ff] +description = "both hands have a flush, tie goes to high card, down to the last one if necessary" +reimplements = "4d90261d-251c-49bd-a468-896bf10133de" + +[3a19361d-8974-455c-82e5-f7152f5dba7c] +description = "full house beats a flush" + +[eb73d0e6-b66c-4f0f-b8ba-bf96bc0a67f0] +description = "both hands have a full house, tie goes to highest-ranked triplet" + +[34b51168-1e43-4c0d-9b32-e356159b4d5d] +description = "with multiple decks, both hands have a full house with the same triplet, tie goes to the pair" + +[d61e9e99-883b-4f99-b021-18f0ae50c5f4] +description = "four of a kind beats a full house" + +[2e1c8c63-e0cb-4214-a01b-91954490d2fe] +description = "both hands have four of a kind, tie goes to high quad" + +[892ca75d-5474-495d-9f64-a6ce2dcdb7e1] +description = "with multiple decks, both hands with identical four of a kind, tie determined by kicker" + +[923bd910-dc7b-4f7d-a330-8b42ec10a3ac] +description = "straight flush beats four of a kind" + +[d9629e22-c943-460b-a951-2134d1b43346] +description = "aces can end a straight flush (10 J Q K A)" + +[05d5ede9-64a5-4678-b8ae-cf4c595dc824] +description = "aces can start a straight flush (A 2 3 4 5)" + +[ad655466-6d04-49e8-a50c-0043c3ac18ff] +description = "aces cannot be in the middle of a straight flush (Q K A 2 3)" + +[d0927f70-5aec-43db-aed8-1cbd1b6ee9ad] +description = "both hands have a straight flush, tie goes to highest-ranked card" + +[be620e09-0397-497b-ac37-d1d7a4464cfc] +description = "even though an ace is usually high, a 5-high straight flush is the lowest-scoring straight flush" diff --git a/exercises/practice/poker/create_fixture.sql b/exercises/practice/poker/create_fixture.sql new file mode 100644 index 0000000..066ed59 --- /dev/null +++ b/exercises/practice/poker/create_fixture.sql @@ -0,0 +1,10 @@ +DROP TABLE IF EXISTS poker; +CREATE TABLE poker ( + hands TEXT NOT NULL, -- json array + result TEXT -- json array +); + +.mode csv +.import ./data.csv poker + +UPDATE poker SET result = NULL; diff --git a/exercises/practice/poker/create_test_table.sql b/exercises/practice/poker/create_test_table.sql new file mode 100644 index 0000000..71a058c --- /dev/null +++ b/exercises/practice/poker/create_test_table.sql @@ -0,0 +1,55 @@ +DROP TABLE IF EXISTS tests; +CREATE TABLE IF NOT EXISTS tests ( + -- uuid and description are taken from the test.toml file + uuid TEXT PRIMARY KEY, + description TEXT NOT NULL, + -- The following section is needed by the online test-runner + status TEXT DEFAULT 'fail', + message TEXT, + output TEXT, + test_code TEXT, + task_id INTEGER DEFAULT NULL, + -- Here are columns for the actual tests + hands TEXT NOT NULL, -- json array + expected TEXT NOT NULL -- json array +); + +INSERT INTO tests (uuid, description, hands, expected) +VALUES +('161f485e-39c2-4012-84cf-bec0c755b66c', 'single hand always wins', '["4S 5S 7H 8D JC"]', '["4S 5S 7H 8D JC"]'), +('370ac23a-a00f-48a9-9965-6f3fb595cf45', 'highest card out of all hands wins', '["4D 5S 6S 8D 3C","2S 4C 7S 9H 10H","3S 4S 5D 6H JH"]', '["3S 4S 5D 6H JH"]'), +('d94ad5a7-17df-484b-9932-c64fc26cff52', 'a tie has multiple winners', '["4D 5S 6S 8D 3C","2S 4C 7S 9H 10H","3S 4S 5D 6H JH","3H 4H 5C 6C JD"]', '["3S 4S 5D 6H JH","3H 4H 5C 6C JD"]'), +('61ed83a9-cfaa-40a5-942a-51f52f0a8725', 'multiple hands with the same high cards, tie compares next highest ranked, down to last card', '["3S 5H 6S 8D 7H","2S 5D 6D 8C 7S"]', '["3S 5H 6S 8D 7H"]'), +('da01becd-f5b0-4342-b7f3-1318191d0580', 'winning high card hand also has the lowest card', '["2S 5H 6S 8D 7H","3S 4D 6D 8C 7S"]', '["2S 5H 6S 8D 7H"]'), +('f7175a89-34ff-44de-b3d7-f6fd97d1fca4', 'one pair beats high card', '["4S 5H 6C 8D KH","2S 4H 6S 4D JH"]', '["2S 4H 6S 4D JH"]'), +('e114fd41-a301-4111-a9e7-5a7f72a76561', 'highest pair wins', '["4S 2H 6S 2D JH","2S 4H 6C 4D JD"]', '["2S 4H 6C 4D JD"]'), +('b3acd3a7-f9fa-4647-85ab-e0a9e07d1365', 'both hands have the same pair, high card wins', '["4H 4S AH JC 3D","4C 4D AS 5D 6C"]', '["4H 4S AH JC 3D"]'), +('935bb4dc-a622-4400-97fa-86e7d06b1f76', 'two pairs beats one pair', '["2S 8H 6S 8D JH","4S 5H 4C 8C 5C"]', '["4S 5H 4C 8C 5C"]'), +('c8aeafe1-6e3d-4711-a6de-5161deca91fd', 'both hands have two pairs, highest ranked pair wins', '["2S 8H 2D 8D 3H","4S 5H 4C 8S 5D"]', '["2S 8H 2D 8D 3H"]'), +('88abe1ba-7ad7-40f3-847e-0a26f8e46a60', 'both hands have two pairs, with the same highest ranked pair, tie goes to low pair', '["2S QS 2C QD JH","JD QH JS 8D QC"]', '["JD QH JS 8D QC"]'), +('15a7a315-0577-47a3-9981-d6cf8e6f387b', 'both hands have two identically ranked pairs, tie goes to remaining card (kicker)', '["JD QH JS 8D QC","JS QS JC 2D QD"]', '["JD QH JS 8D QC"]'), +('f761e21b-2560-4774-a02a-b3e9366a51ce', 'both hands have two pairs that add to the same value, win goes to highest pair', '["6S 6H 3S 3H AS","7H 7S 2H 2S AC"]', '["7H 7S 2H 2S AC"]'), +('fc6277ac-94ac-4078-8d39-9d441bc7a79e', 'two pairs first ranked by largest pair', '["5C 2S 5S 4H 4C","6S 2S 6H 7C 2C"]', '["6S 2S 6H 7C 2C"]'), +('21e9f1e6-2d72-49a1-a930-228e5e0195dc', 'three of a kind beats two pair', '["2S 8H 2H 8D JH","4S 5H 4C 8S 4H"]', '["4S 5H 4C 8S 4H"]'), +('c2fffd1f-c287-480f-bf2d-9628e63bbcc3', 'both hands have three of a kind, tie goes to highest ranked triplet', '["2S 2H 2C 8D JH","4S AH AS 8C AD"]', '["4S AH AS 8C AD"]'), +('26a4a7d4-34a2-4f18-90b4-4a8dd35d2bb1', 'with multiple decks, two players can have same three of a kind, ties go to highest remaining cards', '["5S AH AS 7C AD","4S AH AS 8C AD"]', '["4S AH AS 8C AD"]'), +('a858c5d9-2f28-48e7-9980-b7fa04060a60', 'a straight beats three of a kind', '["4S 5H 4C 8D 4H","3S 4D 2S 6D 5C"]', '["3S 4D 2S 6D 5C"]'), +('73c9c756-e63e-4b01-a88d-0d4491a7a0e3', 'aces can end a straight (10 J Q K A)', '["4S 5H 4C 8D 4H","10D JH QS KD AC"]', '["10D JH QS KD AC"]'), +('76856b0d-35cd-49ce-a492-fe5db53abc02', 'aces can start a straight (A 2 3 4 5)', '["4S 5H 4C 8D 4H","4D AH 3S 2D 5C"]', '["4D AH 3S 2D 5C"]'), +('e214b7df-dcba-45d3-a2e5-342d8c46c286', 'aces cannot be in the middle of a straight (Q K A 2 3)', '["2C 3D 7H 5H 2S","QS KH AC 2D 3S"]', '["2C 3D 7H 5H 2S"]'), +('6980c612-bbff-4914-b17a-b044e4e69ea1', 'both hands with a straight, tie goes to highest ranked card', '["4S 6C 7S 8D 5H","5S 7H 8S 9D 6H"]', '["5S 7H 8S 9D 6H"]'), +('5135675c-c2fc-4e21-9ba3-af77a32e9ba4', 'even though an ace is usually high, a 5-high straight is the lowest-scoring straight', '["2H 3C 4D 5D 6H","4S AH 3S 2D 5H"]', '["2H 3C 4D 5D 6H"]'), +('c601b5e6-e1df-4ade-b444-b60ce13b2571', 'flush beats a straight', '["4C 6H 7D 8D 5H","2S 4S 5S 6S 7S"]', '["2S 4S 5S 6S 7S"]'), +('e04137c5-c19a-4dfc-97a1-9dfe9baaa2ff', 'both hands have a flush, tie goes to high card, down to the last one if necessary', '["2H 7H 8H 9H 6H","3S 5S 6S 7S 8S"]', '["2H 7H 8H 9H 6H"]'), +('3a19361d-8974-455c-82e5-f7152f5dba7c', 'full house beats a flush', '["3H 6H 7H 8H 5H","4S 5H 4C 5D 4H"]', '["4S 5H 4C 5D 4H"]'), +('eb73d0e6-b66c-4f0f-b8ba-bf96bc0a67f0', 'both hands have a full house, tie goes to highest-ranked triplet', '["4H 4S 4D 9S 9D","5H 5S 5D 8S 8D"]', '["5H 5S 5D 8S 8D"]'), +('34b51168-1e43-4c0d-9b32-e356159b4d5d', 'with multiple decks, both hands have a full house with the same triplet, tie goes to the pair', '["5H 5S 5D 9S 9D","5H 5S 5D 8S 8D"]', '["5H 5S 5D 9S 9D"]'), +('d61e9e99-883b-4f99-b021-18f0ae50c5f4', 'four of a kind beats a full house', '["4S 5H 4D 5D 4H","3S 3H 2S 3D 3C"]', '["3S 3H 2S 3D 3C"]'), +('2e1c8c63-e0cb-4214-a01b-91954490d2fe', 'both hands have four of a kind, tie goes to high quad', '["2S 2H 2C 8D 2D","4S 5H 5S 5D 5C"]', '["4S 5H 5S 5D 5C"]'), +('892ca75d-5474-495d-9f64-a6ce2dcdb7e1', 'with multiple decks, both hands with identical four of a kind, tie determined by kicker', '["3S 3H 2S 3D 3C","3S 3H 4S 3D 3C"]', '["3S 3H 4S 3D 3C"]'), +('923bd910-dc7b-4f7d-a330-8b42ec10a3ac', 'straight flush beats four of a kind', '["4S 5H 5S 5D 5C","7S 8S 9S 6S 10S"]', '["7S 8S 9S 6S 10S"]'), +('d9629e22-c943-460b-a951-2134d1b43346', 'aces can end a straight flush (10 J Q K A)', '["KC AH AS AD AC","10C JC QC KC AC"]', '["10C JC QC KC AC"]'), +('05d5ede9-64a5-4678-b8ae-cf4c595dc824', 'aces can start a straight flush (A 2 3 4 5)', '["KS AH AS AD AC","4H AH 3H 2H 5H"]', '["4H AH 3H 2H 5H"]'), +('ad655466-6d04-49e8-a50c-0043c3ac18ff', 'aces cannot be in the middle of a straight flush (Q K A 2 3)', '["2C AC QC 10C KC","QH KH AH 2H 3H"]', '["2C AC QC 10C KC"]'), +('d0927f70-5aec-43db-aed8-1cbd1b6ee9ad', 'both hands have a straight flush, tie goes to highest-ranked card', '["4H 6H 7H 8H 5H","5S 7S 8S 9S 6S"]', '["5S 7S 8S 9S 6S"]'), +('be620e09-0397-497b-ac37-d1d7a4464cfc', 'even though an ace is usually high, a 5-high straight flush is the lowest-scoring straight flush', '["2H 3H 4H 5H 6H","4D AD 3D 2D 5D"]', '["2H 3H 4H 5H 6H"]'); diff --git a/exercises/practice/poker/data.csv b/exercises/practice/poker/data.csv new file mode 100644 index 0000000..bb7158b --- /dev/null +++ b/exercises/practice/poker/data.csv @@ -0,0 +1,37 @@ +"[""4S 5S 7H 8D JC""]", +"[""4D 5S 6S 8D 3C"",""2S 4C 7S 9H 10H"",""3S 4S 5D 6H JH""]", +"[""4D 5S 6S 8D 3C"",""2S 4C 7S 9H 10H"",""3S 4S 5D 6H JH"",""3H 4H 5C 6C JD""]", +"[""3S 5H 6S 8D 7H"",""2S 5D 6D 8C 7S""]", +"[""2S 5H 6S 8D 7H"",""3S 4D 6D 8C 7S""]", +"[""4S 5H 6C 8D KH"",""2S 4H 6S 4D JH""]", +"[""4S 2H 6S 2D JH"",""2S 4H 6C 4D JD""]", +"[""4H 4S AH JC 3D"",""4C 4D AS 5D 6C""]", +"[""2S 8H 6S 8D JH"",""4S 5H 4C 8C 5C""]", +"[""2S 8H 2D 8D 3H"",""4S 5H 4C 8S 5D""]", +"[""2S QS 2C QD JH"",""JD QH JS 8D QC""]", +"[""JD QH JS 8D QC"",""JS QS JC 2D QD""]", +"[""6S 6H 3S 3H AS"",""7H 7S 2H 2S AC""]", +"[""5C 2S 5S 4H 4C"",""6S 2S 6H 7C 2C""]", +"[""2S 8H 2H 8D JH"",""4S 5H 4C 8S 4H""]", +"[""2S 2H 2C 8D JH"",""4S AH AS 8C AD""]", +"[""5S AH AS 7C AD"",""4S AH AS 8C AD""]", +"[""4S 5H 4C 8D 4H"",""3S 4D 2S 6D 5C""]", +"[""4S 5H 4C 8D 4H"",""10D JH QS KD AC""]", +"[""4S 5H 4C 8D 4H"",""4D AH 3S 2D 5C""]", +"[""2C 3D 7H 5H 2S"",""QS KH AC 2D 3S""]", +"[""4S 6C 7S 8D 5H"",""5S 7H 8S 9D 6H""]", +"[""2H 3C 4D 5D 6H"",""4S AH 3S 2D 5H""]", +"[""4C 6H 7D 8D 5H"",""2S 4S 5S 6S 7S""]", +"[""2H 7H 8H 9H 6H"",""3S 5S 6S 7S 8S""]", +"[""3H 6H 7H 8H 5H"",""4S 5H 4C 5D 4H""]", +"[""4H 4S 4D 9S 9D"",""5H 5S 5D 8S 8D""]", +"[""5H 5S 5D 9S 9D"",""5H 5S 5D 8S 8D""]", +"[""4S 5H 4D 5D 4H"",""3S 3H 2S 3D 3C""]", +"[""2S 2H 2C 8D 2D"",""4S 5H 5S 5D 5C""]", +"[""3S 3H 2S 3D 3C"",""3S 3H 4S 3D 3C""]", +"[""4S 5H 5S 5D 5C"",""7S 8S 9S 6S 10S""]", +"[""KC AH AS AD AC"",""10C JC QC KC AC""]", +"[""KS AH AS AD AC"",""4H AH 3H 2H 5H""]", +"[""2C AC QC 10C KC"",""QH KH AH 2H 3H""]", +"[""4H 6H 7H 8H 5H"",""5S 7S 8S 9S 6S""]", +"[""2H 3H 4H 5H 6H"",""4D AD 3D 2D 5D""]", diff --git a/exercises/practice/poker/poker.sql b/exercises/practice/poker/poker.sql new file mode 100644 index 0000000..d0c01d4 --- /dev/null +++ b/exercises/practice/poker/poker.sql @@ -0,0 +1,7 @@ +-- Schema: +-- CREATE TABLE poker ( +-- hands TEXT NOT NULL, -- json array +-- result TEXT -- json array +-- ); +-- +-- Task: update the poder table and set the result column based on the hands. diff --git a/exercises/practice/poker/poker_test.sql b/exercises/practice/poker/poker_test.sql new file mode 100644 index 0000000..49ef17b --- /dev/null +++ b/exercises/practice/poker/poker_test.sql @@ -0,0 +1,49 @@ +-- Create database: +.read ./create_fixture.sql + +-- Read user student solution and save any output as markdown in user_output.md: +.mode markdown +.output user_output.md +.read ./poker.sql +.output + +-- Create a clean testing environment: +.read ./create_test_table.sql + +-- Comparison of user input and the tests updates the status for each test: +UPDATE tests + SET status = 'pass' + FROM (SELECT hands, result FROM poker) AS actual + WHERE JSON(actual.hands) = JSON(tests.hands) + AND (SELECT JSON_GROUP_ARRAY(hand) + FROM (SELECT j.value hand + FROM JSON_EACH(actual.result) j + ORDER BY hand + ) + ) = + (SELECT JSON_GROUP_ARRAY(hand) + FROM (SELECT j.value hand + FROM JSON_EACH(tests.expected) j + ORDER BY hand + ) + ) +; + +-- Update message for failed tests to give helpful information: +UPDATE tests + SET message = ( + 'Result for "' || tests.hands || '"' || ' is <' + || COALESCE(actual.result, 'NULL') || '> but should be <' + || tests.expected || '>' + ) + FROM (SELECT hands, result FROM poker) AS actual + WHERE actual.hands = tests.hands AND tests.status = 'fail'; + +-- Save results to ./output.json (needed by the online test-runner) +.mode json +.once './output.json' +SELECT description, status, message, OUTPUT, test_code, task_id FROM tests; + +-- Display test results in readable form for the student: +.mode table +SELECT description, status, message FROM tests;