Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions bin/auto-sync.txt
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ pascals-triangle
perfect-numbers
phone-number
pig-latin
poker
protein-translation
proverb
queen-attack
Expand Down
26 changes: 13 additions & 13 deletions config.json
Original file line number Diff line number Diff line change
Expand Up @@ -1209,19 +1209,6 @@
"transforming"
]
},
{
"slug": "poker",
"name": "Poker",
"uuid": "e8669c8e-bfdd-4207-baf6-23c2e4b12d13",
"practices": [],
"prerequisites": [],
"difficulty": 5,
"topics": [
"games",
"parsing",
"sorting"
]
},
{
"slug": "robot-simulator",
"name": "Robot Simulator",
Expand Down Expand Up @@ -1347,6 +1334,19 @@
"transforming"
]
},
{
"slug": "poker",
"name": "Poker",
"uuid": "e8669c8e-bfdd-4207-baf6-23c2e4b12d13",
"practices": [],
"prerequisites": [],
"difficulty": 7,
"topics": [
"games",
"parsing",
"sorting"
]
},
{
"slug": "zebra-puzzle",
"name": "Zebra Puzzle",
Expand Down
4 changes: 3 additions & 1 deletion exercises/practice/poker/.docs/instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,6 @@

Pick the best hand(s) from a list of poker hands.

See [wikipedia](https://en.wikipedia.org/wiki/List_of_poker_hands) for an overview of poker hands.
See [Wikipedia][poker-hands] for an overview of poker hands.

[poker-hands]: https://en.wikipedia.org/wiki/List_of_poker_hands
7 changes: 6 additions & 1 deletion exercises/practice/poker/.meta/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
"authors": [
"MichaelBunker"
],
"contributors": [
"resu-xuniL"
],
"files": {
"solution": [
"Poker.php"
Expand All @@ -13,5 +16,7 @@
".meta/example.php"
]
},
"blurb": "Pick the best hand(s) from a list of poker hands."
"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"
}
64 changes: 39 additions & 25 deletions exercises/practice/poker/.meta/example.php
Original file line number Diff line number Diff line change
@@ -1,32 +1,12 @@
<?php

/*
* By adding type hints and enabling strict type checking, code can become
* easier to read, self-documenting and reduce the number of potential bugs.
* By default, type declarations are non-strict, which means they will attempt
* to change the original type to match the type specified by the
* type-declaration.
*
* In other words, if you pass a string to a function requiring a float,
* it will attempt to convert the string value to a float.
*
* To enable strict mode, a single declare directive must be placed at the top
* of the file.
* This means that the strictness of typing is configured on a per-file basis.
* This directive not only affects the type declarations of parameters, but also
* a function's return type.
*
* For more info review the Concept on strict type checking in the PHP track
* <link>.
*
* To disable strict typing, comment out the directive below.
*/

declare(strict_types=1);

class Poker
{
public array $bestHands = [];
Comment thread
mk-mxp marked this conversation as resolved.
private int $tie;

// The '..' prefix for card ranks allows for matching index -> value increasing readability.
public const CARD_RANKS = '..23456789TJQKA';
public const CARD_SUITS = 'HSDC';
Expand All @@ -36,8 +16,41 @@ public function __construct(array $hands)
$this->bestHands = $this->calculateBestHands($hands);
}

private function sortRanks(string $hand): array
{
$cards = explode(",", $hand);

usort($cards, function ($a, $b) {
return $b[0] <=> $a[0];
});

return array_map(fn($card) => $card[0], $cards);
}

private function seekTies(array $hands): int
{
$prevRanks = null;

foreach ($hands as $hand) {
$ranks = $this->sortRanks($hand);

if ($prevRanks !== null) {
for ($i = 0; $i < count($ranks); $i++) {
if ($ranks[$i] !== $prevRanks[$i]) {
return $i;
}
}
}

$prevRanks = $ranks;
}

return 0;
}

private function calculateBestHands(array $hands): array
{
$this->tie = $this->seekTies($hands);
$bestHands = [];
$parsedHands = [];

Expand Down Expand Up @@ -134,6 +147,7 @@ private function scoreHand(array $cards): Score
//Normalize aces for low straights.
if ($this->isEqualHandRanks([14, 2, 3, 4, 5], $ranks)) {
$ranks = [5, 4, 3, 2, 1];
$cardsByRank = $ranks;
}

$isFlush = count(array_unique($suits)) === 1;
Expand All @@ -152,7 +166,7 @@ private function scoreHand(array $cards): Score
}

if ($isFlush) {
return new Score(500 + current($cardsByRank), 0);
return new Score(500 + current($cardsByRank), $cardsByRank[$this->tie]);
}

if ($isStraight) {
Expand All @@ -168,10 +182,10 @@ private function scoreHand(array $cards): Score
}

if ($this->isEqualHandRanks($ranksByFreq, [2,1,1,1])) {
return new Score(100 + $cardsByRank[0], 0);
return new Score(100 + $cardsByRank[0], $cardsByRank[2]);
}

return new Score(max($ranks), $cardsByRank[4]);
return new Score(max($ranks), $cardsByRank[$this->tie]);
}

private function isEqualHandRanks(array $handOne, array $handTwo): bool
Expand Down
131 changes: 131 additions & 0 deletions exercises/practice/poker/.meta/tests.toml
Original file line number Diff line number Diff line change
@@ -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"
9 changes: 9 additions & 0 deletions exercises/practice/poker/Poker.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,15 @@

class Poker
{
/**
* In PHP 8.4 and newer, you can use to enhance data encapsulation:
* - Asymmetric Property Visibility
* @see https://www.php.net/manual/en/language.oop5.visibility.php#language.oop5.visibility-members-aviz
* Or:
* - Property hooks
* @see https://www.php.net/manual/en/language.oop5.property-hooks.php
*/
Comment thread
resu-xuniL marked this conversation as resolved.

public array $bestHands = [];

public function __construct(array $hands)
Expand Down
Loading
Loading