aboutsummaryrefslogtreecommitdiff
path: root/poker
diff options
context:
space:
mode:
authorPaul Harrison <paul@harrison.sh>2022-11-20 15:13:16 +0000
committerPaul Harrison <paul@harrison.sh>2022-12-15 16:02:14 +0000
commit9baafc80ed889c232587cf5d4cfaa2db44d1825a (patch)
tree13371c1220a8eabbc0932d30cc9475b98b984c3b /poker
parentb4ba284dcc20563b9b7dde770b7c9f67c6b25e76 (diff)
feat: Hand ranking API
Hand ranking API with a health check root endpoint and rank endpoint.
Diffstat (limited to 'poker')
-rw-r--r--poker/api.py56
-rw-r--r--poker/constants.py7
-rw-r--r--poker/rank/hands.py4
3 files changed, 63 insertions, 4 deletions
diff --git a/poker/api.py b/poker/api.py
new file mode 100644
index 0000000..9faa89b
--- /dev/null
+++ b/poker/api.py
@@ -0,0 +1,56 @@
+from fastapi import Body, FastAPI
+from loguru import logger
+
+from poker.constants import Suit, Value
+from poker.models import Card, Hand
+from poker.rank import rank_hand
+
+app = FastAPI()
+
+_CARD_PATTERN = r"\s".join(5 * ["(2|3|4|5|6|7|8|9|10|J|K|Q|A)[CDHS]"])
+_SUIT_MAP = {
+ "C": Suit.CLUBS,
+ "D": Suit.DIAMONDS,
+ "H": Suit.HEARTS,
+ "S": Suit.SPADES,
+}
+_VALUE_MAP = {
+ "2": Value.TWO,
+ "3": Value.THREE,
+ "4": Value.FOUR,
+ "5": Value.FIVE,
+ "6": Value.SIX,
+ "7": Value.SEVEN,
+ "8": Value.EIGHT,
+ "9": Value.NINE,
+ "10": Value.TEN,
+ "J": Value.JACK,
+ "Q": Value.QUEEN,
+ "K": Value.KING,
+ "A": Value.ACE,
+}
+
+
+@app.get("/")
+async def health_check() -> str:
+ """Health check endpoint."""
+ return "OK"
+
+
+@app.post("/rank")
+def rank(body: str = Body(regex=_CARD_PATTERN, example="2H 3D 5S 10C KD")) -> str:
+ """Rank hand.
+
+ TODO: Improve error response.
+ """
+ logger.info(f"Input hand: {body}")
+ cards = [
+ Card(suit=_SUIT_MAP[card[-1]], value=_VALUE_MAP[card[:-1]])
+ for card in body.split()
+ ]
+
+ ranked_hand = rank_hand(Hand(cards=cards))
+
+ logger.info(f"Hand rank: {ranked_hand.rank}")
+
+ return ranked_hand.description
diff --git a/poker/constants.py b/poker/constants.py
index e0a7348..6402ef7 100644
--- a/poker/constants.py
+++ b/poker/constants.py
@@ -17,6 +17,11 @@ class Rank(IntEnum):
PAIR = 9
HIGH_CARD = 10
+ def __str__(self) -> str:
+ """Return string representation."""
+ out: str = self.name.lower().replace("_", " ").title()
+ return out
+
class Suit(AutoName):
"""Card suit enum."""
@@ -46,7 +51,7 @@ class Value(IntEnum):
def __str__(self) -> str:
"""Return string representation."""
- if self.value in [1, 11, 12, 13]:
+ if self.value in [1, 11, 12, 13, 14]:
out: str = self.name.lower()
else:
out = str(self.value)
diff --git a/poker/rank/hands.py b/poker/rank/hands.py
index 6a81af5..a622f87 100644
--- a/poker/rank/hands.py
+++ b/poker/rank/hands.py
@@ -162,7 +162,7 @@ def rank_hand(hand: Hand) -> RankedHand:
for rank, func in _FUNCTIONS.items():
result = func(hand)
if result:
- out = RankedHand(
+ return RankedHand(
cards=hand.cards,
rank=rank,
description=DESCRIPTIONS[rank].format(**result),
@@ -170,5 +170,3 @@ def rank_hand(hand: Hand) -> RankedHand:
if out is None:
raise ValueError("No rank found.")
-
- return out