diff --git a/71_Poker/csharp/Game.cs b/71_Poker/csharp/Game.cs index 63239bd6..65a3a131 100644 --- a/71_Poker/csharp/Game.cs +++ b/71_Poker/csharp/Game.cs @@ -1,6 +1,7 @@ using Poker.Cards; using Poker.Players; using Poker.Resources; +using Poker.Strategies; namespace Poker; @@ -9,7 +10,6 @@ internal class Game private readonly IReadWrite _io; private readonly IRandom _random; - private int Z; private int V; public Game(IReadWrite io, IRandom random) @@ -54,28 +54,22 @@ internal class Game _io.WriteLine(); if (table.Human.Balance <= table.Ante && table.Human.IsBroke()) { return true; } - table.Deal(); + table.Deal(_random); _io.WriteLine(); - Z = true switch + table.Computer.Strategy = (table.Computer.Hand.IsWeak, table.Computer.Hand.Rank < HandRank.Three, table.Computer.Hand.Rank < HandRank.FullHouse) switch { - _ when table.Computer.Hand.IsWeak => - table.Computer.BluffIf(Get0To9() < 2, 0b11100) ?? - table.Computer.BluffIf(Get0To9() < 2, 0b11110) ?? - table.Computer.BluffIf(Get0To9() < 1, 0b11111) ?? - 1, - _ 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 + (true, _, _) when Get0To9() < 2 => Strategy.Bluff(23, 0b11100), + (true, _, _) when Get0To9() < 2 => Strategy.Bluff(23, 0b11110), + (true, _, _) when Get0To9() < 1 => Strategy.Bluff(23, 0b11111), + (true, _, _) => Strategy.Fold, + (false, true, _) => Get0To9() < 2 ? Strategy.Bluff(23) : Strategy.Check, + (false, false, true) => Strategy.Bet(35), + (false, false, false) => Get0To9() < 1 ? Strategy.Bet(35) : Strategy.Raise }; - if (Z <= 1) + if (table.Computer.Strategy is Strategies.Bet) { - _io.WriteLine("I check."); - } - else - { - V = Z + Get0To9(); + V = table.Computer.Strategy.Value + Get0To9(); if (table.Computer.Balance - table.Human.Bet - V < 0) { if (table.Human.Bet == 0) @@ -97,32 +91,32 @@ internal class Game _io.WriteLine($"I'll open with ${V}"); table.Computer.Bet = V; } - if (GetWager()) { return true; } + else + { + _io.WriteLine("I check."); + } + if (GetWager(table.Computer.Strategy)) { return true; } if (table.SomeoneHasFolded()) { return false; } table.Draw(); - Z = true switch + table.Computer.Strategy = (table.Computer.Hand.IsWeak, table.Computer.Hand.Rank < HandRank.Three, table.Computer.Hand.Rank < HandRank.FullHouse) switch { - _ when table.Computer.IsBluffing => 28, - _ when table.Computer.Hand.IsWeak => 1, - _ when table.Computer.Hand.Rank < HandRank.Three => Get0To9() == 0 ? 19 : 2, - _ when table.Computer.Hand.Rank < HandRank.FullHouse => Get0To9() == 0 ? 11 : 19, - _ => 2 + _ when table.Computer.Strategy is Bluff => Strategy.Bluff(28), + (true, _, _) => Strategy.Fold, + (false, true, _) => Get0To9() == 0 ? Strategy.Bet(19) : Strategy.Raise, + (false, false, true) => Get0To9() == 0 ? Strategy.Bet(11) : Strategy.Bet(19), + (false, false, false) => Strategy.Raise }; - if (GetWager()) { return true; } + if (GetWager(table.Computer.Strategy)) { return true; } if (table.Human.HasBet) { if (table.SomeoneHasFolded()) { return false; } } - else if (!table.Computer.IsBluffing && table.Computer.Hand.IsWeak) + else if (table.Computer.Strategy is Strategies.Bet) { - _io.WriteLine("I'll check"); - } - else - { - V = Z + Get0To9(); + V = table.Computer.Strategy.Value + Get0To9(); if (table.Computer.Balance - table.Human.Bet - V < 0) { if (table.Human.Bet == 0) @@ -143,9 +137,13 @@ internal class Game } _io.WriteLine($"I'll bet ${V}"); table.Computer.Bet = V; - if (GetWager()) { return true; } + if (GetWager(table.Computer.Strategy)) { return true; } if (table.SomeoneHasFolded()) { return false; } } + else + { + _io.WriteLine("I'll check"); + } if (table.GetWinner() is { } winner) { winner.TakeWinnings(); @@ -153,24 +151,25 @@ internal class Game } } - bool GetWager() + bool GetWager(Strategy computerStrategy) { while (true) { table.Human.HasBet = false; while (true) { - if (_io.ReadPlayerAction(table.Computer.Bet == 0 && table.Human.Bet == 0) is Bet bet) + var humanStrategy = _io.ReadHumanStrategy(table.Computer.Bet == 0 && table.Human.Bet == 0); + if (humanStrategy is Bet or Check) { - if (table.Human.Bet + bet.Amount < table.Computer.Bet) + if (table.Human.Bet + humanStrategy.Value < table.Computer.Bet) { _io.WriteLine("If you can't see my bet, then fold."); continue; } - if (table.Human.Balance - table.Human.Bet - bet.Amount >= 0) + if (table.Human.Balance - table.Human.Bet - humanStrategy.Value >= 0) { table.Human.HasBet = true; - table.Human.Bet += bet.Amount; + table.Human.Bet += humanStrategy.Value; break; } if (table.Human.IsBroke()) { return true; } @@ -188,7 +187,7 @@ internal class Game table.UpdatePot(); return false; } - if (Z == 1) + if (computerStrategy is Fold) { if (table.Human.Bet > 5) { @@ -198,9 +197,9 @@ internal class Game } V = 5; } - if (table.Human.Bet > 3 * Z) + if (table.Human.Bet > 3 * computerStrategy.Value) { - if (Z != 2) + if (computerStrategy is not Raise) { _io.WriteLine("I'll see you."); table.Computer.Bet = table.Human.Bet; @@ -234,13 +233,3 @@ internal class Game } } } - -internal interface IAction { } -internal record Fold : IAction; -internal record Bet(int Amount) : IAction -{ - public Bet(float amount) - : this((int)amount) - { - } -} diff --git a/71_Poker/csharp/IReadWriteExtensions.cs b/71_Poker/csharp/IReadWriteExtensions.cs index 829c6719..7559a328 100644 --- a/71_Poker/csharp/IReadWriteExtensions.cs +++ b/71_Poker/csharp/IReadWriteExtensions.cs @@ -1,3 +1,4 @@ +using Poker.Strategies; using static System.StringComparison; namespace Poker; @@ -28,7 +29,7 @@ internal static class IReadWriteExtensions } } - internal static IAction ReadPlayerAction(this IReadWrite io, bool noCurrentBets) + internal static Strategy ReadHumanStrategy(this IReadWrite io, bool noCurrentBets) { while(true) { @@ -36,12 +37,12 @@ internal static class IReadWriteExtensions var bet = io.ReadNumber("What is your bet"); if (bet != (int)bet) { - if (noCurrentBets && bet == .5) { return new Bet(0); } + if (noCurrentBets && bet == .5) { return Strategy.Check; } io.WriteLine("No small change, please."); continue; } - if (bet == 0) { return new Fold(); } - return new Bet(bet); + if (bet == 0) { return Strategy.Fold; } + return Strategy.Bet(bet); } } } \ No newline at end of file diff --git a/71_Poker/csharp/Players/Computer.cs b/71_Poker/csharp/Players/Computer.cs index a5506853..7a7cff0b 100644 --- a/71_Poker/csharp/Players/Computer.cs +++ b/71_Poker/csharp/Players/Computer.cs @@ -1,4 +1,5 @@ using Poker.Cards; +using Poker.Strategies; using static System.StringComparison; namespace Poker.Players; @@ -7,35 +8,25 @@ internal class Computer : Player { private readonly IReadWrite _io; private readonly IRandom _random; - private bool _isBluffing; public Computer(int bank, IReadWrite io, IRandom random) : base(bank) { _io = io; _random = random; + Strategy = Strategy.Check; } - public bool IsBluffing => _isBluffing; + public Strategy Strategy { get; set; } public override void NewHand() { base.NewHand(); - _isBluffing = false; - } - - public int? BluffIf(bool shouldBluff, int? keepMask = null) - { - if (!shouldBluff) { return null; } - - _isBluffing = true; - Hand.KeepMask = keepMask ?? Hand.KeepMask; - return 23; } protected override void DrawCards(Deck deck) { - var keepMask = Hand.KeepMask; + var keepMask = Strategy.KeepMask ?? Hand.KeepMask; var count = 0; for (var i = 1; i <= 5; i++) { diff --git a/71_Poker/csharp/Strategies/Bet.cs b/71_Poker/csharp/Strategies/Bet.cs new file mode 100644 index 00000000..7299898d --- /dev/null +++ b/71_Poker/csharp/Strategies/Bet.cs @@ -0,0 +1,8 @@ +namespace Poker.Strategies; + +internal class Bet : Strategy +{ + public Bet(int amount) => Value = amount; + + public override int Value { get; } +} diff --git a/71_Poker/csharp/Strategies/Bluff.cs b/71_Poker/csharp/Strategies/Bluff.cs new file mode 100644 index 00000000..ed51e33e --- /dev/null +++ b/71_Poker/csharp/Strategies/Bluff.cs @@ -0,0 +1,12 @@ +namespace Poker.Strategies; + +internal class Bluff : Bet +{ + public Bluff(int amount, int? keepMask) + : base(amount) + { + KeepMask = keepMask; + } + + public override int? KeepMask { get; } +} \ No newline at end of file diff --git a/71_Poker/csharp/Strategies/Check.cs b/71_Poker/csharp/Strategies/Check.cs new file mode 100644 index 00000000..4bbab973 --- /dev/null +++ b/71_Poker/csharp/Strategies/Check.cs @@ -0,0 +1,6 @@ +namespace Poker.Strategies; + +internal class Check : Strategy +{ + public override int Value => 0; +} diff --git a/71_Poker/csharp/Strategies/Fold.cs b/71_Poker/csharp/Strategies/Fold.cs new file mode 100644 index 00000000..2ba31c33 --- /dev/null +++ b/71_Poker/csharp/Strategies/Fold.cs @@ -0,0 +1,6 @@ +namespace Poker.Strategies; + +internal class Fold : Strategy +{ + public override int Value => -1; +} diff --git a/71_Poker/csharp/Strategies/Raise.cs b/71_Poker/csharp/Strategies/Raise.cs new file mode 100644 index 00000000..7be9e522 --- /dev/null +++ b/71_Poker/csharp/Strategies/Raise.cs @@ -0,0 +1,6 @@ +namespace Poker.Strategies; + +internal class Raise : Bet +{ + public Raise() : base(2) { } +} diff --git a/71_Poker/csharp/Strategies/Strategy.cs b/71_Poker/csharp/Strategies/Strategy.cs new file mode 100644 index 00000000..9a5d6842 --- /dev/null +++ b/71_Poker/csharp/Strategies/Strategy.cs @@ -0,0 +1,14 @@ +namespace Poker.Strategies; + +internal abstract class Strategy +{ + public static Strategy Fold = new Fold(); + public static Strategy Check = new Check(); + public static Strategy Raise = new Raise(); + public static Strategy Bet(float amount) => new Bet((int)amount); + public static Strategy Bet(int amount) => new Bet(amount); + public static Strategy Bluff(int amount, int? keepMask = null) => new Bluff(amount, keepMask); + + public abstract int Value { get; } + public virtual int? KeepMask { get; } +} diff --git a/71_Poker/csharp/Table.cs b/71_Poker/csharp/Table.cs index 60a3a89d..059d2fff 100644 --- a/71_Poker/csharp/Table.cs +++ b/71_Poker/csharp/Table.cs @@ -5,7 +5,7 @@ namespace Poker; internal class Table { - private IReadWrite _io; + private readonly IReadWrite _io; public int Pot; public Table(IReadWrite io, Deck deck, Human human, Computer computer) @@ -24,9 +24,9 @@ internal class Table public Human Human { get; } public Computer Computer { get; } - public void Deal() + public void Deal(IRandom random) { - Deck.Shuffle(); + Deck.Shuffle(random); Pot = Human.AnteUp() + Computer.AnteUp();