mirror of
https://github.com/coding-horror/basic-computer-games.git
synced 2026-06-22 14:51:43 -07:00
Introduce HandRank
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
using System.Text;
|
||||
|
||||
using static Poker.Cards.HandRank;
|
||||
namespace Poker.Cards;
|
||||
|
||||
internal class Hand
|
||||
@@ -7,15 +7,11 @@ internal class Hand
|
||||
public static readonly Hand Empty = new Hand();
|
||||
|
||||
private readonly Card[] _cards;
|
||||
private readonly string _name1;
|
||||
private readonly string _name2;
|
||||
|
||||
private Hand()
|
||||
{
|
||||
_cards = Array.Empty<Card>();
|
||||
_name1 = "";
|
||||
_name2 = "";
|
||||
Name = "";
|
||||
Rank = None;
|
||||
}
|
||||
|
||||
public Hand(IEnumerable<Card> cards)
|
||||
@@ -26,16 +22,15 @@ internal class Hand
|
||||
private Hand(IEnumerable<Card> cards, bool isAfterDraw)
|
||||
{
|
||||
_cards = cards.ToArray();
|
||||
(Rank, _name1, _name2, HighCard, KeepMask) = Analyze();
|
||||
Name = GetHandName();
|
||||
(Rank, HighCard, KeepMask) = Analyze();
|
||||
|
||||
IsWeak = Rank < 10
|
||||
|| Rank == 10 && isAfterDraw
|
||||
|| Rank <= 12 && HighCard.Rank <= 6;
|
||||
IsWeak = Rank < PartialStraight
|
||||
|| Rank == PartialStraight && isAfterDraw
|
||||
|| Rank <= TwoPair && HighCard.Rank <= 6;
|
||||
}
|
||||
|
||||
public string Name { get; }
|
||||
public int Rank { get; }
|
||||
public string Name => Rank.ToString(HighCard);
|
||||
public HandRank Rank { get; }
|
||||
public Card HighCard { get; }
|
||||
public int KeepMask { get; set; }
|
||||
public bool IsWeak { get; }
|
||||
@@ -48,7 +43,7 @@ internal class Hand
|
||||
return new Hand(_cards, isAfterDraw: true);
|
||||
}
|
||||
|
||||
private (int, string, string, Card, int) Analyze()
|
||||
private (HandRank, Card, int) Analyze()
|
||||
{
|
||||
var suitMatchCount = 0;
|
||||
for (var i = 0; i < _cards.Length; i++)
|
||||
@@ -60,31 +55,31 @@ internal class Hand
|
||||
}
|
||||
if (suitMatchCount == 4)
|
||||
{
|
||||
return (15, "A Flus", "h in", _cards[0], 0b11111);
|
||||
return (Flush, _cards[0], 0b11111);
|
||||
}
|
||||
var sortedCards = _cards.OrderBy(c => c.Rank).ToArray();
|
||||
|
||||
var handRank = 0;
|
||||
var handRank = Schmaltz;
|
||||
var keepMask = 0;
|
||||
Card highCard = default;
|
||||
var handName1 = "";
|
||||
var handName2 = "";
|
||||
for (var i = 0; i < sortedCards.Length - 1; i++)
|
||||
{
|
||||
if (sortedCards[i].Rank == sortedCards[i+1].Rank)
|
||||
var matchesNextCard = sortedCards[i].Rank == sortedCards[i+1].Rank;
|
||||
var matchesPreviousCard = i > 0 && sortedCards[i].Rank == sortedCards[i - 1].Rank;
|
||||
|
||||
if (matchesNextCard)
|
||||
{
|
||||
keepMask |= 0b11 << i;
|
||||
highCard = sortedCards[i];
|
||||
(handRank, handName1, handName2) =
|
||||
(handRank, i > 0 && sortedCards[i].Rank == sortedCards[i - 1].Rank) switch
|
||||
{
|
||||
(<11, _) => (11, "A Pair", " of "),
|
||||
(11, true) => (13, "Three", " "),
|
||||
(11, _) => (12, "Two P", "air, "),
|
||||
(12, _) => (16, "Full H", "ouse, "),
|
||||
(_, true) => (17, "Four", " "),
|
||||
_ => (16, "Full H", "ouse, ")
|
||||
};
|
||||
handRank = matchesPreviousCard switch
|
||||
{
|
||||
_ when handRank < Pair => Pair,
|
||||
true when handRank == Pair => Three,
|
||||
_ when handRank == Pair => TwoPair,
|
||||
_ when handRank == TwoPair => FullHouse,
|
||||
true => Four,
|
||||
_ => FullHouse
|
||||
};
|
||||
}
|
||||
}
|
||||
if (keepMask == 0)
|
||||
@@ -92,36 +87,21 @@ internal class Hand
|
||||
if (sortedCards[3] - sortedCards[0] == 3)
|
||||
{
|
||||
keepMask=0b1111;
|
||||
handRank=10;
|
||||
handRank=PartialStraight;
|
||||
}
|
||||
if (sortedCards[4] - sortedCards[1] == 3)
|
||||
{
|
||||
if (handRank == 10)
|
||||
if (handRank == PartialStraight)
|
||||
{
|
||||
return (14, "Straig", "ht", sortedCards[4], 0b11111);
|
||||
return (Straight, sortedCards[4], 0b11111);
|
||||
}
|
||||
handRank=10;
|
||||
handRank=PartialStraight;
|
||||
keepMask=0b11110;
|
||||
}
|
||||
}
|
||||
return handRank < 10
|
||||
? (9, "Schmal", "tz, ", sortedCards[4], 0b11000)
|
||||
: (handRank, handName1, handName2, highCard, keepMask);
|
||||
}
|
||||
|
||||
private string GetHandName()
|
||||
{
|
||||
var sb = new StringBuilder(_name1).Append(_name2);
|
||||
if (_name1 == "A Flus")
|
||||
{
|
||||
sb.Append(HighCard.Suit).AppendLine();
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.Append(HighCard.Rank)
|
||||
.AppendLine(_name1 == "Schmal" || _name1 == "Straig" ? " High" : "'s");
|
||||
}
|
||||
return sb.ToString();
|
||||
return handRank < PartialStraight
|
||||
? (Schmaltz, sortedCards[4], 0b11000)
|
||||
: (handRank, highCard, keepMask);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
namespace Poker.Cards;
|
||||
|
||||
internal class HandRank
|
||||
{
|
||||
public static HandRank None = new(0, "");
|
||||
public static HandRank Schmaltz = new(1, "schmaltz, ", c => $"{c.Rank} high");
|
||||
public static HandRank PartialStraight = new(2, ""); // The original code does not assign a display string here
|
||||
public static HandRank Pair = new(3, "a pair of ", c => $"{c.Rank}'s");
|
||||
public static HandRank TwoPair = new(4, "two pair, ", c => $"{c.Rank}'s");
|
||||
public static HandRank Three = new(5, "three ", c => $"{c.Rank}'s");
|
||||
public static HandRank Straight = new(6, "straight", c => $"{c.Rank} high");
|
||||
public static HandRank Flush = new(7, "a flush in ", c => c.Suit.ToString());
|
||||
public static HandRank FullHouse = new(8, "full house, ", c => $"{c.Rank}'s");
|
||||
public static HandRank Four = new(9, "four ", c => $"{c.Rank}'s");
|
||||
// The original code does not detect a straight flush or royal flush
|
||||
|
||||
private readonly int _value;
|
||||
private readonly string _displayName;
|
||||
private readonly Func<Card, string> _suffixSelector;
|
||||
|
||||
private HandRank(int value, string displayName, Func<Card, string>? suffixSelector = null)
|
||||
{
|
||||
_value = value;
|
||||
_displayName = displayName;
|
||||
_suffixSelector = suffixSelector ?? (_ => "");
|
||||
}
|
||||
|
||||
public string ToString(Card highCard) => $"{_displayName}{_suffixSelector.Invoke(highCard)}";
|
||||
|
||||
public static bool operator >(HandRank x, HandRank y) => x._value > y._value;
|
||||
public static bool operator <(HandRank x, HandRank y) => x._value < y._value;
|
||||
public static bool operator >=(HandRank x, HandRank y) => x._value >= y._value;
|
||||
public static bool operator <=(HandRank x, HandRank y) => x._value <= y._value;
|
||||
}
|
||||
@@ -59,12 +59,12 @@ internal class Game
|
||||
Z = table.Computer.Hand.Rank switch
|
||||
{
|
||||
_ when table.Computer.Hand.IsWeak =>
|
||||
table.Computer.BluffIf(Get0To9() > 7, 0b11100) ??
|
||||
table.Computer.BluffIf(Get0To9() > 7, 0b11110) ??
|
||||
table.Computer.BluffIf(Get0To9() < 2, 0b11100) ??
|
||||
table.Computer.BluffIf(Get0To9() < 2, 0b11110) ??
|
||||
table.Computer.BluffIf(Get0To9() < 1, 0b11111) ??
|
||||
1,
|
||||
< 13 => table.Computer.BluffIf(Get0To9() < 2) ?? 0,
|
||||
<= 16 => 35,
|
||||
_ when table.Computer.Hand.Rank < HandRank.Three => table.Computer.BluffIf(Get0To9() < 2) ?? 0,
|
||||
_ when table.Computer.Hand.Rank < HandRank.FullHouse => 35,
|
||||
_ when Get0To9() < 1 => 35,
|
||||
_ => 2
|
||||
};
|
||||
@@ -90,8 +90,8 @@ internal class Game
|
||||
{
|
||||
_ when table.Computer.IsBluffing => 28,
|
||||
_ when table.Computer.Hand.IsWeak => 1,
|
||||
< 13 => Get0To9() == 0 ? 19 : 2,
|
||||
< 16 => Get0To9() == 8 ? 11 : 19,
|
||||
_ when table.Computer.Hand.Rank < HandRank.Three => Get0To9() == 0 ? 19 : 2,
|
||||
_ when table.Computer.Hand.Rank < HandRank.FullHouse => Get0To9() == 0 ? 11 : 19,
|
||||
_ => 2
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user