Reorganise classes

This commit is contained in:
Andrew Cooper
2022-06-18 22:15:05 +10:00
parent ac079fff75
commit fc65452ae6
10 changed files with 307 additions and 288 deletions

View File

@@ -1,4 +1,4 @@
namespace Poker;
namespace Poker.Cards;
internal record struct Card (Rank Rank, Suit Suit)
{

View File

@@ -1,6 +1,6 @@
using static Poker.Rank;
using static Poker.Cards.Rank;
namespace Poker;
namespace Poker.Cards;
internal class Deck
{

View File

@@ -1,6 +1,6 @@
using System.Text;
namespace Poker;
namespace Poker.Cards;
internal class Hand
{

View File

@@ -1,4 +1,4 @@
namespace Poker;
namespace Poker.Cards;
internal struct Rank : IComparable<Rank>
{
@@ -43,4 +43,8 @@ internal struct Rank : IComparable<Rank>
public static bool operator <=(Rank rank, int value) => rank._value <= value;
public static bool operator >=(Rank rank, int value) => rank._value >= value;
public override bool Equals(object? obj) => obj is Rank other && this == other;
public override int GetHashCode() => _value.GetHashCode();
}

View File

@@ -1,4 +1,4 @@
namespace Poker;
namespace Poker.Cards;
internal enum Suit
{

View File

@@ -1,5 +1,6 @@
using Poker.Cards;
using Poker.Players;
using Poker.Resources;
using static System.StringComparison;
namespace Poker;
@@ -239,284 +240,3 @@ internal record Bet (int Amount) : IAction
{
}
}
internal abstract class Player
{
private Table? _table;
private bool _hasFolded;
protected Player(int bank)
{
Hand = Hand.Empty;
Balance = bank;
}
public Hand Hand { get; set; }
public int Balance { get; set; }
public int Bet { get; private set; }
public bool HasFolded => _hasFolded;
protected Table Table =>
_table ?? throw new InvalidOperationException("The player must be sitting at the table.");
public void Sit(Table table) => _table = table;
public virtual void NewHand(Hand hand)
{
Hand = hand;
_hasFolded = false;
}
public void Pay(int amount)
{
Balance -= amount;
}
public virtual void TakeWinnings()
{
Balance += Table.Pot;
Table.Pot = 0;
}
public void Fold()
{
_hasFolded = true;
}
}
internal class Human : Player
{
private readonly IReadWrite _io;
public Human(int bank, IReadWrite io)
: base(bank)
{
HasWatch = true;
_io = io;
}
public bool HasWatch { get; set; }
public void DrawCards(Deck deck)
{
var count = _io.ReadNumber("How many cards do you want", 3, "You can't draw more than three cards.");
if (count == 0) { return; }
_io.WriteLine("What are their numbers:");
for (var i = 1; i <= count; i++)
{
Hand = Hand.Replace((int)_io.ReadNumber(), deck.DealCard());
}
_io.WriteLine("Your new hand:");
_io.Write(Hand);
}
public bool IsBroke()
{
_io.WriteLine();
_io.WriteLine("You can't bet with what you haven't got.");
if (Table.Computer.TryBuyWatch(this)) { return false; }
// The original program had some code about selling a tie tack, but due to a fault
// in the logic the code was unreachable. I've omitted it in this port.
_io.WriteLine("Your wad is shot. So long, sucker!");
return true;
}
public void ReceiveWatch()
{
// In the original code the player does not pay any money to receive the watch back.
HasWatch = true;
}
public void SellWatch(int amount)
{
HasWatch = false;
Balance += amount;
}
public override void TakeWinnings()
{
_io.WriteLine("You win.");
base.TakeWinnings();
}
}
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;
}
public bool IsBluffing => _isBluffing;
public override void NewHand(Hand hand)
{
base.NewHand(hand);
_isBluffing = false;
}
public int? BluffIf(bool shouldBluff, int? keepMask = null)
{
if (!shouldBluff) { return null; }
_isBluffing = true;
Hand.KeepMask = keepMask ?? Hand.KeepMask;
return 23;
}
public void DrawCards(Deck deck)
{
var keepMask = Hand.KeepMask;
var count = 0;
for (var i = 1; i <= 5; i++)
{
if ((keepMask & (1 << (i - 1))) == 0)
{
Hand = Hand.Replace(i, deck.DealCard());
count++;
}
}
_io.WriteLine();
_io.Write($"I am taking {count} card");
if (count != 1)
{
_io.WriteLine("s");
}
}
public bool TryBuyWatch(Human human)
{
if (!human.HasWatch) { return false; }
var response = _io.ReadString("Would you like to sell your watch");
if (response.StartsWith("N", InvariantCultureIgnoreCase)) { return false; }
var (value, message) = (_random.Next(10) < 7) switch
{
true => (75, "I'll give you $75 for it."),
false => (25, "That's a pretty crummy watch - I'll give you $25.")
};
_io.WriteLine(message);
human.SellWatch(value);
// The original code does not have the computer part with any money
return true;
}
public bool TrySellWatch(Human human)
{
if (human.HasWatch) { return false; }
var response = _io.ReadString("Would you like to buy back your watch for $50");
if (response.StartsWith("N", InvariantCultureIgnoreCase)) { return false; }
// The original code does not deduct $50 from the player
Balance += 50;
human.ReceiveWatch();
return true;
}
public override void TakeWinnings()
{
_io.WriteLine("I win.");
base.TakeWinnings();
}
}
internal class Table
{
private IReadWrite _io;
public int Pot;
private Deck _deck;
public Table(IReadWrite io, Deck deck, Human human, Computer computer)
{
_io = io;
_deck = deck;
Human = human;
Computer = computer;
human.Sit(this);
computer.Sit(this);
}
public Human Human { get; }
public Computer Computer { get; }
public void Deal()
{
Pot = 10;
Human.Pay(5);
Computer.Pay(5);
Human.NewHand(_deck.DealHand());
Computer.NewHand(_deck.DealHand());
_io.WriteLine("Your hand:");
_io.Write(Human.Hand);
}
public void Draw()
{
_io.WriteLine();
_io.Write("Now we draw -- ");
Human.DrawCards(_deck);
Computer.DrawCards(_deck);
_io.WriteLine();
}
public void AcceptBets()
{
}
public bool SomeoneHasFolded()
{
if (Human.HasFolded)
{
_io.WriteLine();
Computer.TakeWinnings();
}
else if (Computer.HasFolded)
{
_io.WriteLine();
Human.TakeWinnings();
}
else
{
return false;
}
Pot = 0;
return true;
}
public Player? GetWinner()
{
_io.WriteLine();
_io.WriteLine("Now we compare hands:");
_io.WriteLine("My hand:");
_io.Write(Computer.Hand);
_io.WriteLine();
_io.Write($"You have {Human.Hand.Name}");
_io.Write($"and I have {Computer.Hand.Name}");
if (Computer.Hand > Human.Hand) { return Computer; }
if (Human.Hand > Computer.Hand) { return Human; }
_io.WriteLine("The hand is drawn.");
_io.WriteLine($"All $ {Pot} remains in the pot.");
return null;
}
}

View File

@@ -0,0 +1,95 @@
using Poker.Cards;
using static System.StringComparison;
namespace Poker.Players;
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;
}
public bool IsBluffing => _isBluffing;
public override void NewHand(Hand hand)
{
base.NewHand(hand);
_isBluffing = false;
}
public int? BluffIf(bool shouldBluff, int? keepMask = null)
{
if (!shouldBluff) { return null; }
_isBluffing = true;
Hand.KeepMask = keepMask ?? Hand.KeepMask;
return 23;
}
public void DrawCards(Deck deck)
{
var keepMask = Hand.KeepMask;
var count = 0;
for (var i = 1; i <= 5; i++)
{
if ((keepMask & (1 << (i - 1))) == 0)
{
Hand = Hand.Replace(i, deck.DealCard());
count++;
}
}
_io.WriteLine();
_io.Write($"I am taking {count} card");
if (count != 1)
{
_io.WriteLine("s");
}
}
public bool TryBuyWatch(Human human)
{
if (!human.HasWatch) { return false; }
var response = _io.ReadString("Would you like to sell your watch");
if (response.StartsWith("N", InvariantCultureIgnoreCase)) { return false; }
var (value, message) = (_random.Next(10) < 7) switch
{
true => (75, "I'll give you $75 for it."),
false => (25, "That's a pretty crummy watch - I'll give you $25.")
};
_io.WriteLine(message);
human.SellWatch(value);
// The original code does not have the computer part with any money
return true;
}
public bool TrySellWatch(Human human)
{
if (human.HasWatch) { return false; }
var response = _io.ReadString("Would you like to buy back your watch for $50");
if (response.StartsWith("N", InvariantCultureIgnoreCase)) { return false; }
// The original code does not deduct $50 from the player
Balance += 50;
human.ReceiveWatch();
return true;
}
public override void TakeWinnings()
{
_io.WriteLine("I win.");
base.TakeWinnings();
}
}

View File

@@ -0,0 +1,64 @@
using Poker.Cards;
namespace Poker.Players;
internal class Human : Player
{
private readonly IReadWrite _io;
public Human(int bank, IReadWrite io)
: base(bank)
{
HasWatch = true;
_io = io;
}
public bool HasWatch { get; set; }
public void DrawCards(Deck deck)
{
var count = _io.ReadNumber("How many cards do you want", 3, "You can't draw more than three cards.");
if (count == 0) { return; }
_io.WriteLine("What are their numbers:");
for (var i = 1; i <= count; i++)
{
Hand = Hand.Replace((int)_io.ReadNumber(), deck.DealCard());
}
_io.WriteLine("Your new hand:");
_io.Write(Hand);
}
public bool IsBroke()
{
_io.WriteLine();
_io.WriteLine("You can't bet with what you haven't got.");
if (Table.Computer.TryBuyWatch(this)) { return false; }
// The original program had some code about selling a tie tack, but due to a fault
// in the logic the code was unreachable. I've omitted it in this port.
_io.WriteLine("Your wad is shot. So long, sucker!");
return true;
}
public void ReceiveWatch()
{
// In the original code the player does not pay any money to receive the watch back.
HasWatch = true;
}
public void SellWatch(int amount)
{
HasWatch = false;
Balance += amount;
}
public override void TakeWinnings()
{
_io.WriteLine("You win.");
base.TakeWinnings();
}
}

View File

@@ -0,0 +1,47 @@
using Poker.Cards;
namespace Poker.Players;
internal abstract class Player
{
private Table? _table;
private bool _hasFolded;
protected Player(int bank)
{
Hand = Hand.Empty;
Balance = bank;
}
public Hand Hand { get; set; }
public int Balance { get; set; }
public int Bet { get; private set; }
public bool HasFolded => _hasFolded;
protected Table Table =>
_table ?? throw new InvalidOperationException("The player must be sitting at the table.");
public void Sit(Table table) => _table = table;
public virtual void NewHand(Hand hand)
{
Hand = hand;
_hasFolded = false;
}
public void Pay(int amount)
{
Balance -= amount;
}
public virtual void TakeWinnings()
{
Balance += Table.Pot;
Table.Pot = 0;
}
public void Fold()
{
_hasFolded = true;
}
}

89
71_Poker/csharp/Table.cs Normal file
View File

@@ -0,0 +1,89 @@
using Poker.Cards;
using Poker.Players;
namespace Poker;
internal class Table
{
private IReadWrite _io;
public int Pot;
private Deck _deck;
public Table(IReadWrite io, Deck deck, Human human, Computer computer)
{
_io = io;
_deck = deck;
Human = human;
Computer = computer;
human.Sit(this);
computer.Sit(this);
}
public Human Human { get; }
public Computer Computer { get; }
public void Deal()
{
Pot = 10;
Human.Pay(5);
Computer.Pay(5);
Human.NewHand(_deck.DealHand());
Computer.NewHand(_deck.DealHand());
_io.WriteLine("Your hand:");
_io.Write(Human.Hand);
}
public void Draw()
{
_io.WriteLine();
_io.Write("Now we draw -- ");
Human.DrawCards(_deck);
Computer.DrawCards(_deck);
_io.WriteLine();
}
public void AcceptBets()
{
}
public bool SomeoneHasFolded()
{
if (Human.HasFolded)
{
_io.WriteLine();
Computer.TakeWinnings();
}
else if (Computer.HasFolded)
{
_io.WriteLine();
Human.TakeWinnings();
}
else
{
return false;
}
Pot = 0;
return true;
}
public Player? GetWinner()
{
_io.WriteLine();
_io.WriteLine("Now we compare hands:");
_io.WriteLine("My hand:");
_io.Write(Computer.Hand);
_io.WriteLine();
_io.Write($"You have {Human.Hand.Name}");
_io.Write($"and I have {Computer.Hand.Name}");
if (Computer.Hand > Human.Hand) { return Computer; }
if (Human.Hand > Computer.Hand) { return Human; }
_io.WriteLine("The hand is drawn.");
_io.WriteLine($"All $ {Pot} remains in the pot.");
return null;
}
}