From 62a4d0b5f12ef5c944454069045cb54a7312e972 Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Tue, 19 Apr 2022 07:47:20 +1000 Subject: [PATCH 01/29] Setup game skeleton --- 71_Poker/csharp/Games.cs | 19 +++++++++++++++++++ 71_Poker/csharp/Poker.csproj | 8 ++++++++ 71_Poker/csharp/Program.cs | 4 ++++ 71_Poker/csharp/Resources/Instructions.txt | 5 +++++ 71_Poker/csharp/Resources/Resource.cs | 17 +++++++++++++++++ 71_Poker/csharp/Resources/Title.txt | 5 +++++ 6 files changed, 58 insertions(+) create mode 100644 71_Poker/csharp/Games.cs create mode 100644 71_Poker/csharp/Program.cs create mode 100644 71_Poker/csharp/Resources/Instructions.txt create mode 100644 71_Poker/csharp/Resources/Resource.cs create mode 100644 71_Poker/csharp/Resources/Title.txt diff --git a/71_Poker/csharp/Games.cs b/71_Poker/csharp/Games.cs new file mode 100644 index 00000000..b72b4002 --- /dev/null +++ b/71_Poker/csharp/Games.cs @@ -0,0 +1,19 @@ +using Poker.Resources; + +internal class Game +{ + private readonly IReadWrite _io; + private readonly IRandom _random; + + public Game(IReadWrite io, IRandom random) + { + _io = io; + _random = random; + } + + internal void Play() + { + _io.Write(Resource.Streams.Title); + _io.Write(Resource.Streams.Instructions); + } +} \ No newline at end of file diff --git a/71_Poker/csharp/Poker.csproj b/71_Poker/csharp/Poker.csproj index d3fe4757..3870320c 100644 --- a/71_Poker/csharp/Poker.csproj +++ b/71_Poker/csharp/Poker.csproj @@ -6,4 +6,12 @@ enable enable + + + + + + + + diff --git a/71_Poker/csharp/Program.cs b/71_Poker/csharp/Program.cs new file mode 100644 index 00000000..b1f36179 --- /dev/null +++ b/71_Poker/csharp/Program.cs @@ -0,0 +1,4 @@ +global using Games.Common.IO; +global using Games.Common.Randomness; + +new Game(new ConsoleIO(), new RandomNumberGenerator()).Play(); \ No newline at end of file diff --git a/71_Poker/csharp/Resources/Instructions.txt b/71_Poker/csharp/Resources/Instructions.txt new file mode 100644 index 00000000..7f82c07e --- /dev/null +++ b/71_Poker/csharp/Resources/Instructions.txt @@ -0,0 +1,5 @@ +Welcome to the casino. We each have $200. +I will open the betting before the draw; you open after. +To fold bet 0; to check bet .5. +Enough talk -- Let's get down to business. + diff --git a/71_Poker/csharp/Resources/Resource.cs b/71_Poker/csharp/Resources/Resource.cs new file mode 100644 index 00000000..0ceddb0d --- /dev/null +++ b/71_Poker/csharp/Resources/Resource.cs @@ -0,0 +1,17 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +namespace Poker.Resources; + +internal static class Resource +{ + internal static class Streams + { + public static Stream Instructions => GetStream(); + public static Stream Title => GetStream(); + } + + private static Stream GetStream([CallerMemberName] string? name = null) + => Assembly.GetExecutingAssembly().GetManifestResourceStream($"Poker.Resources.{name}.txt") + ?? throw new ArgumentException($"Resource stream {name} does not exist", nameof(name)); +} \ No newline at end of file diff --git a/71_Poker/csharp/Resources/Title.txt b/71_Poker/csharp/Resources/Title.txt new file mode 100644 index 00000000..2f5c6aa2 --- /dev/null +++ b/71_Poker/csharp/Resources/Title.txt @@ -0,0 +1,5 @@ + Poker + Creative Computing Morristown, New Jersey + + + From 1139eb9cd925249d39e5632fcbcb6b3428965718 Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Wed, 27 Apr 2022 03:17:22 +1000 Subject: [PATCH 02/29] Transliterate BASIC code --- 71_Poker/csharp/Games.cs | 594 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 594 insertions(+) diff --git a/71_Poker/csharp/Games.cs b/71_Poker/csharp/Games.cs index b72b4002..0a6dcbe8 100644 --- a/71_Poker/csharp/Games.cs +++ b/71_Poker/csharp/Games.cs @@ -5,15 +5,609 @@ internal class Game private readonly IReadWrite _io; private readonly IRandom _random; + private class FloatArray + { + private float[] _values; + + public FloatArray(float[] values) + { + _values = values; + } + + public float this[float index] + { + get => _values[(int)index]; + set => _values[(int)index] = value; + } + } + + private readonly FloatArray AA = new(new float[51]); // 10 DIM A(50),B(15) + private readonly FloatArray BB = new(new float[16]); + private float O = 1; // 90 = 120 + private float C = 200; + private float S = 200; + private float P = 0; + + private float B; + private float M; + private float T; + private float D; + private float G; + private float I; + private float N; + private float U; + private float Z; + private float X; + private float K; + private float V; + private float Q; + + private string JS; + private string KS; + private string HS; + private string IS; + public Game(IReadWrite io, IRandom random) { _io = io; _random = random; } + private float FNA() => (int)_random.NextFloat(10); // 20 DEF FNAA[X]=(int)(10*_random.NextFloat()) + + private float FNB(float x) => x - 100 * (int)(x / 100); // 30 DEF FNB(X)=X-100*(int)(X/100) + internal void Play() { _io.Write(Resource.Streams.Title); _io.Write(Resource.Streams.Instructions); + +_90: O=1; +_100: C=200; +_110: S=200; + + while(PlayHand()); + } + + internal bool PlayHand() + { +_120: P=0; +_140: _io.WriteLine(); +_150: if (C<=5) { Line_3670(); return false; } +_160: _io.WriteLine("THE ANTE IS $5. I WILL DEAL:"); +_170: _io.WriteLine(); +_180: if (S>5) { goto _200; } +_190: if (Line_3830()) { return false; } +_200: P=P+10; +_210: S=S-5; +_220: C=C-5; +_230: for (Z=1; Z <= 10; Z++) + { +_240: Line_1740(); + } +_260: _io.WriteLine("YOUR HAND:"); +_270: N=1; +_280: Line_1850(); +_290: N=6; +_300: I=2; +_310: Line_2170(); +_320: _io.WriteLine(); +_330: if (I!=6) { goto _470; } +_340: if (FNA()<=7) { goto _370; } +_350: X=11100; +_360: goto _420; +_370: if (FNA()<=7) { goto _400; } +_380: X=11110; +_390: goto _420; +_400: if (FNA()>=1) { goto _450; } +_410: X=11111; +_420: I=7; +_430: Z=23; +_440: goto _580; +_450: Z=1; +_460: goto _510; +_470: if (U>=13) { goto _540; } +_480: if (FNA()>=2) { goto _500; } +_490: goto _420; +_500: Z=0; +_510: K=0; +_520: _io.WriteLine("I CHECK."); +_530: goto _620; +_540: if (U<=16) { goto _570; } +_550: Z=2; +_560: if (FNA()>=1) { goto _580; } +_570: Z=35; +_580: V=Z+FNA(); +_590: if (Line_3480()) { return false; } +_600: _io.WriteLine($"I'LL OPEN WITH ${V}"); +_610: K=V; +_620: if (Line_3050()) { return false; } +_630: var response = Line_650(); + if (response.HasValue) { return response.Value; } +_640: goto _820; + + bool? Line_650() + { +_650: if (I!=3) { return Line_760(); } +_660: _io.WriteLine(); + return Line_670(); + } + + bool? Line_670() + { +_670: _io.WriteLine("I WIN."); +_680: C=C+P; + return Line_690(); + } + + bool? Line_690() + { +_690: _io.WriteLine($"NOW I HAVE ${C}AND YOU HAVE ${S}"); +_700: _io.Write("DO YOU WISH TO CONTINUE"); +_710: HS = _io.ReadString(""); +_720: if (HS=="YES") { return true; } +_730: if (HS=="NO") { return false; } +_740: _io.WriteLine("ANSWER YES OR NO, PLEASE."); +_750: goto _700; + } + + bool? Line_760() + { +_760: if (I!=4) { return Line_810(); } +_770: _io.WriteLine(); + return Line_780(); + } + + bool? Line_780() + { +_780: _io.WriteLine("YOU WIN."); +_790: S=S+P; +_800: return Line_690(); + } + + bool? Line_810() + { +_810: return null; + } + +_820: _io.WriteLine(); +_830: _io.Write("NOW WE DRAW -- HOW MANY CARDS DO YOU WANT"); +_840: T = _io.ReadNumber(""); +_850: if (T==0) { goto _980; } +_860: Z=10; +_870: if (T<4) { goto _900; } +_880: _io.WriteLine("YOU CAN'T DRAW MORE THAN THREE CARDS."); +_890: goto _840; +_900: _io.WriteLine("WHAT ARE THEIR NUMBERS:"); +_910: for (Q=1; Q <= T; Q++) + { +_920: U = _io.ReadNumber(""); +_930: Line_1730(); + } +_950: _io.WriteLine("YOUR NEW HAND:"); +_960: N=1; +_970: Line_1850(); +_980: Z=10+T; +_990: for (U=6; U <= 10; U++) + { +_1000: if ((int)(X/Math.Pow(10, U-6))!=10*(int)(X/Math.Pow(10, U-5))) { goto _1020; } +_1010: Line_1730(); +_1020: ; + } +_1030: _io.WriteLine(); +_1040: _io.Write($"I AM TAKING{Z-10-T}CARD"); +_1050: if (Z==11+T) { goto _1090; } +_1060: _io.WriteLine("S"); +_1070: _io.WriteLine(); +_1080: goto _1100; +_1090: _io.WriteLine(); +_1100: N=6; +_1110: V=I; +_1120: I=1; +_1130: Line_2170(); +_1140: B=U; +_1150: M=D; +_1160: if (V!=7) { goto _1190; } +_1170: Z=28; +_1180: goto _1330; +_1190: if (I!=6) { goto _1220; } +_1200: Z=1; +_1210: goto _1330; +_1220: if (U>=13) { goto _1270; } +_1230: Z=2; +_1240: if (FNA()!=6) { goto _1260; } +_1250: Z=19; +_1260: goto _1330; +_1270: if (U>=16) { goto _1320; } +_1280: Z=19; +_1290: if (FNA()!=8) { goto _1310; } +_1300: Z=11; +_1310: goto _1330; +_1320: Z=2; +_1330: K=0; +_1340: if (Line_3050()) { return false; } +_1350: if (T!=.5) { goto _1450; } +_1360: if (V==7) { goto _1400; } +_1370: if (I!=6) { goto _1400; } +_1380: _io.WriteLine("I'LL CHECK"); +_1390: goto _1460; +_1400: V=Z+FNA(); +_1410: if (Line_3480()) { return false; } +_1420: _io.WriteLine($"I'LL BET ${V}"); +_1430: K=V; +_1440: if (Line_3060()) { return false; } +_1450: response = Line_650(); + if (response.HasValue) { return response.Value; } +_1460: _io.WriteLine(); +_1470: _io.WriteLine("NOW WE COMPARE HANDS:"); +_1480: JS=HS; +_1490: KS=IS; +_1500: _io.WriteLine("MY HAND:"); +_1510: N=6; +_1520: Line_1850(); +_1530: N=1; +_1540: Line_2170(); +_1550: _io.WriteLine(); +_1560: _io.Write("YOU HAVE "); +_1570: K=D; +_1580: Line_3690(); +_1590: HS=JS; +_1600: IS=KS; +_1610: K=M; +_1620: _io.Write("AND I HAVE "); +_1630: Line_3690(); +_1640: if (B>U) { return Line_670().Value; } +_1650: if (U>B) { return Line_780().Value; } +_1660: if (HS=="A FLUS") { goto _1700; } +_1662: if (FNB(M)FNB(D)) { return Line_670().Value; } +_1670: _io.WriteLine("THE HAND IS DRAWN."); +_1680: _io.WriteLine($"ALL ${P}REMAINS IN THE POT."); +_1690: goto _140; +_1700: if (FNB(M)>FNB(D)) { return Line_670().Value; } +_1710: if (FNB(D)>FNB(M)) { return Line_780().Value; } +_1720: goto _1670; + + void Line_1730() + { +_1730: Z=Z+1; + Line_1740(); + } + + void Line_1740() + { +_1740: AA[Z]=100*(int)(4*_random.NextFloat())+(int)(100*_random.NextFloat()); +_1750: if ((int)(AA[Z]/100)>3) { goto _1740; } +_1760: if (AA[Z]-100*(int)(AA[Z]/100)>12) { goto _1740; } +_1765: if (Z==1) { goto _1840; } +_1770: for (K=1; K <= Z-1; K++) + { +_1780: if (AA[Z]==AA[K]) { goto _1740; } + } +_1800: if (Z<=10) { goto _1840; } +_1810: N=AA[U]; +_1820: AA[U]=AA[Z]; +_1830: AA[Z]=N; +_1840: return; + } + + void Line_1850() + { +_1850: for (Z = N; Z <= N+4; Z++) + { +_1860: _io.Write($"{Z}-- "); +_1870: Line_1950(); +_1880: _io.Write(" OF"); +_1890: Line_2070(); +_1900: if (Z/2!=(int)(Z/2)) { goto _1920; } +_1910: _io.WriteLine(); +_1920: ; + } +_1930: _io.WriteLine(); +_1940: return; + } + + void Line_1950() + { +_1950: K=FNB(AA[Z]); + Line_1960(); + } + + void Line_1960() + { +_1960: if (K!=9) { goto _1980; } +_1970: _io.Write("JACK"); +_1980: if (K!=10) { goto _2000; } +_1990: _io.Write("QUEEN"); +_2000: if (K!=11) { goto _2020; } +_2010: _io.Write("KING"); +_2020: if (K!=12) { goto _2040; } +_2030: _io.Write("ACE"); +_2040: if (K>=9) { goto _2060; } +_2050: _io.Write(K+2); +_2060: return; + } + + void Line_2070() + { +_2070: K=(int)(AA[Z]/100); + Line_2080(); + } + + void Line_2080() + { +_2080: if (K!=0) { goto _2100; } +_2090: _io.Write(" CLUBS"); +_2100: if (K!=1) { goto _2120; } +_2110: _io.Write(" DIAMONDS"); +_2120: if (K!=2) { goto _2140; } +_2130: _io.Write(" HEARTS"); +_2140: if (K!=3) { goto _2160; } +_2150: _io.Write(" SPADES"); +_2160: return; + } + + void Line_2170() + { +_2170: U=0; +_2180: for (Z=N; Z <= N+4; Z++) + { +_2190: BB[Z]=FNB(AA[Z]); +_2200: if (Z==N+4) { goto _2230; } +_2210: if ((int)(AA[Z]/100)!=(int)(AA[Z+1]/100)) { goto _2230; } +_2220: U=U+1; +_2230: ; + } +_2240: if (U!=4) { goto _2310; } +_2250: X=11111; +_2260: D=AA[N]; +_2270: HS="A FLUS"; +_2280: IS="H IN"; +_2290: U=15; +_2300: return; +_2310: for (Z=N; Z <= N+3; Z++) + { +_2320: for (K=Z+1; K <= N+4; K++) + { +_2330: if (BB[Z]<=BB[K]) { goto _2390; } +_2340: X=AA[Z]; +_2350: AA[Z]=AA[K]; +_2360: BB[Z]=BB[K]; +_2370: AA[K]=X; +_2380: BB[K]=AA[K]-100*(int)(AA[K]/100); +_2390: ; + } + } +_2410: X=0; +_2420: for (Z=N; Z <= N+3; Z++) + { +_2430: if (BB[Z]!=BB[Z+1]) { goto _2470; } +_2440: X=X+11*(float)Math.Pow(10, Z-N); +_2450: D=AA[Z]; +_2460: Line_2760(); +_2470: ; + } +_2480: if (X!=0) { goto _2620; } +_2490: if (BB[N]+3!=BB[N+3]) { goto _2520; } +_2500: X=1111; +_2510: U=10; +_2520: if (BB[N+1]+3!=BB[N+4]) { goto _2620; } +_2530: if (U!=10) { goto _2600; } +_2540: U=14; +_2550: HS="STRAIG"; +_2560: IS="HT"; +_2570: X=11111; +_2580: D=AA[N+4]; +_2590: return; +_2600: U=10; +_2610: X=11110; +_2620: if (U>=10) { goto _2690; } +_2630: D=AA[N+4]; +_2640: HS="SCHMAL"; +_2650: IS="TZ, "; +_2660: U=9; +_2670: X=11000; +_2680: goto _2740; +_2690: if (U!=10) { goto _2720; } +_2700: if (I==1) { goto _2740; } +_2710: goto _2750; +_2720: if (U>12) { goto _2750; } +_2730: if (FNB(D)>6) { goto _2750; } +_2740: I=6; +_2750: return; + } + + void Line_2760() + { +_2760: if (U>=11) { goto _2810; } +_2770: U=11; +_2780: HS="A PAIR"; +_2790: IS=" OF "; +_2800: return; +_2810: if (U!=11) { goto _2910; } +_2820: if (BB[Z]!=BB[Z-1]) { goto _2870; } +_2830: HS="THREE"; +_2840: IS=" "; +_2850: U=13; +_2860: return; +_2870: HS="TWO P"; +_2880: IS="AIR, "; +_2890: U=12; +_2900: return; +_2910: if (U>12) { goto _2960; } +_2920: U=16; +_2930: HS="FULL H"; +_2940: IS="OUSE, "; +_2950: return; +_2960: if (BB[Z]!=BB[Z-1]) { goto _3010; } +_2970: U=17; +_2980: HS="FOUR"; +_2990: IS=" "; +_3000: return; +_3010: U=16; +_3020: HS="FULL H"; +_3030: IS="OUSE, "; +_3040: return; + } + + bool Line_3050() + { +_3050: G=0; + return Line_3060(); + } + + bool Line_3060() + { +_3060: _io.WriteLine(); + _io.Write("WHAT IS YOUR BET"); +_3070: T = _io.ReadNumber(""); +_3080: if ((T-(int)T)==0) { goto _3140; } +_3090: if (K!=0) { goto _3120; } +_3100: if (G!=0) { goto _3120; } +_3110: if (T==.5) { return Line_3410(); } +_3120: _io.WriteLine("NO SMALL CHANGE, PLEASE."); +_3130: goto _3060; +_3140: if (S-G-T>=0) { goto _3170; } +_3150: if (Line_3830()) { return true; } +_3160: goto _3060; +_3170: if (T!=0) { goto _3200; } +_3180: I=3; +_3190: return Line_3380(); +_3200: if (G+T>=K) { goto _3230; } +_3210: _io.WriteLine("IF YOU CAN'T SEE MY BET, THEN FOLD."); +_3220: goto _3060; +_3230: G=G+T; +_3240: if (G==K) { return Line_3380(); } +_3250: if (Z!=1) { return Line_3420(); } +_3260: if (G>5) { goto _3300; } +_3270: if (Z>=2) { return Line_3350(); } +_3280: V=5; +_3290: return Line_3420(); +_3300: if (Z==1) { goto _3320; } +_3310: if (T<=25) { return Line_3350(); } +_3320: I=4; +_3330: _io.WriteLine("I FOLD."); +_3340: return false; + } + + bool Line_3350() + { +_3350: if (Z==2) { return Line_3430(); } + return Line_3360(); + } + + bool Line_3360() + { +_3360: _io.WriteLine("I'LL SEE YOU."); +_3370: K=G; + return Line_3380(); + } + + bool Line_3380() + { +_3380: S=S-G; +_3390: C=C-K; +_3400: P=P+G+K; + return Line_3410(); + } + + bool Line_3410() + { +_3410: return false; + } + + bool Line_3420() + { +_3420: if (G>3*Z) { return Line_3350(); } + return Line_3430(); + } + + bool Line_3430() + { +_3430: V=G-K+FNA(); +_3440: if (Line_3480()) { return true; } +_3450: _io.WriteLine($"I'LL SEE YOU, AND RAISE YOU{V}"); +_3460: K=G+V; +_3470: return Line_3060(); + } + + bool Line_3480() + { +_3480: if (C-G-V>=0) { goto _3660; } +_3490: if (G!=0) { goto _3520; } +_3500: V=C; +_3510: return false; +_3520: if (C-G>=0) { return Line_3360(); } +_3530: if (O % 2 != 0) { goto _3600; } +_3540: _io.Write("WOULD YOU LIKE TO BUY BACK YOUR WATCH FOR $50"); +_3550: JS = _io.ReadString(""); +_3560: if (JS[0]=='N') { goto _3600; } +_3570: C=C+50; +_3580: O=O/2; +_3590: return false; +_3600: if (O % 3!= 0) { return Line_3670(); } +_3610: _io.Write("WOULD YOU LIKE TO BUY BACK YOUR TIE TACK FOR $50"); +_3620: JS = _io.ReadString(""); +_3630: if (JS[0]=='N') { return Line_3670(); } +_3640: C=C+50; +_3650: O=O/3; +_3660: return false; + } + + bool Line_3670() + { +_3670: _io.WriteLine("I'M BUSTED. CONGRATULATIONS!"); +_3680: return true; // STOP + } + + void Line_3690() + { +_3690: _io.Write($"{HS}{IS}"); +_3700: if (HS!="A FLUS") { goto _3750; } +_3710: K=K/100; +_3720: Line_2080(); +_3730: _io.WriteLine(); +_3740: return; +_3750: K=FNB(K); +_3760: Line_1960(); +_3770: if (HS=="SCHMAL") { goto _3790; } +_3780: if (HS!="STRAIG") { goto _3810; } +_3790: _io.WriteLine(" HIGH"); +_3800: return; +_3810: _io.WriteLine("'S"); +_3820: return; + } + + bool Line_3830() + { +_3830: _io.WriteLine(); +_3840: _io.WriteLine("YOU CAN'T BET WITH WHAT YOU HAVEN'T GOT."); +_3850: if (O/2 == (int)(O/2)) { goto _3970; } +_3860: _io.Write("WOULD YOU LIKE TO SELL YOUR WATCH"); +_3870: JS = _io.ReadString(""); +_3880: if (JS[0]=='N') { goto _3970; } +_3890: if (FNA()>=7) { goto _3930; } +_3900: _io.WriteLine("I'LL GIVE YOU $75 FOR IT."); +_3910: S=S+75; +_3920: goto _3950; +_3930: _io.WriteLine("THAT'S A PRETTY CRUMMY WATCH - I'LL GIVE YOU $25."); +_3940: S=S+25; +_3950: O=O*2; +_3960: return false; +_3970: if (O/3 != (int)(O/3)) { goto _4090; } +_3980: _io.WriteLine("WILL YOU PART WITH THAT DIAMOND TIE TACK"); +_3990: JS = _io.ReadString(""); +_4000: if (JS[0]=='N') { goto _4080; } +_4010: if (FNA()>=6) { goto _4050; } +_4020: _io.WriteLine("YOU ARE NOW $100 RICHER."); +_4030: S=S+100; +_4040: goto _4070; +_4050: _io.WriteLine("IT'S PASTE. $25."); +_4060: S=S+25; +_4070: O=O*3; +_4080: return false; +_4090: _io.WriteLine("YOUR WAD IS SHOT. SO LONG, SUCKER!"); +_4100: return true; + } } } \ No newline at end of file From 91b3513df6d5821ef00a148295b43e025a3a5d46 Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Wed, 27 Apr 2022 08:05:27 +1000 Subject: [PATCH 03/29] Make text mixed case --- 71_Poker/csharp/Games.cs | 151 ++++++++++++++++++++------------------- 1 file changed, 76 insertions(+), 75 deletions(-) diff --git a/71_Poker/csharp/Games.cs b/71_Poker/csharp/Games.cs index 0a6dcbe8..d6cb862a 100644 --- a/71_Poker/csharp/Games.cs +++ b/71_Poker/csharp/Games.cs @@ -1,4 +1,5 @@ using Poker.Resources; +using static System.StringComparison; internal class Game { @@ -74,7 +75,7 @@ _110: S=200; _120: P=0; _140: _io.WriteLine(); _150: if (C<=5) { Line_3670(); return false; } -_160: _io.WriteLine("THE ANTE IS $5. I WILL DEAL:"); +_160: _io.WriteLine("The ante is $5. I will deal:"); _170: _io.WriteLine(); _180: if (S>5) { goto _200; } _190: if (Line_3830()) { return false; } @@ -85,7 +86,7 @@ _230: for (Z=1; Z <= 10; Z++) { _240: Line_1740(); } -_260: _io.WriteLine("YOUR HAND:"); +_260: _io.WriteLine("Your hand:"); _270: N=1; _280: Line_1850(); _290: N=6; @@ -111,7 +112,7 @@ _480: if (FNA()>=2) { goto _500; } _490: goto _420; _500: Z=0; _510: K=0; -_520: _io.WriteLine("I CHECK."); +_520: _io.WriteLine("I check."); _530: goto _620; _540: if (U<=16) { goto _570; } _550: Z=2; @@ -119,7 +120,7 @@ _560: if (FNA()>=1) { goto _580; } _570: Z=35; _580: V=Z+FNA(); _590: if (Line_3480()) { return false; } -_600: _io.WriteLine($"I'LL OPEN WITH ${V}"); +_600: _io.WriteLine($"I'll open with ${V}"); _610: K=V; _620: if (Line_3050()) { return false; } _630: var response = Line_650(); @@ -135,19 +136,19 @@ _660: _io.WriteLine(); bool? Line_670() { -_670: _io.WriteLine("I WIN."); +_670: _io.WriteLine("I win."); _680: C=C+P; return Line_690(); } bool? Line_690() { -_690: _io.WriteLine($"NOW I HAVE ${C}AND YOU HAVE ${S}"); -_700: _io.Write("DO YOU WISH TO CONTINUE"); +_690: _io.WriteLine($"Now I have ${C}and you have ${S}"); +_700: _io.Write("Do you wish to continue"); _710: HS = _io.ReadString(""); -_720: if (HS=="YES") { return true; } -_730: if (HS=="NO") { return false; } -_740: _io.WriteLine("ANSWER YES OR NO, PLEASE."); +_720: if (HS.Equals("YES", InvariantCultureIgnoreCase)) { return true; } +_730: if (HS.Equals("NO", InvariantCultureIgnoreCase)) { return false; } +_740: _io.WriteLine("Answer Yes or No, please."); _750: goto _700; } @@ -160,7 +161,7 @@ _770: _io.WriteLine(); bool? Line_780() { -_780: _io.WriteLine("YOU WIN."); +_780: _io.WriteLine("You win."); _790: S=S+P; _800: return Line_690(); } @@ -171,20 +172,20 @@ _810: return null; } _820: _io.WriteLine(); -_830: _io.Write("NOW WE DRAW -- HOW MANY CARDS DO YOU WANT"); +_830: _io.Write("Now we draw -- How many cards do you want"); _840: T = _io.ReadNumber(""); _850: if (T==0) { goto _980; } _860: Z=10; _870: if (T<4) { goto _900; } -_880: _io.WriteLine("YOU CAN'T DRAW MORE THAN THREE CARDS."); +_880: _io.WriteLine("You can't draw more than three cards."); _890: goto _840; -_900: _io.WriteLine("WHAT ARE THEIR NUMBERS:"); +_900: _io.WriteLine("What are their numbers:"); _910: for (Q=1; Q <= T; Q++) { _920: U = _io.ReadNumber(""); _930: Line_1730(); } -_950: _io.WriteLine("YOUR NEW HAND:"); +_950: _io.WriteLine("Your new hand:"); _960: N=1; _970: Line_1850(); _980: Z=10+T; @@ -195,9 +196,9 @@ _1010: Line_1730(); _1020: ; } _1030: _io.WriteLine(); -_1040: _io.Write($"I AM TAKING{Z-10-T}CARD"); +_1040: _io.Write($"I am taking{Z-10-T}card"); _1050: if (Z==11+T) { goto _1090; } -_1060: _io.WriteLine("S"); +_1060: _io.WriteLine("s"); _1070: _io.WriteLine(); _1080: goto _1100; _1090: _io.WriteLine(); @@ -229,40 +230,40 @@ _1340: if (Line_3050()) { return false; } _1350: if (T!=.5) { goto _1450; } _1360: if (V==7) { goto _1400; } _1370: if (I!=6) { goto _1400; } -_1380: _io.WriteLine("I'LL CHECK"); +_1380: _io.WriteLine("I'll check"); _1390: goto _1460; _1400: V=Z+FNA(); _1410: if (Line_3480()) { return false; } -_1420: _io.WriteLine($"I'LL BET ${V}"); +_1420: _io.WriteLine($"I'll bet ${V}"); _1430: K=V; _1440: if (Line_3060()) { return false; } _1450: response = Line_650(); if (response.HasValue) { return response.Value; } _1460: _io.WriteLine(); -_1470: _io.WriteLine("NOW WE COMPARE HANDS:"); +_1470: _io.WriteLine("Now we compare hands:"); _1480: JS=HS; _1490: KS=IS; -_1500: _io.WriteLine("MY HAND:"); +_1500: _io.WriteLine("My hand:"); _1510: N=6; _1520: Line_1850(); _1530: N=1; _1540: Line_2170(); _1550: _io.WriteLine(); -_1560: _io.Write("YOU HAVE "); +_1560: _io.Write("You have "); _1570: K=D; _1580: Line_3690(); _1590: HS=JS; _1600: IS=KS; _1610: K=M; -_1620: _io.Write("AND I HAVE "); +_1620: _io.Write("and I have "); _1630: Line_3690(); _1640: if (B>U) { return Line_670().Value; } _1650: if (U>B) { return Line_780().Value; } -_1660: if (HS=="A FLUS") { goto _1700; } +_1660: if (HS=="A Flus") { goto _1700; } _1662: if (FNB(M)FNB(D)) { return Line_670().Value; } -_1670: _io.WriteLine("THE HAND IS DRAWN."); -_1680: _io.WriteLine($"ALL ${P}REMAINS IN THE POT."); +_1670: _io.WriteLine("The hand is drawn."); +_1680: _io.WriteLine($"All ${P}remains in the pot."); _1690: goto _140; _1700: if (FNB(M)>FNB(D)) { return Line_670().Value; } _1710: if (FNB(D)>FNB(M)) { return Line_780().Value; } @@ -297,7 +298,7 @@ _1850: for (Z = N; Z <= N+4; Z++) { _1860: _io.Write($"{Z}-- "); _1870: Line_1950(); -_1880: _io.Write(" OF"); +_1880: _io.Write(" of"); _1890: Line_2070(); _1900: if (Z/2!=(int)(Z/2)) { goto _1920; } _1910: _io.WriteLine(); @@ -316,13 +317,13 @@ _1950: K=FNB(AA[Z]); void Line_1960() { _1960: if (K!=9) { goto _1980; } -_1970: _io.Write("JACK"); +_1970: _io.Write("Jack"); _1980: if (K!=10) { goto _2000; } -_1990: _io.Write("QUEEN"); +_1990: _io.Write("Queen"); _2000: if (K!=11) { goto _2020; } -_2010: _io.Write("KING"); +_2010: _io.Write("King"); _2020: if (K!=12) { goto _2040; } -_2030: _io.Write("ACE"); +_2030: _io.Write("Ace"); _2040: if (K>=9) { goto _2060; } _2050: _io.Write(K+2); _2060: return; @@ -337,13 +338,13 @@ _2070: K=(int)(AA[Z]/100); void Line_2080() { _2080: if (K!=0) { goto _2100; } -_2090: _io.Write(" CLUBS"); +_2090: _io.Write(" Clubs"); _2100: if (K!=1) { goto _2120; } -_2110: _io.Write(" DIAMONDS"); +_2110: _io.Write(" Diamonds"); _2120: if (K!=2) { goto _2140; } -_2130: _io.Write(" HEARTS"); +_2130: _io.Write(" Hearts"); _2140: if (K!=3) { goto _2160; } -_2150: _io.Write(" SPADES"); +_2150: _io.Write(" Spades"); _2160: return; } @@ -361,8 +362,8 @@ _2230: ; _2240: if (U!=4) { goto _2310; } _2250: X=11111; _2260: D=AA[N]; -_2270: HS="A FLUS"; -_2280: IS="H IN"; +_2270: HS="A Flus"; +_2280: IS="h in"; _2290: U=15; _2300: return; _2310: for (Z=N; Z <= N+3; Z++) @@ -394,8 +395,8 @@ _2510: U=10; _2520: if (BB[N+1]+3!=BB[N+4]) { goto _2620; } _2530: if (U!=10) { goto _2600; } _2540: U=14; -_2550: HS="STRAIG"; -_2560: IS="HT"; +_2550: HS="Straig"; +_2560: IS="ht"; _2570: X=11111; _2580: D=AA[N+4]; _2590: return; @@ -403,8 +404,8 @@ _2600: U=10; _2610: X=11110; _2620: if (U>=10) { goto _2690; } _2630: D=AA[N+4]; -_2640: HS="SCHMAL"; -_2650: IS="TZ, "; +_2640: HS="Schmal"; +_2650: IS="tz, "; _2660: U=9; _2670: X=11000; _2680: goto _2740; @@ -421,32 +422,32 @@ _2750: return; { _2760: if (U>=11) { goto _2810; } _2770: U=11; -_2780: HS="A PAIR"; +_2780: HS="A Pair"; _2790: IS=" OF "; _2800: return; _2810: if (U!=11) { goto _2910; } _2820: if (BB[Z]!=BB[Z-1]) { goto _2870; } -_2830: HS="THREE"; +_2830: HS="Three"; _2840: IS=" "; _2850: U=13; _2860: return; -_2870: HS="TWO P"; -_2880: IS="AIR, "; +_2870: HS="Two P"; +_2880: IS="air, "; _2890: U=12; _2900: return; _2910: if (U>12) { goto _2960; } _2920: U=16; -_2930: HS="FULL H"; -_2940: IS="OUSE, "; +_2930: HS="Full H"; +_2940: IS="ouse, "; _2950: return; _2960: if (BB[Z]!=BB[Z-1]) { goto _3010; } _2970: U=17; -_2980: HS="FOUR"; +_2980: HS="Four"; _2990: IS=" "; _3000: return; _3010: U=16; -_3020: HS="FULL H"; -_3030: IS="OUSE, "; +_3020: HS="Full H"; +_3030: IS="ouse, "; _3040: return; } @@ -459,13 +460,13 @@ _3050: G=0; bool Line_3060() { _3060: _io.WriteLine(); - _io.Write("WHAT IS YOUR BET"); + _io.Write("What is your bet"); _3070: T = _io.ReadNumber(""); _3080: if ((T-(int)T)==0) { goto _3140; } _3090: if (K!=0) { goto _3120; } _3100: if (G!=0) { goto _3120; } _3110: if (T==.5) { return Line_3410(); } -_3120: _io.WriteLine("NO SMALL CHANGE, PLEASE."); +_3120: _io.WriteLine("No small change, please."); _3130: goto _3060; _3140: if (S-G-T>=0) { goto _3170; } _3150: if (Line_3830()) { return true; } @@ -474,7 +475,7 @@ _3170: if (T!=0) { goto _3200; } _3180: I=3; _3190: return Line_3380(); _3200: if (G+T>=K) { goto _3230; } -_3210: _io.WriteLine("IF YOU CAN'T SEE MY BET, THEN FOLD."); +_3210: _io.WriteLine("If you can't see my bet, then fold."); _3220: goto _3060; _3230: G=G+T; _3240: if (G==K) { return Line_3380(); } @@ -486,7 +487,7 @@ _3290: return Line_3420(); _3300: if (Z==1) { goto _3320; } _3310: if (T<=25) { return Line_3350(); } _3320: I=4; -_3330: _io.WriteLine("I FOLD."); +_3330: _io.WriteLine("I fold."); _3340: return false; } @@ -498,7 +499,7 @@ _3350: if (Z==2) { return Line_3430(); } bool Line_3360() { -_3360: _io.WriteLine("I'LL SEE YOU."); +_3360: _io.WriteLine("I'll see you."); _3370: K=G; return Line_3380(); } @@ -526,7 +527,7 @@ _3420: if (G>3*Z) { return Line_3350(); } { _3430: V=G-K+FNA(); _3440: if (Line_3480()) { return true; } -_3450: _io.WriteLine($"I'LL SEE YOU, AND RAISE YOU{V}"); +_3450: _io.WriteLine($"I'll see you, and raise you{V}"); _3460: K=G+V; _3470: return Line_3060(); } @@ -539,16 +540,16 @@ _3500: V=C; _3510: return false; _3520: if (C-G>=0) { return Line_3360(); } _3530: if (O % 2 != 0) { goto _3600; } -_3540: _io.Write("WOULD YOU LIKE TO BUY BACK YOUR WATCH FOR $50"); +_3540: _io.Write("Would you like to buy back your watch for $50"); _3550: JS = _io.ReadString(""); -_3560: if (JS[0]=='N') { goto _3600; } +_3560: if (JS.StartsWith("N", InvariantCultureIgnoreCase)) { goto _3600; } _3570: C=C+50; _3580: O=O/2; _3590: return false; _3600: if (O % 3!= 0) { return Line_3670(); } -_3610: _io.Write("WOULD YOU LIKE TO BUY BACK YOUR TIE TACK FOR $50"); +_3610: _io.Write("Would you like to buy back your tie tack for $50"); _3620: JS = _io.ReadString(""); -_3630: if (JS[0]=='N') { return Line_3670(); } +_3630: if (JS.StartsWith("N", InvariantCultureIgnoreCase)) { return Line_3670(); } _3640: C=C+50; _3650: O=O/3; _3660: return false; @@ -556,7 +557,7 @@ _3660: return false; bool Line_3670() { -_3670: _io.WriteLine("I'M BUSTED. CONGRATULATIONS!"); +_3670: _io.WriteLine("I'm busted. Congratulations!"); _3680: return true; // STOP } @@ -570,43 +571,43 @@ _3730: _io.WriteLine(); _3740: return; _3750: K=FNB(K); _3760: Line_1960(); -_3770: if (HS=="SCHMAL") { goto _3790; } -_3780: if (HS!="STRAIG") { goto _3810; } -_3790: _io.WriteLine(" HIGH"); +_3770: if (HS=="Schmal") { goto _3790; } +_3780: if (HS!="Straig") { goto _3810; } +_3790: _io.WriteLine(" High"); _3800: return; -_3810: _io.WriteLine("'S"); +_3810: _io.WriteLine("'s"); _3820: return; } bool Line_3830() { _3830: _io.WriteLine(); -_3840: _io.WriteLine("YOU CAN'T BET WITH WHAT YOU HAVEN'T GOT."); +_3840: _io.WriteLine("You can't bet with what you haven't got."); _3850: if (O/2 == (int)(O/2)) { goto _3970; } -_3860: _io.Write("WOULD YOU LIKE TO SELL YOUR WATCH"); +_3860: _io.Write("Would you like to sell your watch"); _3870: JS = _io.ReadString(""); -_3880: if (JS[0]=='N') { goto _3970; } +_3880: if (JS.StartsWith("N", InvariantCultureIgnoreCase)) { goto _3970; } _3890: if (FNA()>=7) { goto _3930; } -_3900: _io.WriteLine("I'LL GIVE YOU $75 FOR IT."); +_3900: _io.WriteLine("I'll give you $75 for it."); _3910: S=S+75; _3920: goto _3950; -_3930: _io.WriteLine("THAT'S A PRETTY CRUMMY WATCH - I'LL GIVE YOU $25."); +_3930: _io.WriteLine("That's a pretty crummy watch - I'll give you $25."); _3940: S=S+25; _3950: O=O*2; _3960: return false; _3970: if (O/3 != (int)(O/3)) { goto _4090; } -_3980: _io.WriteLine("WILL YOU PART WITH THAT DIAMOND TIE TACK"); +_3980: _io.WriteLine("Will you part with that diamond tie tack"); _3990: JS = _io.ReadString(""); -_4000: if (JS[0]=='N') { goto _4080; } +_4000: if (JS.StartsWith("N", InvariantCultureIgnoreCase)) { goto _4080; } _4010: if (FNA()>=6) { goto _4050; } -_4020: _io.WriteLine("YOU ARE NOW $100 RICHER."); +_4020: _io.WriteLine("You are now $100 richer."); _4030: S=S+100; _4040: goto _4070; -_4050: _io.WriteLine("IT'S PASTE. $25."); +_4050: _io.WriteLine("It's paste. $25."); _4060: S=S+25; _4070: O=O*3; _4080: return false; -_4090: _io.WriteLine("YOUR WAD IS SHOT. SO LONG, SUCKER!"); +_4090: _io.WriteLine("Your wad is shot. So long, sucker!"); _4100: return true; } } From 85e7860aa13a6d747943d9ef6689f5960c750928 Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Thu, 28 Apr 2022 08:36:49 +1000 Subject: [PATCH 04/29] Simplify some functions --- 71_Poker/csharp/Games.cs | 243 ++++++++++++++++++--------------------- 1 file changed, 112 insertions(+), 131 deletions(-) diff --git a/71_Poker/csharp/Games.cs b/71_Poker/csharp/Games.cs index d6cb862a..a7d7ffcb 100644 --- a/71_Poker/csharp/Games.cs +++ b/71_Poker/csharp/Games.cs @@ -22,12 +22,12 @@ internal class Game } } - private readonly FloatArray AA = new(new float[51]); // 10 DIM A(50),B(15) + private readonly FloatArray _cards = new(new float[51]); // 10 DIM A(50),B(15) private readonly FloatArray BB = new(new float[16]); private float O = 1; // 90 = 120 - private float C = 200; - private float S = 200; - private float P = 0; + private float _computerBalance = 200; + private float _playerBalance = 200; + private float _pot = 0; private float B; private float M; @@ -35,7 +35,6 @@ internal class Game private float D; private float G; private float I; - private float N; private float U; private float Z; private float X; @@ -54,9 +53,9 @@ internal class Game _random = random; } - private float FNA() => (int)_random.NextFloat(10); // 20 DEF FNAA[X]=(int)(10*_random.NextFloat()) + private int Get0To9() => _random.Next(10); - private float FNB(float x) => x - 100 * (int)(x / 100); // 30 DEF FNB(X)=X-100*(int)(X/100) + private static int Mod100(float x) => (int)x % 100; internal void Play() { @@ -64,43 +63,41 @@ internal class Game _io.Write(Resource.Streams.Instructions); _90: O=1; -_100: C=200; -_110: S=200; +_100: _computerBalance=200; +_110: _playerBalance=200; while(PlayHand()); } internal bool PlayHand() { -_120: P=0; +_120: _pot=0; _140: _io.WriteLine(); -_150: if (C<=5) { Line_3670(); return false; } +_150: if (_computerBalance<=5) { Line_3670(); return false; } _160: _io.WriteLine("The ante is $5. I will deal:"); _170: _io.WriteLine(); -_180: if (S>5) { goto _200; } +_180: if (_playerBalance>5) { goto _200; } _190: if (Line_3830()) { return false; } -_200: P=P+10; -_210: S=S-5; -_220: C=C-5; +_200: _pot=_pot+10; +_210: _playerBalance=_playerBalance-5; +_220: _computerBalance=_computerBalance-5; _230: for (Z=1; Z <= 10; Z++) { _240: Line_1740(); } _260: _io.WriteLine("Your hand:"); -_270: N=1; -_280: Line_1850(); -_290: N=6; +_280: DisplayHand(1); _300: I=2; -_310: Line_2170(); +_310: AnalyzeHand(6); _320: _io.WriteLine(); _330: if (I!=6) { goto _470; } -_340: if (FNA()<=7) { goto _370; } +_340: if (Get0To9()<=7) { goto _370; } _350: X=11100; _360: goto _420; -_370: if (FNA()<=7) { goto _400; } +_370: if (Get0To9()<=7) { goto _400; } _380: X=11110; _390: goto _420; -_400: if (FNA()>=1) { goto _450; } +_400: if (Get0To9()>=1) { goto _450; } _410: X=11111; _420: I=7; _430: Z=23; @@ -108,7 +105,7 @@ _440: goto _580; _450: Z=1; _460: goto _510; _470: if (U>=13) { goto _540; } -_480: if (FNA()>=2) { goto _500; } +_480: if (Get0To9()>=2) { goto _500; } _490: goto _420; _500: Z=0; _510: K=0; @@ -116,9 +113,9 @@ _520: _io.WriteLine("I check."); _530: goto _620; _540: if (U<=16) { goto _570; } _550: Z=2; -_560: if (FNA()>=1) { goto _580; } +_560: if (Get0To9()>=1) { goto _580; } _570: Z=35; -_580: V=Z+FNA(); +_580: V=Z+Get0To9(); _590: if (Line_3480()) { return false; } _600: _io.WriteLine($"I'll open with ${V}"); _610: K=V; @@ -129,7 +126,12 @@ _640: goto _820; bool? Line_650() { -_650: if (I!=3) { return Line_760(); } +_650: if (I!=3) + { + if (I!=4) { return null; } + _io.WriteLine(); + return Line_780(); + } _660: _io.WriteLine(); return Line_670(); } @@ -137,13 +139,13 @@ _660: _io.WriteLine(); bool? Line_670() { _670: _io.WriteLine("I win."); -_680: C=C+P; +_680: _computerBalance=_computerBalance+_pot; return Line_690(); } bool? Line_690() { -_690: _io.WriteLine($"Now I have ${C}and you have ${S}"); +_690: _io.WriteLine($"Now I have ${_computerBalance}and you have ${_playerBalance}"); _700: _io.Write("Do you wish to continue"); _710: HS = _io.ReadString(""); _720: if (HS.Equals("YES", InvariantCultureIgnoreCase)) { return true; } @@ -152,25 +154,13 @@ _740: _io.WriteLine("Answer Yes or No, please."); _750: goto _700; } - bool? Line_760() - { -_760: if (I!=4) { return Line_810(); } -_770: _io.WriteLine(); - return Line_780(); - } - bool? Line_780() { _780: _io.WriteLine("You win."); -_790: S=S+P; +_790: _playerBalance=_playerBalance+_pot; _800: return Line_690(); } - bool? Line_810() - { -_810: return null; - } - _820: _io.WriteLine(); _830: _io.Write("Now we draw -- How many cards do you want"); _840: T = _io.ReadNumber(""); @@ -186,8 +176,7 @@ _920: U = _io.ReadNumber(""); _930: Line_1730(); } _950: _io.WriteLine("Your new hand:"); -_960: N=1; -_970: Line_1850(); +_970: DisplayHand(1); _980: Z=10+T; _990: for (U=6; U <= 10; U++) { @@ -202,10 +191,9 @@ _1060: _io.WriteLine("s"); _1070: _io.WriteLine(); _1080: goto _1100; _1090: _io.WriteLine(); -_1100: N=6; -_1110: V=I; +_1100: V=I; _1120: I=1; -_1130: Line_2170(); +_1130: AnalyzeHand(6); _1140: B=U; _1150: M=D; _1160: if (V!=7) { goto _1190; } @@ -216,12 +204,12 @@ _1200: Z=1; _1210: goto _1330; _1220: if (U>=13) { goto _1270; } _1230: Z=2; -_1240: if (FNA()!=6) { goto _1260; } +_1240: if (Get0To9()!=6) { goto _1260; } _1250: Z=19; _1260: goto _1330; _1270: if (U>=16) { goto _1320; } _1280: Z=19; -_1290: if (FNA()!=8) { goto _1310; } +_1290: if (Get0To9()!=8) { goto _1310; } _1300: Z=11; _1310: goto _1330; _1320: Z=2; @@ -232,7 +220,7 @@ _1360: if (V==7) { goto _1400; } _1370: if (I!=6) { goto _1400; } _1380: _io.WriteLine("I'll check"); _1390: goto _1460; -_1400: V=Z+FNA(); +_1400: V=Z+Get0To9(); _1410: if (Line_3480()) { return false; } _1420: _io.WriteLine($"I'll bet ${V}"); _1430: K=V; @@ -244,29 +232,27 @@ _1470: _io.WriteLine("Now we compare hands:"); _1480: JS=HS; _1490: KS=IS; _1500: _io.WriteLine("My hand:"); -_1510: N=6; -_1520: Line_1850(); -_1530: N=1; -_1540: Line_2170(); +_1520: DisplayHand(6); +_1540: AnalyzeHand(1); _1550: _io.WriteLine(); _1560: _io.Write("You have "); _1570: K=D; -_1580: Line_3690(); +_1580: DisplayHandRank(); _1590: HS=JS; _1600: IS=KS; _1610: K=M; _1620: _io.Write("and I have "); -_1630: Line_3690(); +_1630: DisplayHandRank(); _1640: if (B>U) { return Line_670().Value; } _1650: if (U>B) { return Line_780().Value; } _1660: if (HS=="A Flus") { goto _1700; } -_1662: if (FNB(M)FNB(D)) { return Line_670().Value; } +_1662: if (Mod100(M)Mod100(D)) { return Line_670().Value; } _1670: _io.WriteLine("The hand is drawn."); -_1680: _io.WriteLine($"All ${P}remains in the pot."); +_1680: _io.WriteLine($"All ${_pot}remains in the pot."); _1690: goto _140; -_1700: if (FNB(M)>FNB(D)) { return Line_670().Value; } -_1710: if (FNB(D)>FNB(M)) { return Line_780().Value; } +_1700: if (Mod100(M)>Mod100(D)) { return Line_670().Value; } +_1710: if (Mod100(D)>Mod100(M)) { return Line_780().Value; } _1720: goto _1670; void Line_1730() @@ -277,29 +263,27 @@ _1730: Z=Z+1; void Line_1740() { -_1740: AA[Z]=100*(int)(4*_random.NextFloat())+(int)(100*_random.NextFloat()); -_1750: if ((int)(AA[Z]/100)>3) { goto _1740; } -_1760: if (AA[Z]-100*(int)(AA[Z]/100)>12) { goto _1740; } +_1740: _cards[Z]=100*(int)(4*_random.NextFloat())+(int)(100*_random.NextFloat()); +_1750: if ((int)(_cards[Z]/100)>3) { goto _1740; } +_1760: if (_cards[Z]-100*(int)(_cards[Z]/100)>12) { goto _1740; } _1765: if (Z==1) { goto _1840; } _1770: for (K=1; K <= Z-1; K++) { -_1780: if (AA[Z]==AA[K]) { goto _1740; } +_1780: if (_cards[Z]==_cards[K]) { goto _1740; } } _1800: if (Z<=10) { goto _1840; } -_1810: N=AA[U]; -_1820: AA[U]=AA[Z]; -_1830: AA[Z]=N; + (_cards[U], _cards[Z]) = (_cards[Z], _cards[U]); _1840: return; } - void Line_1850() + void DisplayHand(int firstCard) { -_1850: for (Z = N; Z <= N+4; Z++) +_1850: for (Z = firstCard; Z <= firstCard+4; Z++) { _1860: _io.Write($"{Z}-- "); -_1870: Line_1950(); +_1870: DisplayRank(Z); _1880: _io.Write(" of"); -_1890: Line_2070(); +_1890: DisplaySuit(Z); _1900: if (Z/2!=(int)(Z/2)) { goto _1920; } _1910: _io.WriteLine(); _1920: ; @@ -308,102 +292,100 @@ _1930: _io.WriteLine(); _1940: return; } - void Line_1950() + void DisplayRank(float cardNumber) { -_1950: K=FNB(AA[Z]); - Line_1960(); + Line_1960(Mod100(_cards[cardNumber])); } - void Line_1960() + void Line_1960(int rank) { -_1960: if (K!=9) { goto _1980; } +_1960: if (rank!=9) { goto _1980; } _1970: _io.Write("Jack"); -_1980: if (K!=10) { goto _2000; } +_1980: if (rank!=10) { goto _2000; } _1990: _io.Write("Queen"); -_2000: if (K!=11) { goto _2020; } +_2000: if (rank!=11) { goto _2020; } _2010: _io.Write("King"); -_2020: if (K!=12) { goto _2040; } +_2020: if (rank!=12) { goto _2040; } _2030: _io.Write("Ace"); -_2040: if (K>=9) { goto _2060; } -_2050: _io.Write(K+2); +_2040: if (rank>=9) { goto _2060; } +_2050: _io.Write(rank+2); _2060: return; } - void Line_2070() + void DisplaySuit(float cardNumber) { -_2070: K=(int)(AA[Z]/100); - Line_2080(); + Line_2080((int)(_cards[cardNumber]/100)); } - void Line_2080() + void Line_2080(int suitNumber) { -_2080: if (K!=0) { goto _2100; } +_2080: if (suitNumber!=0) { goto _2100; } _2090: _io.Write(" Clubs"); -_2100: if (K!=1) { goto _2120; } +_2100: if (suitNumber!=1) { goto _2120; } _2110: _io.Write(" Diamonds"); -_2120: if (K!=2) { goto _2140; } +_2120: if (suitNumber!=2) { goto _2140; } _2130: _io.Write(" Hearts"); -_2140: if (K!=3) { goto _2160; } +_2140: if (suitNumber!=3) { goto _2160; } _2150: _io.Write(" Spades"); _2160: return; } - void Line_2170() + void AnalyzeHand(int firstCard) { _2170: U=0; -_2180: for (Z=N; Z <= N+4; Z++) +_2180: for (Z=firstCard; Z <= firstCard+4; Z++) { -_2190: BB[Z]=FNB(AA[Z]); -_2200: if (Z==N+4) { goto _2230; } -_2210: if ((int)(AA[Z]/100)!=(int)(AA[Z+1]/100)) { goto _2230; } +_2190: BB[Z]=Mod100(_cards[Z]); +_2200: if (Z==firstCard+4) { goto _2230; } +_2210: if ((int)(_cards[Z]/100)!=(int)(_cards[Z+1]/100)) { goto _2230; } _2220: U=U+1; _2230: ; } _2240: if (U!=4) { goto _2310; } _2250: X=11111; -_2260: D=AA[N]; +_2260: D=_cards[firstCard]; _2270: HS="A Flus"; _2280: IS="h in"; _2290: U=15; _2300: return; -_2310: for (Z=N; Z <= N+3; Z++) +_2310: for (Z=firstCard; Z <= firstCard+3; Z++) { -_2320: for (K=Z+1; K <= N+4; K++) +_2320: for (K=Z+1; K <= firstCard+4; K++) { _2330: if (BB[Z]<=BB[K]) { goto _2390; } -_2340: X=AA[Z]; -_2350: AA[Z]=AA[K]; +_2340: X=_cards[Z]; +_2350: _cards[Z]=_cards[K]; _2360: BB[Z]=BB[K]; -_2370: AA[K]=X; -_2380: BB[K]=AA[K]-100*(int)(AA[K]/100); +_2370: _cards[K]=X; +_2380: BB[K]=_cards[K]-100*(int)(_cards[K]/100); _2390: ; } } _2410: X=0; -_2420: for (Z=N; Z <= N+3; Z++) +_2420: for (Z=firstCard; Z <= firstCard+3; Z++) { _2430: if (BB[Z]!=BB[Z+1]) { goto _2470; } -_2440: X=X+11*(float)Math.Pow(10, Z-N); -_2450: D=AA[Z]; +_2440: X=X+11*(float)Math.Pow(10, Z-firstCard); +_2450: D=_cards[Z]; _2460: Line_2760(); _2470: ; } _2480: if (X!=0) { goto _2620; } -_2490: if (BB[N]+3!=BB[N+3]) { goto _2520; } +_2490: if (BB[firstCard]+3!=BB[firstCard+3]) { goto _2520; } _2500: X=1111; _2510: U=10; -_2520: if (BB[N+1]+3!=BB[N+4]) { goto _2620; } +_2520: if (BB[firstCard+1]+3!=BB[firstCard+4]) { goto _2620; } _2530: if (U!=10) { goto _2600; } _2540: U=14; _2550: HS="Straig"; _2560: IS="ht"; _2570: X=11111; -_2580: D=AA[N+4]; +_2580: D=_cards[firstCard+4]; _2590: return; _2600: U=10; _2610: X=11110; _2620: if (U>=10) { goto _2690; } -_2630: D=AA[N+4]; +_2630: D=_cards[firstCard+4]; _2640: HS="Schmal"; _2650: IS="tz, "; _2660: U=9; @@ -413,7 +395,7 @@ _2690: if (U!=10) { goto _2720; } _2700: if (I==1) { goto _2740; } _2710: goto _2750; _2720: if (U>12) { goto _2750; } -_2730: if (FNB(D)>6) { goto _2750; } +_2730: if (Mod100(D)>6) { goto _2750; } _2740: I=6; _2750: return; } @@ -423,7 +405,7 @@ _2750: return; _2760: if (U>=11) { goto _2810; } _2770: U=11; _2780: HS="A Pair"; -_2790: IS=" OF "; +_2790: IS=" of "; _2800: return; _2810: if (U!=11) { goto _2910; } _2820: if (BB[Z]!=BB[Z-1]) { goto _2870; } @@ -468,7 +450,7 @@ _3100: if (G!=0) { goto _3120; } _3110: if (T==.5) { return Line_3410(); } _3120: _io.WriteLine("No small change, please."); _3130: goto _3060; -_3140: if (S-G-T>=0) { goto _3170; } +_3140: if (_playerBalance-G-T>=0) { goto _3170; } _3150: if (Line_3830()) { return true; } _3160: goto _3060; _3170: if (T!=0) { goto _3200; } @@ -506,9 +488,9 @@ _3370: K=G; bool Line_3380() { -_3380: S=S-G; -_3390: C=C-K; -_3400: P=P+G+K; +_3380: _playerBalance=_playerBalance-G; +_3390: _computerBalance=_computerBalance-K; +_3400: _pot=_pot+G+K; return Line_3410(); } @@ -525,7 +507,7 @@ _3420: if (G>3*Z) { return Line_3350(); } bool Line_3430() { -_3430: V=G-K+FNA(); +_3430: V=G-K+Get0To9(); _3440: if (Line_3480()) { return true; } _3450: _io.WriteLine($"I'll see you, and raise you{V}"); _3460: K=G+V; @@ -534,23 +516,23 @@ _3470: return Line_3060(); bool Line_3480() { -_3480: if (C-G-V>=0) { goto _3660; } +_3480: if (_computerBalance-G-V>=0) { goto _3660; } _3490: if (G!=0) { goto _3520; } -_3500: V=C; +_3500: V=_computerBalance; _3510: return false; -_3520: if (C-G>=0) { return Line_3360(); } +_3520: if (_computerBalance-G>=0) { return Line_3360(); } _3530: if (O % 2 != 0) { goto _3600; } _3540: _io.Write("Would you like to buy back your watch for $50"); _3550: JS = _io.ReadString(""); _3560: if (JS.StartsWith("N", InvariantCultureIgnoreCase)) { goto _3600; } -_3570: C=C+50; +_3570: _computerBalance=_computerBalance+50; _3580: O=O/2; _3590: return false; _3600: if (O % 3!= 0) { return Line_3670(); } _3610: _io.Write("Would you like to buy back your tie tack for $50"); _3620: JS = _io.ReadString(""); _3630: if (JS.StartsWith("N", InvariantCultureIgnoreCase)) { return Line_3670(); } -_3640: C=C+50; +_3640: _computerBalance=_computerBalance+50; _3650: O=O/3; _3660: return false; } @@ -561,16 +543,15 @@ _3670: _io.WriteLine("I'm busted. Congratulations!"); _3680: return true; // STOP } - void Line_3690() + void DisplayHandRank() { _3690: _io.Write($"{HS}{IS}"); _3700: if (HS!="A FLUS") { goto _3750; } -_3710: K=K/100; -_3720: Line_2080(); +_3710: ; +_3720: Line_2080((int)(K/=100)); _3730: _io.WriteLine(); _3740: return; -_3750: K=FNB(K); -_3760: Line_1960(); +_3750: Line_1960((int)(K=Mod100(K))); _3770: if (HS=="Schmal") { goto _3790; } _3780: if (HS!="Straig") { goto _3810; } _3790: _io.WriteLine(" High"); @@ -587,24 +568,24 @@ _3850: if (O/2 == (int)(O/2)) { goto _3970; } _3860: _io.Write("Would you like to sell your watch"); _3870: JS = _io.ReadString(""); _3880: if (JS.StartsWith("N", InvariantCultureIgnoreCase)) { goto _3970; } -_3890: if (FNA()>=7) { goto _3930; } +_3890: if (Get0To9()>=7) { goto _3930; } _3900: _io.WriteLine("I'll give you $75 for it."); -_3910: S=S+75; +_3910: _playerBalance=_playerBalance+75; _3920: goto _3950; _3930: _io.WriteLine("That's a pretty crummy watch - I'll give you $25."); -_3940: S=S+25; +_3940: _playerBalance=_playerBalance+25; _3950: O=O*2; _3960: return false; _3970: if (O/3 != (int)(O/3)) { goto _4090; } _3980: _io.WriteLine("Will you part with that diamond tie tack"); _3990: JS = _io.ReadString(""); _4000: if (JS.StartsWith("N", InvariantCultureIgnoreCase)) { goto _4080; } -_4010: if (FNA()>=6) { goto _4050; } +_4010: if (Get0To9()>=6) { goto _4050; } _4020: _io.WriteLine("You are now $100 richer."); -_4030: S=S+100; +_4030: _playerBalance=_playerBalance+100; _4040: goto _4070; _4050: _io.WriteLine("It's paste. $25."); -_4060: S=S+25; +_4060: _playerBalance=_playerBalance+25; _4070: O=O*3; _4080: return false; _4090: _io.WriteLine("Your wad is shot. So long, sucker!"); From 577698e2a294978a80be84b3eff6e4694794c1dd Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Mon, 2 May 2022 08:34:56 +1000 Subject: [PATCH 05/29] Simplify expressions and function calls --- 71_Poker/csharp/Games.cs | 170 +++++++++++++++++---------------------- 1 file changed, 73 insertions(+), 97 deletions(-) diff --git a/71_Poker/csharp/Games.cs b/71_Poker/csharp/Games.cs index a7d7ffcb..3a81cb69 100644 --- a/71_Poker/csharp/Games.cs +++ b/71_Poker/csharp/Games.cs @@ -23,7 +23,7 @@ internal class Game } private readonly FloatArray _cards = new(new float[51]); // 10 DIM A(50),B(15) - private readonly FloatArray BB = new(new float[16]); + private readonly FloatArray _cardRanks = new(new float[16]); private float O = 1; // 90 = 120 private float _computerBalance = 200; private float _playerBalance = 200; @@ -55,7 +55,9 @@ internal class Game private int Get0To9() => _random.Next(10); - private static int Mod100(float x) => (int)x % 100; + private static int GetRank(float x) => (int)x % 100; + + private static int GetSuit(float x) => (int)x / 100; internal void Play() { @@ -78,12 +80,12 @@ _160: _io.WriteLine("The ante is $5. I will deal:"); _170: _io.WriteLine(); _180: if (_playerBalance>5) { goto _200; } _190: if (Line_3830()) { return false; } -_200: _pot=_pot+10; -_210: _playerBalance=_playerBalance-5; -_220: _computerBalance=_computerBalance-5; +_200: _pot += 10; +_210: _playerBalance -= 5; +_220: _computerBalance -= 5; _230: for (Z=1; Z <= 10; Z++) { -_240: Line_1740(); +_240: DealCard((int)Z); } _260: _io.WriteLine("Your hand:"); _280: DisplayHand(1); @@ -119,7 +121,8 @@ _580: V=Z+Get0To9(); _590: if (Line_3480()) { return false; } _600: _io.WriteLine($"I'll open with ${V}"); _610: K=V; -_620: if (Line_3050()) { return false; } + G = 0; +_620: if (GetWager()) { return false; } _630: var response = Line_650(); if (response.HasValue) { return response.Value; } _640: goto _820; @@ -146,8 +149,7 @@ _680: _computerBalance=_computerBalance+_pot; bool? Line_690() { _690: _io.WriteLine($"Now I have ${_computerBalance}and you have ${_playerBalance}"); -_700: _io.Write("Do you wish to continue"); -_710: HS = _io.ReadString(""); +_700: HS = _io.ReadString("Do you wish to continue"); _720: if (HS.Equals("YES", InvariantCultureIgnoreCase)) { return true; } _730: if (HS.Equals("NO", InvariantCultureIgnoreCase)) { return false; } _740: _io.WriteLine("Answer Yes or No, please."); @@ -173,7 +175,7 @@ _900: _io.WriteLine("What are their numbers:"); _910: for (Q=1; Q <= T; Q++) { _920: U = _io.ReadNumber(""); -_930: Line_1730(); +_930: DealCard((int)++Z, (int)U); } _950: _io.WriteLine("Your new hand:"); _970: DisplayHand(1); @@ -181,7 +183,7 @@ _980: Z=10+T; _990: for (U=6; U <= 10; U++) { _1000: if ((int)(X/Math.Pow(10, U-6))!=10*(int)(X/Math.Pow(10, U-5))) { goto _1020; } -_1010: Line_1730(); +_1010: DealCard((int)++Z, (int)U); _1020: ; } _1030: _io.WriteLine(); @@ -214,7 +216,8 @@ _1300: Z=11; _1310: goto _1330; _1320: Z=2; _1330: K=0; -_1340: if (Line_3050()) { return false; } + G=0; +_1340: if (GetWager()) { return false; } _1350: if (T!=.5) { goto _1450; } _1360: if (V==7) { goto _1400; } _1370: if (I!=6) { goto _1400; } @@ -224,7 +227,7 @@ _1400: V=Z+Get0To9(); _1410: if (Line_3480()) { return false; } _1420: _io.WriteLine($"I'll bet ${V}"); _1430: K=V; -_1440: if (Line_3060()) { return false; } +_1440: if (GetWager()) { return false; } _1450: response = Line_650(); if (response.HasValue) { return response.Value; } _1460: _io.WriteLine(); @@ -236,43 +239,33 @@ _1520: DisplayHand(6); _1540: AnalyzeHand(1); _1550: _io.WriteLine(); _1560: _io.Write("You have "); -_1570: K=D; -_1580: DisplayHandRank(); -_1590: HS=JS; -_1600: IS=KS; -_1610: K=M; +_1580: DisplayHandRank(HS, IS, (int)D); _1620: _io.Write("and I have "); -_1630: DisplayHandRank(); +_1630: DisplayHandRank(JS, KS, (int)M); _1640: if (B>U) { return Line_670().Value; } _1650: if (U>B) { return Line_780().Value; } _1660: if (HS=="A Flus") { goto _1700; } -_1662: if (Mod100(M)Mod100(D)) { return Line_670().Value; } +_1662: if (GetRank(M)GetRank(D)) { return Line_670().Value; } _1670: _io.WriteLine("The hand is drawn."); _1680: _io.WriteLine($"All ${_pot}remains in the pot."); _1690: goto _140; -_1700: if (Mod100(M)>Mod100(D)) { return Line_670().Value; } -_1710: if (Mod100(D)>Mod100(M)) { return Line_780().Value; } +_1700: if (GetRank(M)>GetRank(D)) { return Line_670().Value; } +_1710: if (GetRank(D)>GetRank(M)) { return Line_780().Value; } _1720: goto _1670; - void Line_1730() + void DealCard(int index, int indexToReplace = 0) { -_1730: Z=Z+1; - Line_1740(); - } - - void Line_1740() - { -_1740: _cards[Z]=100*(int)(4*_random.NextFloat())+(int)(100*_random.NextFloat()); -_1750: if ((int)(_cards[Z]/100)>3) { goto _1740; } -_1760: if (_cards[Z]-100*(int)(_cards[Z]/100)>12) { goto _1740; } -_1765: if (Z==1) { goto _1840; } -_1770: for (K=1; K <= Z-1; K++) +_1740: _cards[index]=100*_random.Next(4) + _random.Next(100); +_1750: if ((int)_cards[index] / 100 > 3) { goto _1740; } +_1760: if (_cards[index] % 100 > 12) { goto _1740; } +_1765: if (index==1) { goto _1840; } +_1770: for (K=1; K <= index-1; K++) { -_1780: if (_cards[Z]==_cards[K]) { goto _1740; } +_1780: if (_cards[index]==_cards[K]) { goto _1740; } } -_1800: if (Z<=10) { goto _1840; } - (_cards[U], _cards[Z]) = (_cards[Z], _cards[U]); +_1800: if (index<=10) { goto _1840; } + (_cards[indexToReplace], _cards[index]) = (_cards[index], _cards[indexToReplace]); _1840: return; } @@ -280,11 +273,12 @@ _1840: return; { _1850: for (Z = firstCard; Z <= firstCard+4; Z++) { + var card = _cards[Z]; _1860: _io.Write($"{Z}-- "); -_1870: DisplayRank(Z); +_1870: DisplayRank(GetRank(card)); _1880: _io.Write(" of"); -_1890: DisplaySuit(Z); -_1900: if (Z/2!=(int)(Z/2)) { goto _1920; } +_1890: DisplaySuit(GetSuit(card)); +_1900: if (Z % 2 != 0) { goto _1920; } _1910: _io.WriteLine(); _1920: ; } @@ -292,12 +286,7 @@ _1930: _io.WriteLine(); _1940: return; } - void DisplayRank(float cardNumber) - { - Line_1960(Mod100(_cards[cardNumber])); - } - - void Line_1960(int rank) + void DisplayRank(int rank) { _1960: if (rank!=9) { goto _1980; } _1970: _io.Write("Jack"); @@ -312,12 +301,7 @@ _2050: _io.Write(rank+2); _2060: return; } - void DisplaySuit(float cardNumber) - { - Line_2080((int)(_cards[cardNumber]/100)); - } - - void Line_2080(int suitNumber) + void DisplaySuit(int suitNumber) { _2080: if (suitNumber!=0) { goto _2100; } _2090: _io.Write(" Clubs"); @@ -335,10 +319,10 @@ _2160: return; _2170: U=0; _2180: for (Z=firstCard; Z <= firstCard+4; Z++) { -_2190: BB[Z]=Mod100(_cards[Z]); +_2190: _cardRanks[Z]=GetRank(_cards[Z]); _2200: if (Z==firstCard+4) { goto _2230; } -_2210: if ((int)(_cards[Z]/100)!=(int)(_cards[Z+1]/100)) { goto _2230; } -_2220: U=U+1; +_2210: if (GetSuit(_cards[Z]) != GetSuit(_cards[Z+1])) { goto _2230; } +_2220: U++; _2230: ; } _2240: if (U!=4) { goto _2310; } @@ -352,29 +336,29 @@ _2310: for (Z=firstCard; Z <= firstCard+3; Z++) { _2320: for (K=Z+1; K <= firstCard+4; K++) { -_2330: if (BB[Z]<=BB[K]) { goto _2390; } +_2330: if (_cardRanks[Z]<=_cardRanks[K]) { goto _2390; } _2340: X=_cards[Z]; _2350: _cards[Z]=_cards[K]; -_2360: BB[Z]=BB[K]; +_2360: _cardRanks[Z]=_cardRanks[K]; _2370: _cards[K]=X; -_2380: BB[K]=_cards[K]-100*(int)(_cards[K]/100); +_2380: _cardRanks[K]=GetRank(_cards[K]); _2390: ; } } _2410: X=0; _2420: for (Z=firstCard; Z <= firstCard+3; Z++) { -_2430: if (BB[Z]!=BB[Z+1]) { goto _2470; } -_2440: X=X+11*(float)Math.Pow(10, Z-firstCard); +_2430: if (_cardRanks[Z]!=_cardRanks[Z+1]) { goto _2470; } +_2440: X += 11*(float)Math.Pow(10, Z-firstCard); _2450: D=_cards[Z]; -_2460: Line_2760(); +_2460: AnalyzeMultiples(); _2470: ; } _2480: if (X!=0) { goto _2620; } -_2490: if (BB[firstCard]+3!=BB[firstCard+3]) { goto _2520; } +_2490: if (_cardRanks[firstCard]+3!=_cardRanks[firstCard+3]) { goto _2520; } _2500: X=1111; _2510: U=10; -_2520: if (BB[firstCard+1]+3!=BB[firstCard+4]) { goto _2620; } +_2520: if (_cardRanks[firstCard+1]+3!=_cardRanks[firstCard+4]) { goto _2620; } _2530: if (U!=10) { goto _2600; } _2540: U=14; _2550: HS="Straig"; @@ -395,12 +379,12 @@ _2690: if (U!=10) { goto _2720; } _2700: if (I==1) { goto _2740; } _2710: goto _2750; _2720: if (U>12) { goto _2750; } -_2730: if (Mod100(D)>6) { goto _2750; } +_2730: if (GetRank(D)>6) { goto _2750; } _2740: I=6; _2750: return; } - void Line_2760() + void AnalyzeMultiples() { _2760: if (U>=11) { goto _2810; } _2770: U=11; @@ -408,7 +392,7 @@ _2780: HS="A Pair"; _2790: IS=" of "; _2800: return; _2810: if (U!=11) { goto _2910; } -_2820: if (BB[Z]!=BB[Z-1]) { goto _2870; } +_2820: if (_cardRanks[Z]!=_cardRanks[Z-1]) { goto _2870; } _2830: HS="Three"; _2840: IS=" "; _2850: U=13; @@ -422,7 +406,7 @@ _2920: U=16; _2930: HS="Full H"; _2940: IS="ouse, "; _2950: return; -_2960: if (BB[Z]!=BB[Z-1]) { goto _3010; } +_2960: if (_cardRanks[Z]!=_cardRanks[Z-1]) { goto _3010; } _2970: U=17; _2980: HS="Four"; _2990: IS=" "; @@ -436,18 +420,17 @@ _3040: return; bool Line_3050() { _3050: G=0; - return Line_3060(); + return GetWager(); } - bool Line_3060() + bool GetWager() { _3060: _io.WriteLine(); - _io.Write("What is your bet"); -_3070: T = _io.ReadNumber(""); + T = _io.ReadNumber("What is your bet"); _3080: if ((T-(int)T)==0) { goto _3140; } _3090: if (K!=0) { goto _3120; } _3100: if (G!=0) { goto _3120; } -_3110: if (T==.5) { return Line_3410(); } +_3110: if (T==.5) { return false; } _3120: _io.WriteLine("No small change, please."); _3130: goto _3060; _3140: if (_playerBalance-G-T>=0) { goto _3170; } @@ -459,7 +442,7 @@ _3190: return Line_3380(); _3200: if (G+T>=K) { goto _3230; } _3210: _io.WriteLine("If you can't see my bet, then fold."); _3220: goto _3060; -_3230: G=G+T; +_3230: G += T; _3240: if (G==K) { return Line_3380(); } _3250: if (Z!=1) { return Line_3420(); } _3260: if (G>5) { goto _3300; } @@ -488,15 +471,10 @@ _3370: K=G; bool Line_3380() { -_3380: _playerBalance=_playerBalance-G; -_3390: _computerBalance=_computerBalance-K; -_3400: _pot=_pot+G+K; - return Line_3410(); - } - - bool Line_3410() - { -_3410: return false; +_3380: _playerBalance -= G; +_3390: _computerBalance -= K; +_3400: _pot += G+K; + return false; } bool Line_3420() @@ -511,7 +489,7 @@ _3430: V=G-K+Get0To9(); _3440: if (Line_3480()) { return true; } _3450: _io.WriteLine($"I'll see you, and raise you{V}"); _3460: K=G+V; -_3470: return Line_3060(); +_3470: return GetWager(); } bool Line_3480() @@ -522,15 +500,13 @@ _3500: V=_computerBalance; _3510: return false; _3520: if (_computerBalance-G>=0) { return Line_3360(); } _3530: if (O % 2 != 0) { goto _3600; } -_3540: _io.Write("Would you like to buy back your watch for $50"); -_3550: JS = _io.ReadString(""); +_3540: JS = _io.ReadString("Would you like to buy back your watch for $50"); _3560: if (JS.StartsWith("N", InvariantCultureIgnoreCase)) { goto _3600; } _3570: _computerBalance=_computerBalance+50; _3580: O=O/2; _3590: return false; _3600: if (O % 3!= 0) { return Line_3670(); } -_3610: _io.Write("Would you like to buy back your tie tack for $50"); -_3620: JS = _io.ReadString(""); +_3610: JS = _io.ReadString("Would you like to buy back your tie tack for $50"); _3630: if (JS.StartsWith("N", InvariantCultureIgnoreCase)) { return Line_3670(); } _3640: _computerBalance=_computerBalance+50; _3650: O=O/3; @@ -543,17 +519,17 @@ _3670: _io.WriteLine("I'm busted. Congratulations!"); _3680: return true; // STOP } - void DisplayHandRank() + void DisplayHandRank(string part1, string part2, int highCard) { -_3690: _io.Write($"{HS}{IS}"); -_3700: if (HS!="A FLUS") { goto _3750; } +_3690: _io.Write($"{part1}{part2}"); +_3700: if (part1!="A FLUS") { goto _3750; } _3710: ; -_3720: Line_2080((int)(K/=100)); +_3720: DisplaySuit(highCard/100); _3730: _io.WriteLine(); _3740: return; -_3750: Line_1960((int)(K=Mod100(K))); -_3770: if (HS=="Schmal") { goto _3790; } -_3780: if (HS!="Straig") { goto _3810; } +_3750: DisplayRank(GetRank(highCard)); +_3770: if (part1=="Schmal") { goto _3790; } +_3780: if (part1!="Straig") { goto _3810; } _3790: _io.WriteLine(" High"); _3800: return; _3810: _io.WriteLine("'s"); @@ -564,7 +540,7 @@ _3820: return; { _3830: _io.WriteLine(); _3840: _io.WriteLine("You can't bet with what you haven't got."); -_3850: if (O/2 == (int)(O/2)) { goto _3970; } +_3850: if (O % 2 == 0) { goto _3970; } _3860: _io.Write("Would you like to sell your watch"); _3870: JS = _io.ReadString(""); _3880: if (JS.StartsWith("N", InvariantCultureIgnoreCase)) { goto _3970; } @@ -576,7 +552,7 @@ _3930: _io.WriteLine("That's a pretty crummy watch - I'll give you $25."); _3940: _playerBalance=_playerBalance+25; _3950: O=O*2; _3960: return false; -_3970: if (O/3 != (int)(O/3)) { goto _4090; } +_3970: if (O % 3 != 0) { goto _4090; } _3980: _io.WriteLine("Will you part with that diamond tie tack"); _3990: JS = _io.ReadString(""); _4000: if (JS.StartsWith("N", InvariantCultureIgnoreCase)) { goto _4080; } From 6ec5208a330d4ea90bb968885916528610ec4512 Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Wed, 4 May 2022 08:24:59 +1000 Subject: [PATCH 06/29] Simplify some branching and remove labels --- 71_Poker/csharp/Games.cs | 463 ++++++++++++++++++++------------------- 1 file changed, 240 insertions(+), 223 deletions(-) diff --git a/71_Poker/csharp/Games.cs b/71_Poker/csharp/Games.cs index 3a81cb69..a7c89c1b 100644 --- a/71_Poker/csharp/Games.cs +++ b/71_Poker/csharp/Games.cs @@ -64,255 +64,253 @@ internal class Game _io.Write(Resource.Streams.Title); _io.Write(Resource.Streams.Instructions); -_90: O=1; -_100: _computerBalance=200; -_110: _playerBalance=200; - + O=1; + _computerBalance=200; + _playerBalance=200; while(PlayHand()); } internal bool PlayHand() { -_120: _pot=0; -_140: _io.WriteLine(); -_150: if (_computerBalance<=5) { Line_3670(); return false; } -_160: _io.WriteLine("The ante is $5. I will deal:"); -_170: _io.WriteLine(); -_180: if (_playerBalance>5) { goto _200; } -_190: if (Line_3830()) { return false; } -_200: _pot += 10; -_210: _playerBalance -= 5; -_220: _computerBalance -= 5; -_230: for (Z=1; Z <= 10; Z++) + _pot=0; + while(true) { -_240: DealCard((int)Z); - } -_260: _io.WriteLine("Your hand:"); -_280: DisplayHand(1); -_300: I=2; -_310: AnalyzeHand(6); -_320: _io.WriteLine(); -_330: if (I!=6) { goto _470; } -_340: if (Get0To9()<=7) { goto _370; } -_350: X=11100; -_360: goto _420; -_370: if (Get0To9()<=7) { goto _400; } -_380: X=11110; -_390: goto _420; -_400: if (Get0To9()>=1) { goto _450; } -_410: X=11111; -_420: I=7; -_430: Z=23; -_440: goto _580; -_450: Z=1; -_460: goto _510; -_470: if (U>=13) { goto _540; } -_480: if (Get0To9()>=2) { goto _500; } -_490: goto _420; -_500: Z=0; -_510: K=0; -_520: _io.WriteLine("I check."); -_530: goto _620; -_540: if (U<=16) { goto _570; } -_550: Z=2; -_560: if (Get0To9()>=1) { goto _580; } -_570: Z=35; -_580: V=Z+Get0To9(); -_590: if (Line_3480()) { return false; } -_600: _io.WriteLine($"I'll open with ${V}"); -_610: K=V; - G = 0; -_620: if (GetWager()) { return false; } -_630: var response = Line_650(); - if (response.HasValue) { return response.Value; } -_640: goto _820; + _io.WriteLine(); + if (_computerBalance<=5) + { + CongratulatePlayer(); + return false; + } + _io.WriteLine("The ante is $5. I will deal:"); + _io.WriteLine(); + if (_playerBalance <= 5 && PlayerCantRaiseFunds()) { return false; } + _pot += 10; + _playerBalance -= 5; + _computerBalance -= 5; + for (Z=1; Z <= 10; Z++) + { + DealCard((int)Z); + } + _io.WriteLine("Your hand:"); + DisplayHand(1); + I=2; + AnalyzeHand(6); + _io.WriteLine(); +_330: if (I!=6) { goto _470; } +_340: if (Get0To9()<=7) { goto _370; } +_350: X=11100; +_360: goto _420; +_370: if (Get0To9()<=7) { goto _400; } +_380: X=11110; +_390: goto _420; +_400: if (Get0To9()>=1) { goto _450; } +_410: X=11111; +_420: I=7; +_430: Z=23; +_440: goto _580; +_450: Z=1; +_460: goto _510; +_470: if (U>=13) { goto _540; } +_480: if (Get0To9()>=2) { goto _500; } +_490: goto _420; +_500: Z=0; +_510: K=0; +_520: _io.WriteLine("I check."); +_530: goto _620; +_540: Z = U <= 16 || Get0To9() < 1 ? 35 : 2; +_580: V=Z+Get0To9(); +_590: if (Line_3480()) { return false; } +_600: _io.WriteLine($"I'll open with ${V}"); +_610: K=V; + G = 0; +_620: if (GetWager()) { return false; } +_630: var response = IsThereAWinner(); + if (response.HasValue) { return response.Value; } - bool? Line_650() + _io.WriteLine(); + T = _io.ReadNumber("Now we draw -- How many cards do you want", 3, "You can't draw more than three cards."); + if (T != 0) + { + Z=10; + _io.WriteLine("What are their numbers:"); + for (Q=1; Q <= T; Q++) + { + U = _io.ReadNumber(""); + DealCard((int)++Z, (int)U); + } + _io.WriteLine("Your new hand:"); + DisplayHand(1); + } + Z=10+T; + for (U=6; U <= 10; U++) + { + if ((int)(X/Math.Pow(10, U-6)) == 10*(int)(X/Math.Pow(10, U-5))) + { + DealCard((int)++Z, (int)U); + } + } + _io.WriteLine(); + _io.Write($"I am taking{Z-10-T}card"); + if (Z != 11 + T) + { + _io.WriteLine("s"); + } + _io.WriteLine(); + V=I; + I=1; + AnalyzeHand(6); + B=U; + M=D; + if (V == 7) + { + Z=28; + } + else if (I == 6) + { + Z=1; + } + else if (U < 13) + { + Z = Get0To9() == 6 ? 19 : 2; + } + else + { + if (U >= 16) + { + Z = 2; + } + else + { + Z = Get0To9()==8 ? 11 : 19; + } + } +_1330: K=0; + G=0; +_1340: if (GetWager()) { return false; } +_1350: if (T!=.5) { goto _1450; } +_1360: if (V==7) { goto _1400; } +_1370: if (I!=6) { goto _1400; } +_1380: _io.WriteLine("I'll check"); +_1390: goto _1460; +_1400: V=Z+Get0To9(); +_1410: if (Line_3480()) { return false; } +_1420: _io.WriteLine($"I'll bet ${V}"); +_1430: K=V; +_1440: if (GetWager()) { return false; } +_1450: response = IsThereAWinner(); + if (response.HasValue) { return response.Value; } +_1460: _io.WriteLine(); +_1470: _io.WriteLine("Now we compare hands:"); +_1480: JS=HS; +_1490: KS=IS; +_1500: _io.WriteLine("My hand:"); +_1520: DisplayHand(6); +_1540: AnalyzeHand(1); +_1550: _io.WriteLine(); +_1560: _io.Write("You have "); +_1580: DisplayHandRank(HS, IS, (int)D); +_1620: _io.Write("and I have "); +_1630: DisplayHandRank(JS, KS, (int)M); + if (B > U || GetRank(M) > GetRank(D)) { return ComputerWins().Value; } + if (U > B || GetRank(D) > GetRank(M)) { return PlayerWins().Value; } +_1670: _io.WriteLine("The hand is drawn."); +_1680: _io.WriteLine($"All ${_pot}remains in the pot."); + } + + bool? IsThereAWinner() { -_650: if (I!=3) + if (I!=3) { if (I!=4) { return null; } _io.WriteLine(); - return Line_780(); + return PlayerWins(); } -_660: _io.WriteLine(); - return Line_670(); + _io.WriteLine(); + return ComputerWins(); } - bool? Line_670() + bool? ComputerWins() { -_670: _io.WriteLine("I win."); -_680: _computerBalance=_computerBalance+_pot; - return Line_690(); + _io.WriteLine("I win."); + _computerBalance += _pot; + return ShouldContinue(); } - bool? Line_690() + bool? ShouldContinue() { -_690: _io.WriteLine($"Now I have ${_computerBalance}and you have ${_playerBalance}"); -_700: HS = _io.ReadString("Do you wish to continue"); -_720: if (HS.Equals("YES", InvariantCultureIgnoreCase)) { return true; } -_730: if (HS.Equals("NO", InvariantCultureIgnoreCase)) { return false; } -_740: _io.WriteLine("Answer Yes or No, please."); -_750: goto _700; + _io.WriteLine($"Now I have ${_computerBalance}and you have ${_playerBalance}"); + return _io.ReadYesNo("Do you wish to continue"); } - bool? Line_780() + bool? PlayerWins() { -_780: _io.WriteLine("You win."); -_790: _playerBalance=_playerBalance+_pot; -_800: return Line_690(); + _io.WriteLine("You win."); + _playerBalance += _pot; + return ShouldContinue(); } -_820: _io.WriteLine(); -_830: _io.Write("Now we draw -- How many cards do you want"); -_840: T = _io.ReadNumber(""); -_850: if (T==0) { goto _980; } -_860: Z=10; -_870: if (T<4) { goto _900; } -_880: _io.WriteLine("You can't draw more than three cards."); -_890: goto _840; -_900: _io.WriteLine("What are their numbers:"); -_910: for (Q=1; Q <= T; Q++) - { -_920: U = _io.ReadNumber(""); -_930: DealCard((int)++Z, (int)U); - } -_950: _io.WriteLine("Your new hand:"); -_970: DisplayHand(1); -_980: Z=10+T; -_990: for (U=6; U <= 10; U++) - { -_1000: if ((int)(X/Math.Pow(10, U-6))!=10*(int)(X/Math.Pow(10, U-5))) { goto _1020; } -_1010: DealCard((int)++Z, (int)U); -_1020: ; - } -_1030: _io.WriteLine(); -_1040: _io.Write($"I am taking{Z-10-T}card"); -_1050: if (Z==11+T) { goto _1090; } -_1060: _io.WriteLine("s"); -_1070: _io.WriteLine(); -_1080: goto _1100; -_1090: _io.WriteLine(); -_1100: V=I; -_1120: I=1; -_1130: AnalyzeHand(6); -_1140: B=U; -_1150: M=D; -_1160: if (V!=7) { goto _1190; } -_1170: Z=28; -_1180: goto _1330; -_1190: if (I!=6) { goto _1220; } -_1200: Z=1; -_1210: goto _1330; -_1220: if (U>=13) { goto _1270; } -_1230: Z=2; -_1240: if (Get0To9()!=6) { goto _1260; } -_1250: Z=19; -_1260: goto _1330; -_1270: if (U>=16) { goto _1320; } -_1280: Z=19; -_1290: if (Get0To9()!=8) { goto _1310; } -_1300: Z=11; -_1310: goto _1330; -_1320: Z=2; -_1330: K=0; - G=0; -_1340: if (GetWager()) { return false; } -_1350: if (T!=.5) { goto _1450; } -_1360: if (V==7) { goto _1400; } -_1370: if (I!=6) { goto _1400; } -_1380: _io.WriteLine("I'll check"); -_1390: goto _1460; -_1400: V=Z+Get0To9(); -_1410: if (Line_3480()) { return false; } -_1420: _io.WriteLine($"I'll bet ${V}"); -_1430: K=V; -_1440: if (GetWager()) { return false; } -_1450: response = Line_650(); - if (response.HasValue) { return response.Value; } -_1460: _io.WriteLine(); -_1470: _io.WriteLine("Now we compare hands:"); -_1480: JS=HS; -_1490: KS=IS; -_1500: _io.WriteLine("My hand:"); -_1520: DisplayHand(6); -_1540: AnalyzeHand(1); -_1550: _io.WriteLine(); -_1560: _io.Write("You have "); -_1580: DisplayHandRank(HS, IS, (int)D); -_1620: _io.Write("and I have "); -_1630: DisplayHandRank(JS, KS, (int)M); -_1640: if (B>U) { return Line_670().Value; } -_1650: if (U>B) { return Line_780().Value; } -_1660: if (HS=="A Flus") { goto _1700; } -_1662: if (GetRank(M)GetRank(D)) { return Line_670().Value; } -_1670: _io.WriteLine("The hand is drawn."); -_1680: _io.WriteLine($"All ${_pot}remains in the pot."); -_1690: goto _140; -_1700: if (GetRank(M)>GetRank(D)) { return Line_670().Value; } -_1710: if (GetRank(D)>GetRank(M)) { return Line_780().Value; } -_1720: goto _1670; - void DealCard(int index, int indexToReplace = 0) { -_1740: _cards[index]=100*_random.Next(4) + _random.Next(100); -_1750: if ((int)_cards[index] / 100 > 3) { goto _1740; } -_1760: if (_cards[index] % 100 > 12) { goto _1740; } -_1765: if (index==1) { goto _1840; } -_1770: for (K=1; K <= index-1; K++) + while(true) { -_1780: if (_cards[index]==_cards[K]) { goto _1740; } + _cards[index]=100*_random.Next(4) + _random.Next(100); + if (GetSuit(_cards[index]) > 3) { continue; } + if (GetRank(_cards[index]) > 12) { continue; } + if (index==1) { break; } + var matchFound = false; + for (K=1; K <= index-1; K++) + { + if (_cards[index]==_cards[K]) + { + matchFound = true; + break; + } + } + if (!matchFound) { break; } } -_1800: if (index<=10) { goto _1840; } - (_cards[indexToReplace], _cards[index]) = (_cards[index], _cards[indexToReplace]); -_1840: return; + if (index > 10) + { + (_cards[indexToReplace], _cards[index]) = (_cards[index], _cards[indexToReplace]); + } + return; } void DisplayHand(int firstCard) { -_1850: for (Z = firstCard; Z <= firstCard+4; Z++) + for (Z = firstCard; Z <= firstCard+4; Z++) { var card = _cards[Z]; -_1860: _io.Write($"{Z}-- "); -_1870: DisplayRank(GetRank(card)); -_1880: _io.Write(" of"); -_1890: DisplaySuit(GetSuit(card)); -_1900: if (Z % 2 != 0) { goto _1920; } -_1910: _io.WriteLine(); -_1920: ; + _io.Write($"{Z}-- "); + _io.Write(GetRankName(GetRank(card))); + _io.Write(" of"); + _io.Write(GetSuitName(GetSuit(card))); + if (Z % 2 == 0) + { + _io.WriteLine(); + } } -_1930: _io.WriteLine(); -_1940: return; + _io.WriteLine(); + return; } - void DisplayRank(int rank) + string GetRankName(int rank) => rank switch { -_1960: if (rank!=9) { goto _1980; } -_1970: _io.Write("Jack"); -_1980: if (rank!=10) { goto _2000; } -_1990: _io.Write("Queen"); -_2000: if (rank!=11) { goto _2020; } -_2010: _io.Write("King"); -_2020: if (rank!=12) { goto _2040; } -_2030: _io.Write("Ace"); -_2040: if (rank>=9) { goto _2060; } -_2050: _io.Write(rank+2); -_2060: return; - } + 9 => "Jack", + 10 => "Queen", + 11 => "King", + 12 => "Ace", + _ => (rank + 2).ToString() + }; - void DisplaySuit(int suitNumber) + + string GetSuitName(int suitNumber) => suitNumber switch { -_2080: if (suitNumber!=0) { goto _2100; } -_2090: _io.Write(" Clubs"); -_2100: if (suitNumber!=1) { goto _2120; } -_2110: _io.Write(" Diamonds"); -_2120: if (suitNumber!=2) { goto _2140; } -_2130: _io.Write(" Hearts"); -_2140: if (suitNumber!=3) { goto _2160; } -_2150: _io.Write(" Spades"); -_2160: return; - } + 0 => " Clubs", + 1 => " Diamonds", + 2 => " Hearts", + 3 => " Spades", + }; + void AnalyzeHand(int firstCard) { @@ -417,12 +415,6 @@ _3030: IS="ouse, "; _3040: return; } - bool Line_3050() - { -_3050: G=0; - return GetWager(); - } - bool GetWager() { _3060: _io.WriteLine(); @@ -434,7 +426,7 @@ _3110: if (T==.5) { return false; } _3120: _io.WriteLine("No small change, please."); _3130: goto _3060; _3140: if (_playerBalance-G-T>=0) { goto _3170; } -_3150: if (Line_3830()) { return true; } +_3150: if (PlayerCantRaiseFunds()) { return true; } _3160: goto _3060; _3170: if (T!=0) { goto _3200; } _3180: I=3; @@ -505,15 +497,15 @@ _3560: if (JS.StartsWith("N", InvariantCultureIgnoreCase)) { goto _3600; } _3570: _computerBalance=_computerBalance+50; _3580: O=O/2; _3590: return false; -_3600: if (O % 3!= 0) { return Line_3670(); } +_3600: if (O % 3!= 0) { return CongratulatePlayer(); } _3610: JS = _io.ReadString("Would you like to buy back your tie tack for $50"); -_3630: if (JS.StartsWith("N", InvariantCultureIgnoreCase)) { return Line_3670(); } +_3630: if (JS.StartsWith("N", InvariantCultureIgnoreCase)) { return CongratulatePlayer(); } _3640: _computerBalance=_computerBalance+50; _3650: O=O/3; _3660: return false; } - bool Line_3670() + bool CongratulatePlayer() { _3670: _io.WriteLine("I'm busted. Congratulations!"); _3680: return true; // STOP @@ -524,10 +516,10 @@ _3680: return true; // STOP _3690: _io.Write($"{part1}{part2}"); _3700: if (part1!="A FLUS") { goto _3750; } _3710: ; -_3720: DisplaySuit(highCard/100); +_3720: _io.Write(GetSuitName(highCard/100)); _3730: _io.WriteLine(); _3740: return; -_3750: DisplayRank(GetRank(highCard)); +_3750: _io.Write(GetRankName(GetRank(highCard))); _3770: if (part1=="Schmal") { goto _3790; } _3780: if (part1!="Straig") { goto _3810; } _3790: _io.WriteLine(" High"); @@ -536,7 +528,7 @@ _3810: _io.WriteLine("'s"); _3820: return; } - bool Line_3830() + bool PlayerCantRaiseFunds() { _3830: _io.WriteLine(); _3840: _io.WriteLine("You can't bet with what you haven't got."); @@ -568,4 +560,29 @@ _4090: _io.WriteLine("Your wad is shot. So long, sucker!"); _4100: return true; } } +} + +internal static class IReadWriteExtensions +{ + internal static bool ReadYesNo(this IReadWrite io, string prompt) + { + while (true) + { + var response = io.ReadString("Do you wish to continue"); + if (response.Equals("YES", InvariantCultureIgnoreCase)) { return true; } + if (response.Equals("NO", InvariantCultureIgnoreCase)) { return false; } + io.WriteLine("Answer Yes or No, please."); + } + } + + internal static int ReadNumber(this IReadWrite io, string prompt, int max, string maxPrompt) + { + io.Write(prompt); + while (true) + { + var response = io.ReadNumber(""); + if (response <= max) { return (int)response; } + io.WriteLine(maxPrompt); + } + } } \ No newline at end of file From 7773d828333f95ad59a913be77d30cc55a813dfe Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Wed, 4 May 2022 22:34:54 +1000 Subject: [PATCH 07/29] Clean up more branching and lables --- 71_Poker/csharp/Games.cs | 379 ++++++++++++++++++--------------------- 1 file changed, 176 insertions(+), 203 deletions(-) diff --git a/71_Poker/csharp/Games.cs b/71_Poker/csharp/Games.cs index a7c89c1b..5552fd0d 100644 --- a/71_Poker/csharp/Games.cs +++ b/71_Poker/csharp/Games.cs @@ -22,12 +22,12 @@ internal class Game } } - private readonly FloatArray _cards = new(new float[51]); // 10 DIM A(50),B(15) + private readonly FloatArray _cards = new(new float[51]); private readonly FloatArray _cardRanks = new(new float[16]); - private float O = 1; // 90 = 120 - private float _computerBalance = 200; - private float _playerBalance = 200; - private float _pot = 0; + private bool _hasWatch; + private float _computerBalance; + private float _playerBalance; + private float _pot; private float B; private float M; @@ -64,9 +64,10 @@ internal class Game _io.Write(Resource.Streams.Title); _io.Write(Resource.Streams.Instructions); - O=1; - _computerBalance=200; - _playerBalance=200; + _hasWatch = true; + _computerBalance = 200; + _playerBalance = 200; + while(PlayHand()); } @@ -94,7 +95,7 @@ internal class Game _io.WriteLine("Your hand:"); DisplayHand(1); I=2; - AnalyzeHand(6); + (B, JS, KS, M, X) = AnalyzeHand(6); _io.WriteLine(); _330: if (I!=6) { goto _470; } _340: if (Get0To9()<=7) { goto _370; } @@ -110,16 +111,16 @@ _430: Z=23; _440: goto _580; _450: Z=1; _460: goto _510; -_470: if (U>=13) { goto _540; } +_470: if (B >= 13) { goto _540; } _480: if (Get0To9()>=2) { goto _500; } _490: goto _420; _500: Z=0; _510: K=0; _520: _io.WriteLine("I check."); _530: goto _620; -_540: Z = U <= 16 || Get0To9() < 1 ? 35 : 2; +_540: Z = B <= 16 || Get0To9() < 1 ? 35 : 2; _580: V=Z+Get0To9(); -_590: if (Line_3480()) { return false; } +_590: if (CopmuterCantContinue()) { return false; } _600: _io.WriteLine($"I'll open with ${V}"); _610: K=V; G = 0; @@ -158,30 +159,28 @@ _630: var response = IsThereAWinner(); _io.WriteLine(); V=I; I=1; - AnalyzeHand(6); - B=U; - M=D; + (B, JS, KS, M, X) = AnalyzeHand(6); if (V == 7) { - Z=28; + Z = 28; } else if (I == 6) { - Z=1; + Z = 1; } - else if (U < 13) + else if (B < 13) { Z = Get0To9() == 6 ? 19 : 2; } else { - if (U >= 16) + if (B >= 16) { Z = 2; } else { - Z = Get0To9()==8 ? 11 : 19; + Z = Get0To9() == 8 ? 11 : 19; } } _1330: K=0; @@ -193,28 +192,26 @@ _1370: if (I!=6) { goto _1400; } _1380: _io.WriteLine("I'll check"); _1390: goto _1460; _1400: V=Z+Get0To9(); -_1410: if (Line_3480()) { return false; } +_1410: if (CopmuterCantContinue()) { return false; } _1420: _io.WriteLine($"I'll bet ${V}"); _1430: K=V; _1440: if (GetWager()) { return false; } _1450: response = IsThereAWinner(); if (response.HasValue) { return response.Value; } _1460: _io.WriteLine(); -_1470: _io.WriteLine("Now we compare hands:"); -_1480: JS=HS; -_1490: KS=IS; -_1500: _io.WriteLine("My hand:"); -_1520: DisplayHand(6); -_1540: AnalyzeHand(1); -_1550: _io.WriteLine(); -_1560: _io.Write("You have "); -_1580: DisplayHandRank(HS, IS, (int)D); -_1620: _io.Write("and I have "); -_1630: DisplayHandRank(JS, KS, (int)M); + _io.WriteLine("Now we compare hands:"); + _io.WriteLine("My hand:"); + DisplayHand(6); + (U, HS, IS, D, X) = AnalyzeHand(1); + _io.WriteLine(); + _io.Write("You have "); + DisplayHandRank(HS, IS, (int)D); + _io.Write("and I have "); + DisplayHandRank(JS, KS, (int)M); if (B > U || GetRank(M) > GetRank(D)) { return ComputerWins().Value; } if (U > B || GetRank(D) > GetRank(M)) { return PlayerWins().Value; } -_1670: _io.WriteLine("The hand is drawn."); -_1680: _io.WriteLine($"All ${_pot}remains in the pot."); + _io.WriteLine("The hand is drawn."); + _io.WriteLine($"All ${_pot}remains in the pot."); } bool? IsThereAWinner() @@ -258,9 +255,9 @@ _1680: _io.WriteLine($"All ${_pot}remains in the pot."); if (GetRank(_cards[index]) > 12) { continue; } if (index==1) { break; } var matchFound = false; - for (K=1; K <= index-1; K++) + for (var i=1; i <= index-1; i++) { - if (_cards[index]==_cards[K]) + if (_cards[index]==_cards[i]) { matchFound = true; break; @@ -302,118 +299,97 @@ _1680: _io.WriteLine($"All ${_pot}remains in the pot."); _ => (rank + 2).ToString() }; - string GetSuitName(int suitNumber) => suitNumber switch { 0 => " Clubs", 1 => " Diamonds", 2 => " Hearts", - 3 => " Spades", + 3 => " Spades" }; - - void AnalyzeHand(int firstCard) + (int, string, string, float, int) AnalyzeHand(int firstCard) { -_2170: U=0; -_2180: for (Z=firstCard; Z <= firstCard+4; Z++) + var suitMatchCount = 0; + for (var i = firstCard; i <= firstCard+4; i++) { -_2190: _cardRanks[Z]=GetRank(_cards[Z]); -_2200: if (Z==firstCard+4) { goto _2230; } -_2210: if (GetSuit(_cards[Z]) != GetSuit(_cards[Z+1])) { goto _2230; } -_2220: U++; -_2230: ; + _cardRanks[i]=GetRank(_cards[i]); + if (i < firstCard+4 && GetSuit(_cards[i]) == GetSuit(_cards[i+1])) + { + suitMatchCount++; + } } -_2240: if (U!=4) { goto _2310; } -_2250: X=11111; -_2260: D=_cards[firstCard]; -_2270: HS="A Flus"; -_2280: IS="h in"; -_2290: U=15; -_2300: return; -_2310: for (Z=firstCard; Z <= firstCard+3; Z++) + if (suitMatchCount == 4) { -_2320: for (K=Z+1; K <= firstCard+4; K++) + return (15, "A Flus", "h in", _cards[firstCard], 11111); + } + for (var i = firstCard; i <= firstCard+3; i++) + { + for (var j = i+1; j <= firstCard+4; j++) { -_2330: if (_cardRanks[Z]<=_cardRanks[K]) { goto _2390; } -_2340: X=_cards[Z]; -_2350: _cards[Z]=_cards[K]; -_2360: _cardRanks[Z]=_cardRanks[K]; -_2370: _cards[K]=X; -_2380: _cardRanks[K]=GetRank(_cards[K]); -_2390: ; + if (_cardRanks[i] > _cardRanks[j]) + { + (_cards[i], _cards[j]) = (_cards[j], _cards[i]); + (_cardRanks[i], _cardRanks[j]) = (_cardRanks[j], _cardRanks[i]); + } } } -_2410: X=0; -_2420: for (Z=firstCard; Z <= firstCard+3; Z++) + var handRank = 0; + var keepMask = 0; + var highCard = 0f; + var handName1 = ""; + var handName2 = ""; + for (var i = firstCard; i <= firstCard+3; i++) { -_2430: if (_cardRanks[Z]!=_cardRanks[Z+1]) { goto _2470; } -_2440: X += 11*(float)Math.Pow(10, Z-firstCard); -_2450: D=_cards[Z]; -_2460: AnalyzeMultiples(); -_2470: ; + if (_cardRanks[i] == _cardRanks[i+1]) + { + keepMask += 11*(int)Math.Pow(10, i-firstCard); + highCard = _cards[i]; + (handRank, handName1, handName2) = AnalyzeMultiples(handRank, i); + } } -_2480: if (X!=0) { goto _2620; } -_2490: if (_cardRanks[firstCard]+3!=_cardRanks[firstCard+3]) { goto _2520; } -_2500: X=1111; -_2510: U=10; -_2520: if (_cardRanks[firstCard+1]+3!=_cardRanks[firstCard+4]) { goto _2620; } -_2530: if (U!=10) { goto _2600; } -_2540: U=14; -_2550: HS="Straig"; -_2560: IS="ht"; -_2570: X=11111; -_2580: D=_cards[firstCard+4]; -_2590: return; -_2600: U=10; -_2610: X=11110; -_2620: if (U>=10) { goto _2690; } -_2630: D=_cards[firstCard+4]; -_2640: HS="Schmal"; -_2650: IS="tz, "; -_2660: U=9; -_2670: X=11000; -_2680: goto _2740; -_2690: if (U!=10) { goto _2720; } -_2700: if (I==1) { goto _2740; } -_2710: goto _2750; -_2720: if (U>12) { goto _2750; } -_2730: if (GetRank(D)>6) { goto _2750; } -_2740: I=6; -_2750: return; + if (keepMask == 0) + { + if (_cardRanks[firstCard]+3 == _cardRanks[firstCard+3]) + { + keepMask=1111; + handRank=10; + } + if (_cardRanks[firstCard+1]+3 == _cardRanks[firstCard+4]) + { + if (handRank == 10) + { + return (14, "Straig", "ht", _cards[firstCard+4], 11111); + } + handRank=10; + keepMask=11110; + } + } + if (handRank < 10) + { + I = 6; + return (9, "Schmal", "tz, ", _cards[firstCard+4], 11000); + } + else if (handRank == 10) + { + if (I == 1) { I = 6; } + } + else if (handRank <= 12 && GetRank(highCard) <= 6) + { + I = 6; + } + return (handRank, handName1, handName2, highCard, keepMask); } - void AnalyzeMultiples() - { -_2760: if (U>=11) { goto _2810; } -_2770: U=11; -_2780: HS="A Pair"; -_2790: IS=" of "; -_2800: return; -_2810: if (U!=11) { goto _2910; } -_2820: if (_cardRanks[Z]!=_cardRanks[Z-1]) { goto _2870; } -_2830: HS="Three"; -_2840: IS=" "; -_2850: U=13; -_2860: return; -_2870: HS="Two P"; -_2880: IS="air, "; -_2890: U=12; -_2900: return; -_2910: if (U>12) { goto _2960; } -_2920: U=16; -_2930: HS="Full H"; -_2940: IS="ouse, "; -_2950: return; -_2960: if (_cardRanks[Z]!=_cardRanks[Z-1]) { goto _3010; } -_2970: U=17; -_2980: HS="Four"; -_2990: IS=" "; -_3000: return; -_3010: U=16; -_3020: HS="Full H"; -_3030: IS="ouse, "; -_3040: return; - } + (int, string, string) AnalyzeMultiples(int handStrength, int index) => + (handStrength, _cardRanks[index] == _cardRanks[index - 1]) 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, ") + }; bool GetWager() { @@ -450,114 +426,111 @@ _3340: return false; bool Line_3350() { -_3350: if (Z==2) { return Line_3430(); } + if (Z==2) { return Line_3430(); } return Line_3360(); } bool Line_3360() { -_3360: _io.WriteLine("I'll see you."); -_3370: K=G; + _io.WriteLine("I'll see you."); + K=G; return Line_3380(); } bool Line_3380() { -_3380: _playerBalance -= G; -_3390: _computerBalance -= K; -_3400: _pot += G+K; + _playerBalance -= G; + _computerBalance -= K; + _pot += G+K; return false; } bool Line_3420() { -_3420: if (G>3*Z) { return Line_3350(); } + if (G>3*Z) { return Line_3350(); } return Line_3430(); } bool Line_3430() { -_3430: V=G-K+Get0To9(); -_3440: if (Line_3480()) { return true; } -_3450: _io.WriteLine($"I'll see you, and raise you{V}"); -_3460: K=G+V; -_3470: return GetWager(); + V=G-K+Get0To9(); + if (CopmuterCantContinue()) { return true; } + _io.WriteLine($"I'll see you, and raise you{V}"); + K=G+V; + return GetWager(); } - bool Line_3480() + bool CopmuterCantContinue() { -_3480: if (_computerBalance-G-V>=0) { goto _3660; } -_3490: if (G!=0) { goto _3520; } -_3500: V=_computerBalance; -_3510: return false; -_3520: if (_computerBalance-G>=0) { return Line_3360(); } -_3530: if (O % 2 != 0) { goto _3600; } -_3540: JS = _io.ReadString("Would you like to buy back your watch for $50"); -_3560: if (JS.StartsWith("N", InvariantCultureIgnoreCase)) { goto _3600; } -_3570: _computerBalance=_computerBalance+50; -_3580: O=O/2; -_3590: return false; -_3600: if (O % 3!= 0) { return CongratulatePlayer(); } -_3610: JS = _io.ReadString("Would you like to buy back your tie tack for $50"); -_3630: if (JS.StartsWith("N", InvariantCultureIgnoreCase)) { return CongratulatePlayer(); } -_3640: _computerBalance=_computerBalance+50; -_3650: O=O/3; -_3660: return false; + if (_computerBalance - G - V >= 0) { return false; } + if (G == 0) + { + V = _computerBalance; + } + else if (_computerBalance - G >= 0) + { + return Line_3360(); + } + else if (!_hasWatch) + { + var response = _io.ReadString("Would you like to buy back your watch for $50"); + if (!response.StartsWith("N", InvariantCultureIgnoreCase)) + { + // The original code did not deduct $50 from the player + _computerBalance += 50; + _hasWatch = true; + } + } + return false; } bool CongratulatePlayer() { -_3670: _io.WriteLine("I'm busted. Congratulations!"); -_3680: return true; // STOP + _io.WriteLine("I'm busted. Congratulations!"); + return true; } void DisplayHandRank(string part1, string part2, int highCard) { -_3690: _io.Write($"{part1}{part2}"); -_3700: if (part1!="A FLUS") { goto _3750; } -_3710: ; -_3720: _io.Write(GetSuitName(highCard/100)); -_3730: _io.WriteLine(); -_3740: return; -_3750: _io.Write(GetRankName(GetRank(highCard))); -_3770: if (part1=="Schmal") { goto _3790; } -_3780: if (part1!="Straig") { goto _3810; } -_3790: _io.WriteLine(" High"); -_3800: return; -_3810: _io.WriteLine("'s"); -_3820: return; + _io.Write($"{part1}{part2}"); + if (part1 == "A Flus") + { + _io.Write(GetSuitName(highCard/100)); + _io.WriteLine(); + } + else + { + _io.Write(GetRankName(GetRank(highCard))); + _io.WriteLine(part1 == "Schmal" || part1 == "Straig" ? " High" : "'s"); + } } bool PlayerCantRaiseFunds() { -_3830: _io.WriteLine(); -_3840: _io.WriteLine("You can't bet with what you haven't got."); -_3850: if (O % 2 == 0) { goto _3970; } -_3860: _io.Write("Would you like to sell your watch"); -_3870: JS = _io.ReadString(""); -_3880: if (JS.StartsWith("N", InvariantCultureIgnoreCase)) { goto _3970; } -_3890: if (Get0To9()>=7) { goto _3930; } -_3900: _io.WriteLine("I'll give you $75 for it."); -_3910: _playerBalance=_playerBalance+75; -_3920: goto _3950; -_3930: _io.WriteLine("That's a pretty crummy watch - I'll give you $25."); -_3940: _playerBalance=_playerBalance+25; -_3950: O=O*2; -_3960: return false; -_3970: if (O % 3 != 0) { goto _4090; } -_3980: _io.WriteLine("Will you part with that diamond tie tack"); -_3990: JS = _io.ReadString(""); -_4000: if (JS.StartsWith("N", InvariantCultureIgnoreCase)) { goto _4080; } -_4010: if (Get0To9()>=6) { goto _4050; } -_4020: _io.WriteLine("You are now $100 richer."); -_4030: _playerBalance=_playerBalance+100; -_4040: goto _4070; -_4050: _io.WriteLine("It's paste. $25."); -_4060: _playerBalance=_playerBalance+25; -_4070: O=O*3; -_4080: return false; -_4090: _io.WriteLine("Your wad is shot. So long, sucker!"); -_4100: return true; + _io.WriteLine(); + _io.WriteLine("You can't bet with what you haven't got."); + if (_hasWatch) + { + var response = _io.ReadString("Would you like to sell your watch"); + if (!response.StartsWith("N", InvariantCultureIgnoreCase)) + { + if (Get0To9() < 7) + { + _io.WriteLine("I'll give you $75 for it."); + _playerBalance += 75; + } + else + { + _io.WriteLine("That's a pretty crummy watch - I'll give you $25."); + _playerBalance += 25; + } + _hasWatch = false; + return false; + } + } + + _io.WriteLine("Your wad is shot. So long, sucker!"); + return true; } } } From 078ea428c58217a85634be115440d859f1ddcc9e Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Tue, 17 May 2022 19:17:13 +1000 Subject: [PATCH 08/29] Add Card, Rank and Suit types --- 71_Poker/csharp/Games.cs | 162 ++++++++++++++++++++++++++----------- 71_Poker/csharp/Program.cs | 1 + 2 files changed, 118 insertions(+), 45 deletions(-) diff --git a/71_Poker/csharp/Games.cs b/71_Poker/csharp/Games.cs index 5552fd0d..2fc44440 100644 --- a/71_Poker/csharp/Games.cs +++ b/71_Poker/csharp/Games.cs @@ -1,29 +1,32 @@ using Poker.Resources; using static System.StringComparison; +using static Poker.Rank; + +namespace Poker; internal class Game { private readonly IReadWrite _io; private readonly IRandom _random; - private class FloatArray + private class CardArray { - private float[] _values; + private Card[] _values; - public FloatArray(float[] values) + public CardArray(Card[] values) { _values = values; } - public float this[float index] + public Card this[float index] { get => _values[(int)index]; set => _values[(int)index] = value; } } - private readonly FloatArray _cards = new(new float[51]); - private readonly FloatArray _cardRanks = new(new float[16]); + private readonly CardArray _cards = new(new Card[51]); + private readonly CardArray _cardRanks = new(new Card[16]); private bool _hasWatch; private float _computerBalance; private float _playerBalance; @@ -61,6 +64,8 @@ internal class Game internal void Play() { + var deck = new Deck(); + _io.Write(Resource.Streams.Title); _io.Write(Resource.Streams.Instructions); @@ -68,10 +73,13 @@ internal class Game _computerBalance = 200; _playerBalance = 200; - while(PlayHand()); + do + { + deck.Shuffle(_random); + } while (PlayHand(deck)); } - internal bool PlayHand() + internal bool PlayHand(Deck deck) { _pot=0; while(true) @@ -248,23 +256,7 @@ _1460: _io.WriteLine(); void DealCard(int index, int indexToReplace = 0) { - while(true) - { - _cards[index]=100*_random.Next(4) + _random.Next(100); - if (GetSuit(_cards[index]) > 3) { continue; } - if (GetRank(_cards[index]) > 12) { continue; } - if (index==1) { break; } - var matchFound = false; - for (var i=1; i <= index-1; i++) - { - if (_cards[index]==_cards[i]) - { - matchFound = true; - break; - } - } - if (!matchFound) { break; } - } + _cards[index] = deck.Deal(); if (index > 10) { (_cards[indexToReplace], _cards[index]) = (_cards[index], _cards[indexToReplace]); @@ -276,11 +268,7 @@ _1460: _io.WriteLine(); { for (Z = firstCard; Z <= firstCard+4; Z++) { - var card = _cards[Z]; - _io.Write($"{Z}-- "); - _io.Write(GetRankName(GetRank(card))); - _io.Write(" of"); - _io.Write(GetSuitName(GetSuit(card))); + _io.Write($"{Z}-- {_cards[Z]}"); if (Z % 2 == 0) { _io.WriteLine(); @@ -312,35 +300,33 @@ _1460: _io.WriteLine(); var suitMatchCount = 0; for (var i = firstCard; i <= firstCard+4; i++) { - _cardRanks[i]=GetRank(_cards[i]); - if (i < firstCard+4 && GetSuit(_cards[i]) == GetSuit(_cards[i+1])) + if (i < firstCard+4 && _cards[i].Suit == _cards[i+1].Suit) { suitMatchCount++; } } if (suitMatchCount == 4) { - return (15, "A Flus", "h in", _cards[firstCard], 11111); + return (15, "A Flus", "h in", _cards[firstCard].Value, 11111); } for (var i = firstCard; i <= firstCard+3; i++) { for (var j = i+1; j <= firstCard+4; j++) { - if (_cardRanks[i] > _cardRanks[j]) + if (_cards[i].Rank > _cards[j].Rank) { (_cards[i], _cards[j]) = (_cards[j], _cards[i]); - (_cardRanks[i], _cardRanks[j]) = (_cardRanks[j], _cardRanks[i]); } } } var handRank = 0; var keepMask = 0; - var highCard = 0f; + Card highCard = default; var handName1 = ""; var handName2 = ""; for (var i = firstCard; i <= firstCard+3; i++) { - if (_cardRanks[i] == _cardRanks[i+1]) + if (_cards[i].Rank == _cards[i+1].Rank) { keepMask += 11*(int)Math.Pow(10, i-firstCard); highCard = _cards[i]; @@ -349,16 +335,16 @@ _1460: _io.WriteLine(); } if (keepMask == 0) { - if (_cardRanks[firstCard]+3 == _cardRanks[firstCard+3]) + if (_cards[firstCard].Rank.Value + 3 == _cards[firstCard+3].Rank.Value) { keepMask=1111; handRank=10; } - if (_cardRanks[firstCard+1]+3 == _cardRanks[firstCard+4]) + if (_cards[firstCard+1].Rank.Value + 3 == _cards[firstCard+4].Rank.Value) { if (handRank == 10) { - return (14, "Straig", "ht", _cards[firstCard+4], 11111); + return (14, "Straig", "ht", _cards[firstCard+4].Value, 11111); } handRank=10; keepMask=11110; @@ -367,21 +353,21 @@ _1460: _io.WriteLine(); if (handRank < 10) { I = 6; - return (9, "Schmal", "tz, ", _cards[firstCard+4], 11000); + return (9, "Schmal", "tz, ", _cards[firstCard+4].Value, 11000); } else if (handRank == 10) { if (I == 1) { I = 6; } } - else if (handRank <= 12 && GetRank(highCard) <= 6) + else if (handRank <= 12 && highCard.Rank <= 6) { I = 6; } - return (handRank, handName1, handName2, highCard, keepMask); + return (handRank, handName1, handName2, highCard.Value, keepMask); } (int, string, string) AnalyzeMultiples(int handStrength, int index) => - (handStrength, _cardRanks[index] == _cardRanks[index - 1]) switch + (handStrength, _cards[index].Rank == _cards[index - 1].Rank) switch { (<11, _) => (11, "A Pair", " of "), (11, true) => (13, "Three", " "), @@ -509,6 +495,7 @@ _3340: return false; { _io.WriteLine(); _io.WriteLine("You can't bet with what you haven't got."); + if (_hasWatch) { var response = _io.ReadString("Would you like to sell your watch"); @@ -529,19 +516,104 @@ _3340: 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; } } } +internal enum Suit +{ + Clubs, + Diamonds, + Hearts, + Spades +} + +internal class Deck +{ + private readonly Card[] _cards; + private int _nextCard; + + public Deck() + { + _cards = Ranks.SelectMany(r => Enum.GetValues().Select(s => new Card(r, s))).ToArray(); + } + + public void Shuffle(IRandom _random) + { + for (int i = 0; i < _cards.Length; i++) + { + var j = _random.Next(_cards.Length); + (_cards[i], _cards[j]) = (_cards[j], _cards[i]); + } + } + + public Card Deal() => _cards[_nextCard++]; +} + +internal record struct Card (Rank Rank, Suit Suit) +{ + public float Value => Rank.Value + (int)Suit * 100; + + public override string ToString() => $"{Rank} of {Suit}"; + + public static bool operator <(Card x, Card y) => x.Rank < y.Rank; + public static bool operator >(Card x, Card y) => x.Rank > y.Rank; +} + +internal struct Rank +{ + public static IEnumerable Ranks => new[] + { + Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten, Jack, Queen, King, Ace + }; + + public static Rank Two = new Rank(2); + public static Rank Three = new Rank(3); + public static Rank Four = new Rank(4); + public static Rank Five = new Rank(5); + public static Rank Six = new Rank(6); + public static Rank Seven = new Rank(7); + public static Rank Eight = new Rank(8); + public static Rank Nine = new Rank(9); + public static Rank Ten = new Rank(10); + public static Rank Jack = new Rank(11, "Jack"); + public static Rank Queen = new Rank(12, "Queen"); + public static Rank King = new Rank(13, "King"); + public static Rank Ace = new Rank(14, "Ace"); + + private readonly int _value; + private readonly string _name; + + private Rank(int value, string? name = null) + { + _value = value; + _name = name ?? $" {value} "; + } + + public int Value => _value - 2; + public override string ToString() => _name; + + public static bool operator <(Rank x, Rank y) => x._value < y._value; + public static bool operator >(Rank x, Rank y) => x._value > y._value; + public static bool operator ==(Rank x, Rank y) => x._value == y._value; + public static bool operator !=(Rank x, Rank y) => x._value != y._value; + + public static bool operator <=(Rank rank, int value) => rank._value <= value; + public static bool operator >=(Rank rank, int value) => rank._value >= value; +} + internal static class IReadWriteExtensions { internal static bool ReadYesNo(this IReadWrite io, string prompt) { while (true) { - var response = io.ReadString("Do you wish to continue"); + var response = io.ReadString(prompt); if (response.Equals("YES", InvariantCultureIgnoreCase)) { return true; } if (response.Equals("NO", InvariantCultureIgnoreCase)) { return false; } io.WriteLine("Answer Yes or No, please."); diff --git a/71_Poker/csharp/Program.cs b/71_Poker/csharp/Program.cs index b1f36179..c3200a96 100644 --- a/71_Poker/csharp/Program.cs +++ b/71_Poker/csharp/Program.cs @@ -1,4 +1,5 @@ global using Games.Common.IO; global using Games.Common.Randomness; +global using Poker; new Game(new ConsoleIO(), new RandomNumberGenerator()).Play(); \ No newline at end of file From b95b475fc5414940fc196a94a7cbc61fd1b0b7a1 Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Tue, 17 May 2022 19:34:20 +1000 Subject: [PATCH 09/29] Use Card type for HighCard --- 71_Poker/csharp/Games.cs | 67 ++++++++++++++-------------------------- 1 file changed, 23 insertions(+), 44 deletions(-) diff --git a/71_Poker/csharp/Games.cs b/71_Poker/csharp/Games.cs index 2fc44440..20b1c985 100644 --- a/71_Poker/csharp/Games.cs +++ b/71_Poker/csharp/Games.cs @@ -26,16 +26,15 @@ internal class Game } private readonly CardArray _cards = new(new Card[51]); - private readonly CardArray _cardRanks = new(new Card[16]); private bool _hasWatch; private float _computerBalance; private float _playerBalance; private float _pot; private float B; - private float M; + private Card _computerHighCard; private float T; - private float D; + private Card _playerHighCard; private float G; private float I; private float U; @@ -58,10 +57,6 @@ internal class Game private int Get0To9() => _random.Next(10); - private static int GetRank(float x) => (int)x % 100; - - private static int GetSuit(float x) => (int)x / 100; - internal void Play() { var deck = new Deck(); @@ -103,7 +98,7 @@ internal class Game _io.WriteLine("Your hand:"); DisplayHand(1); I=2; - (B, JS, KS, M, X) = AnalyzeHand(6); + (B, JS, KS, _computerHighCard, X) = AnalyzeHand(6); _io.WriteLine(); _330: if (I!=6) { goto _470; } _340: if (Get0To9()<=7) { goto _370; } @@ -167,7 +162,7 @@ _630: var response = IsThereAWinner(); _io.WriteLine(); V=I; I=1; - (B, JS, KS, M, X) = AnalyzeHand(6); + (B, JS, KS, _computerHighCard, X) = AnalyzeHand(6); if (V == 7) { Z = 28; @@ -210,14 +205,14 @@ _1460: _io.WriteLine(); _io.WriteLine("Now we compare hands:"); _io.WriteLine("My hand:"); DisplayHand(6); - (U, HS, IS, D, X) = AnalyzeHand(1); + (U, HS, IS, _playerHighCard, X) = AnalyzeHand(1); _io.WriteLine(); _io.Write("You have "); - DisplayHandRank(HS, IS, (int)D); + DisplayHandRank(HS, IS, _playerHighCard); _io.Write("and I have "); - DisplayHandRank(JS, KS, (int)M); - if (B > U || GetRank(M) > GetRank(D)) { return ComputerWins().Value; } - if (U > B || GetRank(D) > GetRank(M)) { return PlayerWins().Value; } + DisplayHandRank(JS, KS, _computerHighCard); + if (B > U || _computerHighCard > _playerHighCard) { return ComputerWins().Value; } + if (U > B || _playerHighCard > _computerHighCard) { return PlayerWins().Value; } _io.WriteLine("The hand is drawn."); _io.WriteLine($"All ${_pot}remains in the pot."); } @@ -278,24 +273,7 @@ _1460: _io.WriteLine(); return; } - string GetRankName(int rank) => rank switch - { - 9 => "Jack", - 10 => "Queen", - 11 => "King", - 12 => "Ace", - _ => (rank + 2).ToString() - }; - - string GetSuitName(int suitNumber) => suitNumber switch - { - 0 => " Clubs", - 1 => " Diamonds", - 2 => " Hearts", - 3 => " Spades" - }; - - (int, string, string, float, int) AnalyzeHand(int firstCard) + (int, string, string, Card, int) AnalyzeHand(int firstCard) { var suitMatchCount = 0; for (var i = firstCard; i <= firstCard+4; i++) @@ -307,7 +285,7 @@ _1460: _io.WriteLine(); } if (suitMatchCount == 4) { - return (15, "A Flus", "h in", _cards[firstCard].Value, 11111); + return (15, "A Flus", "h in", _cards[firstCard], 11111); } for (var i = firstCard; i <= firstCard+3; i++) { @@ -335,16 +313,16 @@ _1460: _io.WriteLine(); } if (keepMask == 0) { - if (_cards[firstCard].Rank.Value + 3 == _cards[firstCard+3].Rank.Value) + if (_cards[firstCard+3] - _cards[firstCard] == 3) { keepMask=1111; handRank=10; } - if (_cards[firstCard+1].Rank.Value + 3 == _cards[firstCard+4].Rank.Value) + if (_cards[firstCard+4] - _cards[firstCard+1] == 3) { if (handRank == 10) { - return (14, "Straig", "ht", _cards[firstCard+4].Value, 11111); + return (14, "Straig", "ht", _cards[firstCard+4], 11111); } handRank=10; keepMask=11110; @@ -353,7 +331,7 @@ _1460: _io.WriteLine(); if (handRank < 10) { I = 6; - return (9, "Schmal", "tz, ", _cards[firstCard+4].Value, 11000); + return (9, "Schmal", "tz, ", _cards[firstCard+4], 11000); } else if (handRank == 10) { @@ -363,7 +341,7 @@ _1460: _io.WriteLine(); { I = 6; } - return (handRank, handName1, handName2, highCard.Value, keepMask); + return (handRank, handName1, handName2, highCard, keepMask); } (int, string, string) AnalyzeMultiples(int handStrength, int index) => @@ -476,17 +454,17 @@ _3340: return false; return true; } - void DisplayHandRank(string part1, string part2, int highCard) + void DisplayHandRank(string part1, string part2, Card highCard) { _io.Write($"{part1}{part2}"); if (part1 == "A Flus") { - _io.Write(GetSuitName(highCard/100)); + _io.Write(highCard.Suit); _io.WriteLine(); } else { - _io.Write(GetRankName(GetRank(highCard))); + _io.Write(highCard.Rank); _io.WriteLine(part1 == "Schmal" || part1 == "Straig" ? " High" : "'s"); } } @@ -557,12 +535,12 @@ internal class Deck internal record struct Card (Rank Rank, Suit Suit) { - public float Value => Rank.Value + (int)Suit * 100; - public override string ToString() => $"{Rank} of {Suit}"; public static bool operator <(Card x, Card y) => x.Rank < y.Rank; public static bool operator >(Card x, Card y) => x.Rank > y.Rank; + + public static int operator -(Card x, Card y) => x.Rank - y.Rank; } internal struct Rank @@ -595,7 +573,6 @@ internal struct Rank _name = name ?? $" {value} "; } - public int Value => _value - 2; public override string ToString() => _name; public static bool operator <(Rank x, Rank y) => x._value < y._value; @@ -603,6 +580,8 @@ internal struct Rank public static bool operator ==(Rank x, Rank y) => x._value == y._value; public static bool operator !=(Rank x, Rank y) => x._value != y._value; + public static int operator -(Rank x, Rank y) => x._value - y._value; + public static bool operator <=(Rank rank, int value) => rank._value <= value; public static bool operator >=(Rank rank, int value) => rank._value >= value; } From 0fc3b2a40c8750d4b6846c70bba8e0191a58840b Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Sun, 29 May 2022 22:10:30 +1000 Subject: [PATCH 10/29] Add Hand type --- 71_Poker/csharp/Games.cs | 409 ++++++++++++++++++++------------------- 1 file changed, 207 insertions(+), 202 deletions(-) diff --git a/71_Poker/csharp/Games.cs b/71_Poker/csharp/Games.cs index 20b1c985..d24de695 100644 --- a/71_Poker/csharp/Games.cs +++ b/71_Poker/csharp/Games.cs @@ -1,3 +1,4 @@ +using System.Text; using Poker.Resources; using static System.StringComparison; using static Poker.Rank; @@ -9,45 +10,21 @@ internal class Game private readonly IReadWrite _io; private readonly IRandom _random; - private class CardArray - { - private Card[] _values; + private Hand _playerHand; + private Hand _computerHand; - public CardArray(Card[] values) - { - _values = values; - } - - public Card this[float index] - { - get => _values[(int)index]; - set => _values[(int)index] = value; - } - } - - private readonly CardArray _cards = new(new Card[51]); private bool _hasWatch; private float _computerBalance; private float _playerBalance; private float _pot; - private float B; - private Card _computerHighCard; private float T; - private Card _playerHighCard; private float G; - private float I; - private float U; + private int I; private float Z; private float X; private float K; private float V; - private float Q; - - private string JS; - private string KS; - private string HS; - private string IS; public Game(IReadWrite io, IRandom random) { @@ -89,16 +66,15 @@ internal class Game _io.WriteLine(); if (_playerBalance <= 5 && PlayerCantRaiseFunds()) { return false; } _pot += 10; + _playerBalance -= 5; _computerBalance -= 5; - for (Z=1; Z <= 10; Z++) - { - DealCard((int)Z); - } + _playerHand = deck.DealHand(); + _computerHand = deck.DealHand(); + _io.WriteLine("Your hand:"); - DisplayHand(1); - I=2; - (B, JS, KS, _computerHighCard, X) = AnalyzeHand(6); + _io.Write(_playerHand); + (X, I) = _computerHand.Analyze(2); _io.WriteLine(); _330: if (I!=6) { goto _470; } _340: if (Get0To9()<=7) { goto _370; } @@ -114,16 +90,16 @@ _430: Z=23; _440: goto _580; _450: Z=1; _460: goto _510; -_470: if (B >= 13) { goto _540; } +_470: if (_computerHand.Rank >= 13) { goto _540; } _480: if (Get0To9()>=2) { goto _500; } _490: goto _420; _500: Z=0; _510: K=0; _520: _io.WriteLine("I check."); _530: goto _620; -_540: Z = B <= 16 || Get0To9() < 1 ? 35 : 2; +_540: Z = _computerHand.Rank <= 16 || Get0To9() < 1 ? 35 : 2; _580: V=Z+Get0To9(); -_590: if (CopmuterCantContinue()) { return false; } +_590: if (ComputerCantContinue()) { return false; } _600: _io.WriteLine($"I'll open with ${V}"); _610: K=V; G = 0; @@ -132,37 +108,39 @@ _630: var response = IsThereAWinner(); if (response.HasValue) { return response.Value; } _io.WriteLine(); - T = _io.ReadNumber("Now we draw -- How many cards do you want", 3, "You can't draw more than three cards."); - if (T != 0) + var playerDrawCount = _io.ReadNumber( + "Now we draw -- How many cards do you want", + 3, + "You can't draw more than three cards."); + if (playerDrawCount != 0) { Z=10; _io.WriteLine("What are their numbers:"); - for (Q=1; Q <= T; Q++) + for (var i = 1; i <= playerDrawCount; i++) { - U = _io.ReadNumber(""); - DealCard((int)++Z, (int)U); + _playerHand = _playerHand.Replace((int)_io.ReadNumber(""), deck.DealCard()); } _io.WriteLine("Your new hand:"); - DisplayHand(1); + _io.Write(_playerHand); } - Z=10+T; - for (U=6; U <= 10; U++) + var computerDrawCount = 0; + for (var i = 1; i <= 5; i++) { - if ((int)(X/Math.Pow(10, U-6)) == 10*(int)(X/Math.Pow(10, U-5))) + if ((int)(X/Math.Pow(10, i-1)) == 10*(int)(X/Math.Pow(10, i))) { - DealCard((int)++Z, (int)U); + _computerHand = _computerHand.Replace(i, deck.DealCard()); + computerDrawCount++; } } _io.WriteLine(); - _io.Write($"I am taking{Z-10-T}card"); - if (Z != 11 + T) + _io.Write($"I am taking {computerDrawCount} card"); + if (computerDrawCount != 1) { _io.WriteLine("s"); } _io.WriteLine(); V=I; - I=1; - (B, JS, KS, _computerHighCard, X) = AnalyzeHand(6); + (X, I) = _computerHand.Analyze(1); if (V == 7) { Z = 28; @@ -171,13 +149,13 @@ _630: var response = IsThereAWinner(); { Z = 1; } - else if (B < 13) + else if (_computerHand.Rank < 13) { Z = Get0To9() == 6 ? 19 : 2; } else { - if (B >= 16) + if (_computerHand.Rank >= 16) { Z = 2; } @@ -195,7 +173,7 @@ _1370: if (I!=6) { goto _1400; } _1380: _io.WriteLine("I'll check"); _1390: goto _1460; _1400: V=Z+Get0To9(); -_1410: if (CopmuterCantContinue()) { return false; } +_1410: if (ComputerCantContinue()) { return false; } _1420: _io.WriteLine($"I'll bet ${V}"); _1430: K=V; _1440: if (GetWager()) { return false; } @@ -204,17 +182,15 @@ _1450: response = IsThereAWinner(); _1460: _io.WriteLine(); _io.WriteLine("Now we compare hands:"); _io.WriteLine("My hand:"); - DisplayHand(6); - (U, HS, IS, _playerHighCard, X) = AnalyzeHand(1); + _io.Write(_computerHand); + (X, I) = _playerHand.Analyze(0); _io.WriteLine(); - _io.Write("You have "); - DisplayHandRank(HS, IS, _playerHighCard); - _io.Write("and I have "); - DisplayHandRank(JS, KS, _computerHighCard); - if (B > U || _computerHighCard > _playerHighCard) { return ComputerWins().Value; } - if (U > B || _playerHighCard > _computerHighCard) { return PlayerWins().Value; } - _io.WriteLine("The hand is drawn."); - _io.WriteLine($"All ${_pot}remains in the pot."); + _io.Write($"You have {_playerHand.Name}"); + _io.Write($"and I have {_computerHand.Name}"); + if (_computerHand > _playerHand) { return ComputerWins().Value; } + if (_playerHand > _computerHand) { return PlayerWins().Value; } + _io.WriteLine("The hand is drawn."); + _io.WriteLine($"All ${_pot}remains in the pot."); } bool? IsThereAWinner() @@ -249,112 +225,6 @@ _1460: _io.WriteLine(); return ShouldContinue(); } - void DealCard(int index, int indexToReplace = 0) - { - _cards[index] = deck.Deal(); - if (index > 10) - { - (_cards[indexToReplace], _cards[index]) = (_cards[index], _cards[indexToReplace]); - } - return; - } - - void DisplayHand(int firstCard) - { - for (Z = firstCard; Z <= firstCard+4; Z++) - { - _io.Write($"{Z}-- {_cards[Z]}"); - if (Z % 2 == 0) - { - _io.WriteLine(); - } - } - _io.WriteLine(); - return; - } - - (int, string, string, Card, int) AnalyzeHand(int firstCard) - { - var suitMatchCount = 0; - for (var i = firstCard; i <= firstCard+4; i++) - { - if (i < firstCard+4 && _cards[i].Suit == _cards[i+1].Suit) - { - suitMatchCount++; - } - } - if (suitMatchCount == 4) - { - return (15, "A Flus", "h in", _cards[firstCard], 11111); - } - for (var i = firstCard; i <= firstCard+3; i++) - { - for (var j = i+1; j <= firstCard+4; j++) - { - if (_cards[i].Rank > _cards[j].Rank) - { - (_cards[i], _cards[j]) = (_cards[j], _cards[i]); - } - } - } - var handRank = 0; - var keepMask = 0; - Card highCard = default; - var handName1 = ""; - var handName2 = ""; - for (var i = firstCard; i <= firstCard+3; i++) - { - if (_cards[i].Rank == _cards[i+1].Rank) - { - keepMask += 11*(int)Math.Pow(10, i-firstCard); - highCard = _cards[i]; - (handRank, handName1, handName2) = AnalyzeMultiples(handRank, i); - } - } - if (keepMask == 0) - { - if (_cards[firstCard+3] - _cards[firstCard] == 3) - { - keepMask=1111; - handRank=10; - } - if (_cards[firstCard+4] - _cards[firstCard+1] == 3) - { - if (handRank == 10) - { - return (14, "Straig", "ht", _cards[firstCard+4], 11111); - } - handRank=10; - keepMask=11110; - } - } - if (handRank < 10) - { - I = 6; - return (9, "Schmal", "tz, ", _cards[firstCard+4], 11000); - } - else if (handRank == 10) - { - if (I == 1) { I = 6; } - } - else if (handRank <= 12 && highCard.Rank <= 6) - { - I = 6; - } - return (handRank, handName1, handName2, highCard, keepMask); - } - - (int, string, string) AnalyzeMultiples(int handStrength, int index) => - (handStrength, _cards[index].Rank == _cards[index - 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, ") - }; - bool GetWager() { _3060: _io.WriteLine(); @@ -418,13 +288,13 @@ _3340: return false; bool Line_3430() { V=G-K+Get0To9(); - if (CopmuterCantContinue()) { return true; } + if (ComputerCantContinue()) { return true; } _io.WriteLine($"I'll see you, and raise you{V}"); K=G+V; return GetWager(); } - bool CopmuterCantContinue() + bool ComputerCantContinue() { if (_computerBalance - G - V >= 0) { return false; } if (G == 0) @@ -454,21 +324,6 @@ _3340: return false; return true; } - void DisplayHandRank(string part1, string part2, Card highCard) - { - _io.Write($"{part1}{part2}"); - if (part1 == "A Flus") - { - _io.Write(highCard.Suit); - _io.WriteLine(); - } - else - { - _io.Write(highCard.Rank); - _io.WriteLine(part1 == "Schmal" || part1 == "Straig" ? " High" : "'s"); - } - } - bool PlayerCantRaiseFunds() { _io.WriteLine(); @@ -503,6 +358,152 @@ _3340: return false; } } +internal class Hand +{ + private readonly Card[] _cards; + private readonly Card _highCard; + private readonly string _name1; + private readonly string _name2; + private readonly int _keepMask; + private readonly Func _iTransform; + + public Hand(IEnumerable cards) + { + _cards = cards.ToArray(); + (Rank, _name1, _name2, _highCard, _keepMask, _iTransform) = Analyze(); + Name = GetHandName(); + } + + public string Name { get; } + public int Rank { get; } + + public Hand Replace(int cardNumber, Card newCard) + { + if (cardNumber < 1 || cardNumber > _cards.Length) { return this; } + + _cards[cardNumber - 1] = newCard; + return new Hand(_cards); + } + + public (int, int) Analyze(int i) => (_keepMask, _iTransform(i)); + + private (int, string, string, Card, int, Func) Analyze() + { + var suitMatchCount = 0; + for (var i = 0; i < _cards.Length; i++) + { + if (i < _cards.Length-1 && _cards[i].Suit == _cards[i+1].Suit) + { + suitMatchCount++; + } + } + if (suitMatchCount == 4) + { + return (15, "A Flus", "h in", _cards[0], 11111, x => x); + } + var sortedCards = _cards.OrderBy(c => c.Rank).ToArray(); + + var handRank = 0; + 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) + { + keepMask += 11*(int)Math.Pow(10, 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, ") + }; + } + } + if (keepMask == 0) + { + if (sortedCards[3] - sortedCards[0] == 3) + { + keepMask=1111; + handRank=10; + } + if (sortedCards[4] - sortedCards[1] == 3) + { + if (handRank == 10) + { + return (14, "Straig", "ht", sortedCards[4], 11111, x => x); + } + handRank=10; + keepMask=11110; + } + } + if (handRank < 10) + { + return (9, "Schmal", "tz, ", sortedCards[4], 11000, _ => 6); + } + var iTransform = Identity; + if (handRank == 10) + { + iTransform = To6If1; + } + else if (handRank <= 12 && highCard.Rank <= 6) + { + iTransform = To6; + } + return (handRank, handName1, handName2, highCard, keepMask, iTransform); + + int Identity(int x) => x; + int To6(int _) => 6; + int To6If1(int x) => x == 1 ? 6 : x; + } + + 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(); + } + + public override string ToString() + { + var sb = new StringBuilder(); + for (var i = 0; i < _cards.Length; i++) + { + var cardDisplay = $" {i+1} -- {_cards[i]}"; + // Emulates the effect of the BASIC PRINT statement using the ',' to align text to 14-char print zones + sb.Append(cardDisplay.PadRight(cardDisplay.Length + 14 - cardDisplay.Length % 14)); + if (i % 2 == 1) + { + sb.AppendLine(); + } + } + sb.AppendLine(); + return sb.ToString(); + } + + public static bool operator >(Hand x, Hand y) => + x.Rank > y.Rank || + x.Rank == y.Rank && x._highCard > y._highCard; + + public static bool operator <(Hand x, Hand y) => + x.Rank < y.Rank || + x.Rank == y.Rank && x._highCard < y._highCard; +} + internal enum Suit { Clubs, @@ -530,7 +531,9 @@ internal class Deck } } - public Card Deal() => _cards[_nextCard++]; + public Card DealCard() => _cards[_nextCard++]; + + public Hand DealHand() => new Hand(Enumerable.Range(0, 5).Select(_ => DealCard())); } internal record struct Card (Rank Rank, Suit Suit) @@ -543,26 +546,26 @@ internal record struct Card (Rank Rank, Suit Suit) public static int operator -(Card x, Card y) => x.Rank - y.Rank; } -internal struct Rank +internal struct Rank : IComparable { public static IEnumerable Ranks => new[] { Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten, Jack, Queen, King, Ace }; - public static Rank Two = new Rank(2); - public static Rank Three = new Rank(3); - public static Rank Four = new Rank(4); - public static Rank Five = new Rank(5); - public static Rank Six = new Rank(6); - public static Rank Seven = new Rank(7); - public static Rank Eight = new Rank(8); - public static Rank Nine = new Rank(9); - public static Rank Ten = new Rank(10); - public static Rank Jack = new Rank(11, "Jack"); - public static Rank Queen = new Rank(12, "Queen"); - public static Rank King = new Rank(13, "King"); - public static Rank Ace = new Rank(14, "Ace"); + public static Rank Two = new(2); + public static Rank Three = new(3); + public static Rank Four = new(4); + public static Rank Five = new(5); + public static Rank Six = new(6); + public static Rank Seven = new(7); + public static Rank Eight = new(8); + public static Rank Nine = new(9); + public static Rank Ten = new(10); + public static Rank Jack = new(11, "Jack"); + public static Rank Queen = new(12, "Queen"); + public static Rank King = new(13, "King"); + public static Rank Ace = new(14, "Ace"); private readonly int _value; private readonly string _name; @@ -575,6 +578,8 @@ internal struct Rank public override string ToString() => _name; + public int CompareTo(Rank other) => this - other; + public static bool operator <(Rank x, Rank y) => x._value < y._value; public static bool operator >(Rank x, Rank y) => x._value > y._value; public static bool operator ==(Rank x, Rank y) => x._value == y._value; From 3ff6a18082149d95538a364245f20f2d3f0e914a Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Tue, 31 May 2022 08:39:11 +1000 Subject: [PATCH 11/29] Simplify some variable names and usage --- 71_Poker/csharp/Games.cs | 107 ++++++++++++++++++++------------------- 1 file changed, 54 insertions(+), 53 deletions(-) diff --git a/71_Poker/csharp/Games.cs b/71_Poker/csharp/Games.cs index d24de695..41cd64ac 100644 --- a/71_Poker/csharp/Games.cs +++ b/71_Poker/csharp/Games.cs @@ -14,17 +14,17 @@ internal class Game private Hand _computerHand; private bool _hasWatch; - private float _computerBalance; - private float _playerBalance; - private float _pot; + private int _computerBalance; + private int _playerBalance; + private int _pot; - private float T; - private float G; + private float _playerBet; + private int _playerTotalBet; private int I; - private float Z; - private float X; - private float K; - private float V; + private int Z; + private int _keepMask; + private int _computerTotalBet; + private int V; public Game(IReadWrite io, IRandom random) { @@ -74,17 +74,17 @@ internal class Game _io.WriteLine("Your hand:"); _io.Write(_playerHand); - (X, I) = _computerHand.Analyze(2); + (_keepMask, I) = _computerHand.Analyze(2); _io.WriteLine(); _330: if (I!=6) { goto _470; } _340: if (Get0To9()<=7) { goto _370; } -_350: X=11100; +_350: _keepMask = 0b11100; _360: goto _420; _370: if (Get0To9()<=7) { goto _400; } -_380: X=11110; +_380: _keepMask = 0b11110; _390: goto _420; _400: if (Get0To9()>=1) { goto _450; } -_410: X=11111; +_410: _keepMask = 0b11111; _420: I=7; _430: Z=23; _440: goto _580; @@ -94,15 +94,15 @@ _470: if (_computerHand.Rank >= 13) { goto _540; } _480: if (Get0To9()>=2) { goto _500; } _490: goto _420; _500: Z=0; -_510: K=0; +_510: _computerTotalBet = 0; _520: _io.WriteLine("I check."); _530: goto _620; _540: Z = _computerHand.Rank <= 16 || Get0To9() < 1 ? 35 : 2; _580: V=Z+Get0To9(); _590: if (ComputerCantContinue()) { return false; } _600: _io.WriteLine($"I'll open with ${V}"); -_610: K=V; - G = 0; +_610: _computerTotalBet = V; + _playerTotalBet = 0; _620: if (GetWager()) { return false; } _630: var response = IsThereAWinner(); if (response.HasValue) { return response.Value; } @@ -126,7 +126,7 @@ _630: var response = IsThereAWinner(); var computerDrawCount = 0; for (var i = 1; i <= 5; i++) { - if ((int)(X/Math.Pow(10, i-1)) == 10*(int)(X/Math.Pow(10, i))) + if ((_keepMask & (1 << (i - 1))) == 0) { _computerHand = _computerHand.Replace(i, deck.DealCard()); computerDrawCount++; @@ -140,7 +140,7 @@ _630: var response = IsThereAWinner(); } _io.WriteLine(); V=I; - (X, I) = _computerHand.Analyze(1); + (_keepMask, I) = _computerHand.Analyze(1); if (V == 7) { Z = 28; @@ -164,10 +164,10 @@ _630: var response = IsThereAWinner(); Z = Get0To9() == 8 ? 11 : 19; } } -_1330: K=0; - G=0; +_1330: _computerTotalBet = 0; + _playerTotalBet = 0; _1340: if (GetWager()) { return false; } -_1350: if (T!=.5) { goto _1450; } +_1350: if (_playerBet!=.5) { goto _1450; } _1360: if (V==7) { goto _1400; } _1370: if (I!=6) { goto _1400; } _1380: _io.WriteLine("I'll check"); @@ -175,7 +175,7 @@ _1390: goto _1460; _1400: V=Z+Get0To9(); _1410: if (ComputerCantContinue()) { return false; } _1420: _io.WriteLine($"I'll bet ${V}"); -_1430: K=V; +_1430: _computerTotalBet = V; _1440: if (GetWager()) { return false; } _1450: response = IsThereAWinner(); if (response.HasValue) { return response.Value; } @@ -183,7 +183,7 @@ _1460: _io.WriteLine(); _io.WriteLine("Now we compare hands:"); _io.WriteLine("My hand:"); _io.Write(_computerHand); - (X, I) = _playerHand.Analyze(0); + _playerHand.Analyze(0); _io.WriteLine(); _io.Write($"You have {_playerHand.Name}"); _io.Write($"and I have {_computerHand.Name}"); @@ -228,31 +228,31 @@ _1460: _io.WriteLine(); bool GetWager() { _3060: _io.WriteLine(); - T = _io.ReadNumber("What is your bet"); -_3080: if ((T-(int)T)==0) { goto _3140; } -_3090: if (K!=0) { goto _3120; } -_3100: if (G!=0) { goto _3120; } -_3110: if (T==.5) { return false; } + _playerBet = _io.ReadNumber("What is your bet"); +_3080: if ((_playerBet - (int)_playerBet) == 0) { goto _3140; } +_3090: if (_computerTotalBet != 0) { goto _3120; } +_3100: if (_playerTotalBet != 0) { goto _3120; } +_3110: if (_playerBet == .5) { return false; } _3120: _io.WriteLine("No small change, please."); _3130: goto _3060; -_3140: if (_playerBalance-G-T>=0) { goto _3170; } +_3140: if (_playerBalance - _playerTotalBet - _playerBet>=0) { goto _3170; } _3150: if (PlayerCantRaiseFunds()) { return true; } _3160: goto _3060; -_3170: if (T!=0) { goto _3200; } +_3170: if (_playerBet != 0) { goto _3200; } _3180: I=3; _3190: return Line_3380(); -_3200: if (G+T>=K) { goto _3230; } +_3200: if (_playerTotalBet + _playerBet >= _computerTotalBet) { goto _3230; } _3210: _io.WriteLine("If you can't see my bet, then fold."); _3220: goto _3060; -_3230: G += T; -_3240: if (G==K) { return Line_3380(); } +_3230: _playerTotalBet += (int)_playerBet; +_3240: if (_playerTotalBet == _computerTotalBet) { return Line_3380(); } _3250: if (Z!=1) { return Line_3420(); } -_3260: if (G>5) { goto _3300; } +_3260: if (_playerTotalBet>5) { goto _3300; } _3270: if (Z>=2) { return Line_3350(); } _3280: V=5; _3290: return Line_3420(); _3300: if (Z==1) { goto _3320; } -_3310: if (T<=25) { return Line_3350(); } +_3310: if (_playerBet <= 25) { return Line_3350(); } _3320: I=4; _3330: _io.WriteLine("I fold."); _3340: return false; @@ -267,41 +267,41 @@ _3340: return false; bool Line_3360() { _io.WriteLine("I'll see you."); - K=G; + _computerTotalBet = _playerTotalBet; return Line_3380(); } bool Line_3380() { - _playerBalance -= G; - _computerBalance -= K; - _pot += G+K; + _playerBalance -= _playerTotalBet; + _computerBalance -= _computerTotalBet; + _pot += _playerTotalBet + _computerTotalBet; return false; } bool Line_3420() { - if (G>3*Z) { return Line_3350(); } + if (_playerTotalBet>3*Z) { return Line_3350(); } return Line_3430(); } bool Line_3430() { - V=G-K+Get0To9(); + V = _playerTotalBet - _computerTotalBet + Get0To9(); if (ComputerCantContinue()) { return true; } _io.WriteLine($"I'll see you, and raise you{V}"); - K=G+V; + _computerTotalBet = _playerTotalBet + V; return GetWager(); } bool ComputerCantContinue() { - if (_computerBalance - G - V >= 0) { return false; } - if (G == 0) + if (_computerBalance - _playerTotalBet - V >= 0) { return false; } + if (_playerTotalBet == 0) { V = _computerBalance; } - else if (_computerBalance - G >= 0) + else if (_computerBalance - _playerTotalBet >= 0) { return Line_3360(); } @@ -310,12 +310,13 @@ _3340: return false; var response = _io.ReadString("Would you like to buy back your watch for $50"); if (!response.StartsWith("N", InvariantCultureIgnoreCase)) { - // The original code did not deduct $50 from the player + // The original code does not deduct $50 from the player _computerBalance += 50; _hasWatch = true; + return false; } } - return false; + return CongratulatePlayer(); } bool CongratulatePlayer() @@ -399,7 +400,7 @@ internal class Hand } if (suitMatchCount == 4) { - return (15, "A Flus", "h in", _cards[0], 11111, x => x); + return (15, "A Flus", "h in", _cards[0], 0b11111, x => x); } var sortedCards = _cards.OrderBy(c => c.Rank).ToArray(); @@ -412,7 +413,7 @@ internal class Hand { if (sortedCards[i].Rank == sortedCards[i+1].Rank) { - keepMask += 11*(int)Math.Pow(10, i); + keepMask |= 0b11 << i; highCard = sortedCards[i]; (handRank, handName1, handName2) = (handRank, i > 0 && sortedCards[i].Rank == sortedCards[i - 1].Rank) switch @@ -430,22 +431,22 @@ internal class Hand { if (sortedCards[3] - sortedCards[0] == 3) { - keepMask=1111; + keepMask=0b1111; handRank=10; } if (sortedCards[4] - sortedCards[1] == 3) { if (handRank == 10) { - return (14, "Straig", "ht", sortedCards[4], 11111, x => x); + return (14, "Straig", "ht", sortedCards[4], 0b11111, x => x); } handRank=10; - keepMask=11110; + keepMask=0b11110; } } if (handRank < 10) { - return (9, "Schmal", "tz, ", sortedCards[4], 11000, _ => 6); + return (9, "Schmal", "tz, ", sortedCards[4], 0b11000, _ => 6); } var iTransform = Identity; if (handRank == 10) From b17aa1afba402f962d6f735d8366574b0392f064 Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Fri, 3 Jun 2022 08:40:47 +1000 Subject: [PATCH 12/29] Simplify more logic --- 71_Poker/csharp/Games.cs | 140 +++++++++++++++++++++++++-------------- 1 file changed, 92 insertions(+), 48 deletions(-) diff --git a/71_Poker/csharp/Games.cs b/71_Poker/csharp/Games.cs index 41cd64ac..e08c960f 100644 --- a/71_Poker/csharp/Games.cs +++ b/71_Poker/csharp/Games.cs @@ -18,13 +18,15 @@ internal class Game private int _playerBalance; private int _pot; - private float _playerBet; + private int _playerBet; private int _playerTotalBet; private int I; private int Z; private int _keepMask; private int _computerTotalBet; private int V; + private bool _playerFolds; + private bool _computerFolds; public Game(IReadWrite io, IRandom random) { @@ -53,6 +55,7 @@ internal class Game internal bool PlayHand(Deck deck) { + _playerFolds = _computerFolds = false; _pot=0; while(true) { @@ -104,8 +107,7 @@ _600: _io.WriteLine($"I'll open with ${V}"); _610: _computerTotalBet = V; _playerTotalBet = 0; _620: if (GetWager()) { return false; } -_630: var response = IsThereAWinner(); - if (response.HasValue) { return response.Value; } +_630: if (IsThereAWinner() is {} response) { return response; } _io.WriteLine(); var playerDrawCount = _io.ReadNumber( @@ -118,7 +120,7 @@ _630: var response = IsThereAWinner(); _io.WriteLine("What are their numbers:"); for (var i = 1; i <= playerDrawCount; i++) { - _playerHand = _playerHand.Replace((int)_io.ReadNumber(""), deck.DealCard()); + _playerHand = _playerHand.Replace((int)_io.ReadNumber(), deck.DealCard()); } _io.WriteLine("Your new hand:"); _io.Write(_playerHand); @@ -140,7 +142,7 @@ _630: var response = IsThereAWinner(); } _io.WriteLine(); V=I; - (_keepMask, I) = _computerHand.Analyze(1); + (_, I) = _computerHand.Analyze(1); if (V == 7) { Z = 28; @@ -167,7 +169,7 @@ _630: var response = IsThereAWinner(); _1330: _computerTotalBet = 0; _playerTotalBet = 0; _1340: if (GetWager()) { return false; } -_1350: if (_playerBet!=.5) { goto _1450; } +_1350: if (_playerBet != 0) { goto _1450; } _1360: if (V==7) { goto _1400; } _1370: if (I!=6) { goto _1400; } _1380: _io.WriteLine("I'll check"); @@ -177,8 +179,7 @@ _1410: if (ComputerCantContinue()) { return false; } _1420: _io.WriteLine($"I'll bet ${V}"); _1430: _computerTotalBet = V; _1440: if (GetWager()) { return false; } -_1450: response = IsThereAWinner(); - if (response.HasValue) { return response.Value; } +_1450: if (IsThereAWinner() is {} response2) { return response2; } _1460: _io.WriteLine(); _io.WriteLine("Now we compare hands:"); _io.WriteLine("My hand:"); @@ -190,19 +191,25 @@ _1460: _io.WriteLine(); if (_computerHand > _playerHand) { return ComputerWins().Value; } if (_playerHand > _computerHand) { return PlayerWins().Value; } _io.WriteLine("The hand is drawn."); - _io.WriteLine($"All ${_pot}remains in the pot."); + _io.WriteLine($"All $ {_pot} remains in the pot."); } bool? IsThereAWinner() { - if (I!=3) + if (_playerFolds) + { + _io.WriteLine(); + return ComputerWins(); + } + else if (_computerFolds) { - if (I!=4) { return null; } _io.WriteLine(); return PlayerWins(); } - _io.WriteLine(); - return ComputerWins(); + else + { + return null; + } } bool? ComputerWins() @@ -227,35 +234,42 @@ _1460: _io.WriteLine(); bool GetWager() { -_3060: _io.WriteLine(); - _playerBet = _io.ReadNumber("What is your bet"); -_3080: if ((_playerBet - (int)_playerBet) == 0) { goto _3140; } -_3090: if (_computerTotalBet != 0) { goto _3120; } -_3100: if (_playerTotalBet != 0) { goto _3120; } -_3110: if (_playerBet == .5) { return false; } -_3120: _io.WriteLine("No small change, please."); -_3130: goto _3060; -_3140: if (_playerBalance - _playerTotalBet - _playerBet>=0) { goto _3170; } -_3150: if (PlayerCantRaiseFunds()) { return true; } -_3160: goto _3060; -_3170: if (_playerBet != 0) { goto _3200; } -_3180: I=3; -_3190: return Line_3380(); -_3200: if (_playerTotalBet + _playerBet >= _computerTotalBet) { goto _3230; } -_3210: _io.WriteLine("If you can't see my bet, then fold."); -_3220: goto _3060; -_3230: _playerTotalBet += (int)_playerBet; -_3240: if (_playerTotalBet == _computerTotalBet) { return Line_3380(); } -_3250: if (Z!=1) { return Line_3420(); } -_3260: if (_playerTotalBet>5) { goto _3300; } -_3270: if (Z>=2) { return Line_3350(); } -_3280: V=5; -_3290: return Line_3420(); -_3300: if (Z==1) { goto _3320; } -_3310: if (_playerBet <= 25) { return Line_3350(); } -_3320: I=4; -_3330: _io.WriteLine("I fold."); -_3340: return false; + while(true) + { + if (_io.ReadPlayerAction(_computerTotalBet == 0 && _playerTotalBet == 0) is Bet bet) + { + if (_playerTotalBet + bet.Amount < _computerTotalBet) + { + _io.WriteLine("If you can't see my bet, then fold."); + continue; + } + if (_playerBalance - _playerTotalBet - bet.Amount >= 0) + { + _playerBet = bet.Amount; + _playerTotalBet += bet.Amount; + break; + } + if (PlayerCantRaiseFunds()) { return true; } + continue; + } + else + { + _playerFolds = true; + return UpdatePot(); + } + } + if (_playerTotalBet == _computerTotalBet) { return UpdatePot(); } + if (Z == 1) + { + if (_playerTotalBet > 5) + { + _computerFolds = true; + _io.WriteLine("I fold."); + return false; + } + V = 5; + } + return Line_3420(); } bool Line_3350() @@ -268,10 +282,10 @@ _3340: return false; { _io.WriteLine("I'll see you."); _computerTotalBet = _playerTotalBet; - return Line_3380(); + return UpdatePot(); } - bool Line_3380() + bool UpdatePot() { _playerBalance -= _playerTotalBet; _computerBalance -= _computerTotalBet; @@ -359,6 +373,16 @@ _3340: return false; } } +internal interface IAction { } +internal record Fold : IAction; +internal record Bet (int Amount) : IAction +{ + public Bet(float amount) + : this((int)amount) + { + } +} + internal class Hand { private readonly Card[] _cards; @@ -400,7 +424,7 @@ internal class Hand } if (suitMatchCount == 4) { - return (15, "A Flus", "h in", _cards[0], 0b11111, x => x); + return (15, "A Flus", "h in", _cards[0], 0b11111, Identity); } var sortedCards = _cards.OrderBy(c => c.Rank).ToArray(); @@ -438,7 +462,7 @@ internal class Hand { if (handRank == 10) { - return (14, "Straig", "ht", sortedCards[4], 0b11111, x => x); + return (14, "Straig", "ht", sortedCards[4], 0b11111, Identity); } handRank=10; keepMask=0b11110; @@ -446,7 +470,7 @@ internal class Hand } if (handRank < 10) { - return (9, "Schmal", "tz, ", sortedCards[4], 0b11000, _ => 6); + return (9, "Schmal", "tz, ", sortedCards[4], 0b11000, To6); } var iTransform = Identity; if (handRank == 10) @@ -530,6 +554,7 @@ internal class Deck var j = _random.Next(_cards.Length); (_cards[i], _cards[j]) = (_cards[j], _cards[i]); } + _nextCard = 0; } public Card DealCard() => _cards[_nextCard++]; @@ -605,14 +630,33 @@ internal static class IReadWriteExtensions } } + internal static float ReadNumber(this IReadWrite io) => io.ReadNumber(""); + internal static int ReadNumber(this IReadWrite io, string prompt, int max, string maxPrompt) { io.Write(prompt); while (true) { - var response = io.ReadNumber(""); + var response = io.ReadNumber(); if (response <= max) { return (int)response; } io.WriteLine(maxPrompt); } } + + internal static IAction ReadPlayerAction(this IReadWrite io, bool noCurrentBets) + { + while(true) + { + io.WriteLine(); + var bet = io.ReadNumber("What is your bet"); + if (bet != (int)bet) + { + if (noCurrentBets && bet == .5) { return new Bet(0); } + io.WriteLine("No small change, please."); + continue; + } + if (bet == 0) { return new Fold(); } + return new Bet(bet); + } + } } \ No newline at end of file From 5c7f5f644ec09cf074f6ac30982b203c013d5f26 Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Fri, 3 Jun 2022 08:42:21 +1000 Subject: [PATCH 13/29] Move classes to separate files --- 71_Poker/csharp/Card.cs | 11 + 71_Poker/csharp/Deck.cs | 28 +++ 71_Poker/csharp/Games.cs | 290 +----------------------- 71_Poker/csharp/Hand.cs | 149 ++++++++++++ 71_Poker/csharp/IReadWriteExtensions.cs | 47 ++++ 71_Poker/csharp/Rank.cs | 46 ++++ 71_Poker/csharp/Suit.cs | 9 + 7 files changed, 295 insertions(+), 285 deletions(-) create mode 100644 71_Poker/csharp/Card.cs create mode 100644 71_Poker/csharp/Deck.cs create mode 100644 71_Poker/csharp/Hand.cs create mode 100644 71_Poker/csharp/IReadWriteExtensions.cs create mode 100644 71_Poker/csharp/Rank.cs create mode 100644 71_Poker/csharp/Suit.cs diff --git a/71_Poker/csharp/Card.cs b/71_Poker/csharp/Card.cs new file mode 100644 index 00000000..95721142 --- /dev/null +++ b/71_Poker/csharp/Card.cs @@ -0,0 +1,11 @@ +namespace Poker; + +internal record struct Card (Rank Rank, Suit Suit) +{ + public override string ToString() => $"{Rank} of {Suit}"; + + public static bool operator <(Card x, Card y) => x.Rank < y.Rank; + public static bool operator >(Card x, Card y) => x.Rank > y.Rank; + + public static int operator -(Card x, Card y) => x.Rank - y.Rank; +} diff --git a/71_Poker/csharp/Deck.cs b/71_Poker/csharp/Deck.cs new file mode 100644 index 00000000..38a72244 --- /dev/null +++ b/71_Poker/csharp/Deck.cs @@ -0,0 +1,28 @@ +using static Poker.Rank; + +namespace Poker; + +internal class Deck +{ + private readonly Card[] _cards; + private int _nextCard; + + public Deck() + { + _cards = Ranks.SelectMany(r => Enum.GetValues().Select(s => new Card(r, s))).ToArray(); + } + + public void Shuffle(IRandom _random) + { + for (int i = 0; i < _cards.Length; i++) + { + var j = _random.Next(_cards.Length); + (_cards[i], _cards[j]) = (_cards[j], _cards[i]); + } + _nextCard = 0; + } + + public Card DealCard() => _cards[_nextCard++]; + + public Hand DealHand() => new Hand(Enumerable.Range(0, 5).Select(_ => DealCard())); +} diff --git a/71_Poker/csharp/Games.cs b/71_Poker/csharp/Games.cs index e08c960f..5ad7ae02 100644 --- a/71_Poker/csharp/Games.cs +++ b/71_Poker/csharp/Games.cs @@ -1,7 +1,5 @@ -using System.Text; using Poker.Resources; using static System.StringComparison; -using static Poker.Rank; namespace Poker; @@ -188,8 +186,8 @@ _1460: _io.WriteLine(); _io.WriteLine(); _io.Write($"You have {_playerHand.Name}"); _io.Write($"and I have {_computerHand.Name}"); - if (_computerHand > _playerHand) { return ComputerWins().Value; } - if (_playerHand > _computerHand) { return PlayerWins().Value; } + if (_computerHand > _playerHand) { return ComputerWins(); } + if (_playerHand > _computerHand) { return PlayerWins(); } _io.WriteLine("The hand is drawn."); _io.WriteLine($"All $ {_pot} remains in the pot."); } @@ -212,20 +210,20 @@ _1460: _io.WriteLine(); } } - bool? ComputerWins() + bool ComputerWins() { _io.WriteLine("I win."); _computerBalance += _pot; return ShouldContinue(); } - bool? ShouldContinue() + bool ShouldContinue() { _io.WriteLine($"Now I have ${_computerBalance}and you have ${_playerBalance}"); return _io.ReadYesNo("Do you wish to continue"); } - bool? PlayerWins() + bool PlayerWins() { _io.WriteLine("You win."); _playerBalance += _pot; @@ -382,281 +380,3 @@ internal record Bet (int Amount) : IAction { } } - -internal class Hand -{ - private readonly Card[] _cards; - private readonly Card _highCard; - private readonly string _name1; - private readonly string _name2; - private readonly int _keepMask; - private readonly Func _iTransform; - - public Hand(IEnumerable cards) - { - _cards = cards.ToArray(); - (Rank, _name1, _name2, _highCard, _keepMask, _iTransform) = Analyze(); - Name = GetHandName(); - } - - public string Name { get; } - public int Rank { get; } - - public Hand Replace(int cardNumber, Card newCard) - { - if (cardNumber < 1 || cardNumber > _cards.Length) { return this; } - - _cards[cardNumber - 1] = newCard; - return new Hand(_cards); - } - - public (int, int) Analyze(int i) => (_keepMask, _iTransform(i)); - - private (int, string, string, Card, int, Func) Analyze() - { - var suitMatchCount = 0; - for (var i = 0; i < _cards.Length; i++) - { - if (i < _cards.Length-1 && _cards[i].Suit == _cards[i+1].Suit) - { - suitMatchCount++; - } - } - if (suitMatchCount == 4) - { - return (15, "A Flus", "h in", _cards[0], 0b11111, Identity); - } - var sortedCards = _cards.OrderBy(c => c.Rank).ToArray(); - - var handRank = 0; - 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) - { - 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, ") - }; - } - } - if (keepMask == 0) - { - if (sortedCards[3] - sortedCards[0] == 3) - { - keepMask=0b1111; - handRank=10; - } - if (sortedCards[4] - sortedCards[1] == 3) - { - if (handRank == 10) - { - return (14, "Straig", "ht", sortedCards[4], 0b11111, Identity); - } - handRank=10; - keepMask=0b11110; - } - } - if (handRank < 10) - { - return (9, "Schmal", "tz, ", sortedCards[4], 0b11000, To6); - } - var iTransform = Identity; - if (handRank == 10) - { - iTransform = To6If1; - } - else if (handRank <= 12 && highCard.Rank <= 6) - { - iTransform = To6; - } - return (handRank, handName1, handName2, highCard, keepMask, iTransform); - - int Identity(int x) => x; - int To6(int _) => 6; - int To6If1(int x) => x == 1 ? 6 : x; - } - - 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(); - } - - public override string ToString() - { - var sb = new StringBuilder(); - for (var i = 0; i < _cards.Length; i++) - { - var cardDisplay = $" {i+1} -- {_cards[i]}"; - // Emulates the effect of the BASIC PRINT statement using the ',' to align text to 14-char print zones - sb.Append(cardDisplay.PadRight(cardDisplay.Length + 14 - cardDisplay.Length % 14)); - if (i % 2 == 1) - { - sb.AppendLine(); - } - } - sb.AppendLine(); - return sb.ToString(); - } - - public static bool operator >(Hand x, Hand y) => - x.Rank > y.Rank || - x.Rank == y.Rank && x._highCard > y._highCard; - - public static bool operator <(Hand x, Hand y) => - x.Rank < y.Rank || - x.Rank == y.Rank && x._highCard < y._highCard; -} - -internal enum Suit -{ - Clubs, - Diamonds, - Hearts, - Spades -} - -internal class Deck -{ - private readonly Card[] _cards; - private int _nextCard; - - public Deck() - { - _cards = Ranks.SelectMany(r => Enum.GetValues().Select(s => new Card(r, s))).ToArray(); - } - - public void Shuffle(IRandom _random) - { - for (int i = 0; i < _cards.Length; i++) - { - var j = _random.Next(_cards.Length); - (_cards[i], _cards[j]) = (_cards[j], _cards[i]); - } - _nextCard = 0; - } - - public Card DealCard() => _cards[_nextCard++]; - - public Hand DealHand() => new Hand(Enumerable.Range(0, 5).Select(_ => DealCard())); -} - -internal record struct Card (Rank Rank, Suit Suit) -{ - public override string ToString() => $"{Rank} of {Suit}"; - - public static bool operator <(Card x, Card y) => x.Rank < y.Rank; - public static bool operator >(Card x, Card y) => x.Rank > y.Rank; - - public static int operator -(Card x, Card y) => x.Rank - y.Rank; -} - -internal struct Rank : IComparable -{ - public static IEnumerable Ranks => new[] - { - Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten, Jack, Queen, King, Ace - }; - - public static Rank Two = new(2); - public static Rank Three = new(3); - public static Rank Four = new(4); - public static Rank Five = new(5); - public static Rank Six = new(6); - public static Rank Seven = new(7); - public static Rank Eight = new(8); - public static Rank Nine = new(9); - public static Rank Ten = new(10); - public static Rank Jack = new(11, "Jack"); - public static Rank Queen = new(12, "Queen"); - public static Rank King = new(13, "King"); - public static Rank Ace = new(14, "Ace"); - - private readonly int _value; - private readonly string _name; - - private Rank(int value, string? name = null) - { - _value = value; - _name = name ?? $" {value} "; - } - - public override string ToString() => _name; - - public int CompareTo(Rank other) => this - other; - - public static bool operator <(Rank x, Rank y) => x._value < y._value; - public static bool operator >(Rank x, Rank y) => x._value > y._value; - public static bool operator ==(Rank x, Rank y) => x._value == y._value; - public static bool operator !=(Rank x, Rank y) => x._value != y._value; - - public static int operator -(Rank x, Rank y) => x._value - y._value; - - public static bool operator <=(Rank rank, int value) => rank._value <= value; - public static bool operator >=(Rank rank, int value) => rank._value >= value; -} - -internal static class IReadWriteExtensions -{ - internal static bool ReadYesNo(this IReadWrite io, string prompt) - { - while (true) - { - var response = io.ReadString(prompt); - if (response.Equals("YES", InvariantCultureIgnoreCase)) { return true; } - if (response.Equals("NO", InvariantCultureIgnoreCase)) { return false; } - io.WriteLine("Answer Yes or No, please."); - } - } - - internal static float ReadNumber(this IReadWrite io) => io.ReadNumber(""); - - internal static int ReadNumber(this IReadWrite io, string prompt, int max, string maxPrompt) - { - io.Write(prompt); - while (true) - { - var response = io.ReadNumber(); - if (response <= max) { return (int)response; } - io.WriteLine(maxPrompt); - } - } - - internal static IAction ReadPlayerAction(this IReadWrite io, bool noCurrentBets) - { - while(true) - { - io.WriteLine(); - var bet = io.ReadNumber("What is your bet"); - if (bet != (int)bet) - { - if (noCurrentBets && bet == .5) { return new Bet(0); } - io.WriteLine("No small change, please."); - continue; - } - if (bet == 0) { return new Fold(); } - return new Bet(bet); - } - } -} \ No newline at end of file diff --git a/71_Poker/csharp/Hand.cs b/71_Poker/csharp/Hand.cs new file mode 100644 index 00000000..2064cb9b --- /dev/null +++ b/71_Poker/csharp/Hand.cs @@ -0,0 +1,149 @@ +using System.Text; + +namespace Poker; + +internal class Hand +{ + private readonly Card[] _cards; + private readonly Card _highCard; + private readonly string _name1; + private readonly string _name2; + private readonly int _keepMask; + private readonly Func _iTransform; + + public Hand(IEnumerable cards) + { + _cards = cards.ToArray(); + (Rank, _name1, _name2, _highCard, _keepMask, _iTransform) = Analyze(); + Name = GetHandName(); + } + + public string Name { get; } + public int Rank { get; } + + public Hand Replace(int cardNumber, Card newCard) + { + if (cardNumber < 1 || cardNumber > _cards.Length) { return this; } + + _cards[cardNumber - 1] = newCard; + return new Hand(_cards); + } + + public (int, int) Analyze(int i) => (_keepMask, _iTransform(i)); + + private (int, string, string, Card, int, Func) Analyze() + { + var suitMatchCount = 0; + for (var i = 0; i < _cards.Length; i++) + { + if (i < _cards.Length-1 && _cards[i].Suit == _cards[i+1].Suit) + { + suitMatchCount++; + } + } + if (suitMatchCount == 4) + { + return (15, "A Flus", "h in", _cards[0], 0b11111, Identity); + } + var sortedCards = _cards.OrderBy(c => c.Rank).ToArray(); + + var handRank = 0; + 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) + { + 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, ") + }; + } + } + if (keepMask == 0) + { + if (sortedCards[3] - sortedCards[0] == 3) + { + keepMask=0b1111; + handRank=10; + } + if (sortedCards[4] - sortedCards[1] == 3) + { + if (handRank == 10) + { + return (14, "Straig", "ht", sortedCards[4], 0b11111, Identity); + } + handRank=10; + keepMask=0b11110; + } + } + if (handRank < 10) + { + return (9, "Schmal", "tz, ", sortedCards[4], 0b11000, To6); + } + var iTransform = Identity; + if (handRank == 10) + { + iTransform = To6If1; + } + else if (handRank <= 12 && highCard.Rank <= 6) + { + iTransform = To6; + } + return (handRank, handName1, handName2, highCard, keepMask, iTransform); + + int Identity(int x) => x; + int To6(int _) => 6; + int To6If1(int x) => x == 1 ? 6 : x; + } + + 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(); + } + + public override string ToString() + { + var sb = new StringBuilder(); + for (var i = 0; i < _cards.Length; i++) + { + var cardDisplay = $" {i+1} -- {_cards[i]}"; + // Emulates the effect of the BASIC PRINT statement using the ',' to align text to 14-char print zones + sb.Append(cardDisplay.PadRight(cardDisplay.Length + 14 - cardDisplay.Length % 14)); + if (i % 2 == 1) + { + sb.AppendLine(); + } + } + sb.AppendLine(); + return sb.ToString(); + } + + public static bool operator >(Hand x, Hand y) => + x.Rank > y.Rank || + x.Rank == y.Rank && x._highCard > y._highCard; + + public static bool operator <(Hand x, Hand y) => + x.Rank < y.Rank || + x.Rank == y.Rank && x._highCard < y._highCard; +} diff --git a/71_Poker/csharp/IReadWriteExtensions.cs b/71_Poker/csharp/IReadWriteExtensions.cs new file mode 100644 index 00000000..829c6719 --- /dev/null +++ b/71_Poker/csharp/IReadWriteExtensions.cs @@ -0,0 +1,47 @@ +using static System.StringComparison; + +namespace Poker; + +internal static class IReadWriteExtensions +{ + internal static bool ReadYesNo(this IReadWrite io, string prompt) + { + while (true) + { + var response = io.ReadString(prompt); + if (response.Equals("YES", InvariantCultureIgnoreCase)) { return true; } + if (response.Equals("NO", InvariantCultureIgnoreCase)) { return false; } + io.WriteLine("Answer Yes or No, please."); + } + } + + internal static float ReadNumber(this IReadWrite io) => io.ReadNumber(""); + + internal static int ReadNumber(this IReadWrite io, string prompt, int max, string maxPrompt) + { + io.Write(prompt); + while (true) + { + var response = io.ReadNumber(); + if (response <= max) { return (int)response; } + io.WriteLine(maxPrompt); + } + } + + internal static IAction ReadPlayerAction(this IReadWrite io, bool noCurrentBets) + { + while(true) + { + io.WriteLine(); + var bet = io.ReadNumber("What is your bet"); + if (bet != (int)bet) + { + if (noCurrentBets && bet == .5) { return new Bet(0); } + io.WriteLine("No small change, please."); + continue; + } + if (bet == 0) { return new Fold(); } + return new Bet(bet); + } + } +} \ No newline at end of file diff --git a/71_Poker/csharp/Rank.cs b/71_Poker/csharp/Rank.cs new file mode 100644 index 00000000..ab642cd4 --- /dev/null +++ b/71_Poker/csharp/Rank.cs @@ -0,0 +1,46 @@ +namespace Poker; + +internal struct Rank : IComparable +{ + public static IEnumerable Ranks => new[] + { + Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten, Jack, Queen, King, Ace + }; + + public static Rank Two = new(2); + public static Rank Three = new(3); + public static Rank Four = new(4); + public static Rank Five = new(5); + public static Rank Six = new(6); + public static Rank Seven = new(7); + public static Rank Eight = new(8); + public static Rank Nine = new(9); + public static Rank Ten = new(10); + public static Rank Jack = new(11, "Jack"); + public static Rank Queen = new(12, "Queen"); + public static Rank King = new(13, "King"); + public static Rank Ace = new(14, "Ace"); + + private readonly int _value; + private readonly string _name; + + private Rank(int value, string? name = null) + { + _value = value; + _name = name ?? $" {value} "; + } + + public override string ToString() => _name; + + public int CompareTo(Rank other) => this - other; + + public static bool operator <(Rank x, Rank y) => x._value < y._value; + public static bool operator >(Rank x, Rank y) => x._value > y._value; + public static bool operator ==(Rank x, Rank y) => x._value == y._value; + public static bool operator !=(Rank x, Rank y) => x._value != y._value; + + public static int operator -(Rank x, Rank y) => x._value - y._value; + + public static bool operator <=(Rank rank, int value) => rank._value <= value; + public static bool operator >=(Rank rank, int value) => rank._value >= value; +} diff --git a/71_Poker/csharp/Suit.cs b/71_Poker/csharp/Suit.cs new file mode 100644 index 00000000..616febb3 --- /dev/null +++ b/71_Poker/csharp/Suit.cs @@ -0,0 +1,9 @@ +namespace Poker; + +internal enum Suit +{ + Clubs, + Diamonds, + Hearts, + Spades +} From 0ba82dc9c4fe5d6324a68e422dd6f5cdddb6b21d Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Fri, 3 Jun 2022 17:47:40 +1000 Subject: [PATCH 14/29] Remove more gotos and labels --- 71_Poker/csharp/Games.cs | 39 +++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/71_Poker/csharp/Games.cs b/71_Poker/csharp/Games.cs index 5ad7ae02..e3d9d7ed 100644 --- a/71_Poker/csharp/Games.cs +++ b/71_Poker/csharp/Games.cs @@ -105,7 +105,7 @@ _600: _io.WriteLine($"I'll open with ${V}"); _610: _computerTotalBet = V; _playerTotalBet = 0; _620: if (GetWager()) { return false; } -_630: if (IsThereAWinner() is {} response) { return response; } +_630: if (CheckIfSomeoneFolded() is {} response) { return response; } _io.WriteLine(); var playerDrawCount = _io.ReadNumber( @@ -164,21 +164,27 @@ _630: if (IsThereAWinner() is {} response) { return response; } Z = Get0To9() == 8 ? 11 : 19; } } -_1330: _computerTotalBet = 0; + _computerTotalBet = 0; _playerTotalBet = 0; -_1340: if (GetWager()) { return false; } -_1350: if (_playerBet != 0) { goto _1450; } -_1360: if (V==7) { goto _1400; } -_1370: if (I!=6) { goto _1400; } -_1380: _io.WriteLine("I'll check"); -_1390: goto _1460; -_1400: V=Z+Get0To9(); -_1410: if (ComputerCantContinue()) { return false; } -_1420: _io.WriteLine($"I'll bet ${V}"); -_1430: _computerTotalBet = V; -_1440: if (GetWager()) { return false; } -_1450: if (IsThereAWinner() is {} response2) { return response2; } -_1460: _io.WriteLine(); + if (GetWager()) { return false; } + if (_playerBet != 0) + { + if (CheckIfSomeoneFolded() is {} response2) { return response2; } + } + else if (V != 7 && I == 6) + { + _io.WriteLine("I'll check"); + } + else + { + V=Z+Get0To9(); + if (ComputerCantContinue()) { return false; } + _io.WriteLine($"I'll bet ${V}"); + _computerTotalBet = V; + if (GetWager()) { return false; } + if (CheckIfSomeoneFolded() is {} response3) { return response3; } + } + _io.WriteLine(); _io.WriteLine("Now we compare hands:"); _io.WriteLine("My hand:"); _io.Write(_computerHand); @@ -192,7 +198,7 @@ _1460: _io.WriteLine(); _io.WriteLine($"All $ {_pot} remains in the pot."); } - bool? IsThereAWinner() + bool? CheckIfSomeoneFolded() { if (_playerFolds) { @@ -232,6 +238,7 @@ _1460: _io.WriteLine(); bool GetWager() { + _playerBet = 0; while(true) { if (_io.ReadPlayerAction(_computerTotalBet == 0 && _playerTotalBet == 0) is Bet bet) From b31c0194b29fb68c755d3a80245023c365a7a2c8 Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Wed, 8 Jun 2022 21:35:46 +1000 Subject: [PATCH 15/29] Add Table and Player abstractions --- 71_Poker/csharp/Games.cs | 295 ++++++++++++++++++++++++++------------- 71_Poker/csharp/Hand.cs | 19 ++- 2 files changed, 211 insertions(+), 103 deletions(-) diff --git a/71_Poker/csharp/Games.cs b/71_Poker/csharp/Games.cs index e3d9d7ed..3035fbbf 100644 --- a/71_Poker/csharp/Games.cs +++ b/71_Poker/csharp/Games.cs @@ -8,19 +8,12 @@ internal class Game private readonly IReadWrite _io; private readonly IRandom _random; - private Hand _playerHand; - private Hand _computerHand; - private bool _hasWatch; - private int _computerBalance; - private int _playerBalance; - private int _pot; private int _playerBet; private int _playerTotalBet; private int I; private int Z; - private int _keepMask; private int _computerTotalBet; private int V; private bool _playerFolds; @@ -37,110 +30,96 @@ internal class Game internal void Play() { var deck = new Deck(); + var human = new Human(200); + var computer = new Computer(200); + var table = new Table(_io, deck, human, computer); _io.Write(Resource.Streams.Title); _io.Write(Resource.Streams.Instructions); _hasWatch = true; - _computerBalance = 200; - _playerBalance = 200; do { deck.Shuffle(_random); - } while (PlayHand(deck)); + } while (PlayHand(table)); } - internal bool PlayHand(Deck deck) + internal bool PlayHand(Table table) { _playerFolds = _computerFolds = false; - _pot=0; + table.Pot=0; while(true) { _io.WriteLine(); - if (_computerBalance<=5) + if (table.Computer.Balance<=5) { CongratulatePlayer(); return false; } _io.WriteLine("The ante is $5. I will deal:"); _io.WriteLine(); - if (_playerBalance <= 5 && PlayerCantRaiseFunds()) { return false; } - _pot += 10; + if (table.Human.Balance <= 5 && PlayerCantRaiseFunds()) { return false; } - _playerBalance -= 5; - _computerBalance -= 5; - _playerHand = deck.DealHand(); - _computerHand = deck.DealHand(); + table.Deal(); - _io.WriteLine("Your hand:"); - _io.Write(_playerHand); - (_keepMask, I) = _computerHand.Analyze(2); + (table.Computer.KeepMask, I) = table.Computer.Hand.Analyze(2); _io.WriteLine(); -_330: if (I!=6) { goto _470; } -_340: if (Get0To9()<=7) { goto _370; } -_350: _keepMask = 0b11100; -_360: goto _420; -_370: if (Get0To9()<=7) { goto _400; } -_380: _keepMask = 0b11110; -_390: goto _420; -_400: if (Get0To9()>=1) { goto _450; } -_410: _keepMask = 0b11111; -_420: I=7; -_430: Z=23; -_440: goto _580; -_450: Z=1; -_460: goto _510; -_470: if (_computerHand.Rank >= 13) { goto _540; } -_480: if (Get0To9()>=2) { goto _500; } -_490: goto _420; -_500: Z=0; -_510: _computerTotalBet = 0; -_520: _io.WriteLine("I check."); -_530: goto _620; -_540: Z = _computerHand.Rank <= 16 || Get0To9() < 1 ? 35 : 2; -_580: V=Z+Get0To9(); -_590: if (ComputerCantContinue()) { return false; } -_600: _io.WriteLine($"I'll open with ${V}"); -_610: _computerTotalBet = V; - _playerTotalBet = 0; -_620: if (GetWager()) { return false; } -_630: if (CheckIfSomeoneFolded() is {} response) { return response; } - - _io.WriteLine(); - var playerDrawCount = _io.ReadNumber( - "Now we draw -- How many cards do you want", - 3, - "You can't draw more than three cards."); - if (playerDrawCount != 0) + if (I == 6) { - Z=10; - _io.WriteLine("What are their numbers:"); - for (var i = 1; i <= playerDrawCount; i++) + Z=1; + if (Get0To9() > 7) { - _playerHand = _playerHand.Replace((int)_io.ReadNumber(), deck.DealCard()); + table.Computer.KeepMask = 0b11100; + I=7; + Z=23; } - _io.WriteLine("Your new hand:"); - _io.Write(_playerHand); - } - var computerDrawCount = 0; - for (var i = 1; i <= 5; i++) - { - if ((_keepMask & (1 << (i - 1))) == 0) + else if (Get0To9() > 7) { - _computerHand = _computerHand.Replace(i, deck.DealCard()); - computerDrawCount++; + table.Computer.KeepMask = 0b11110; + I=7; + Z=23; + } + else if (Get0To9() < 1) + { + table.Computer.KeepMask = 0b11111; + I=7; + Z=23; } } - _io.WriteLine(); - _io.Write($"I am taking {computerDrawCount} card"); - if (computerDrawCount != 1) + else { - _io.WriteLine("s"); + Z=0; + if (table.Computer.Hand.Rank >= 13) + { + Z = table.Computer.Hand.Rank <= 16 || Get0To9() < 1 ? 35 : 2; + } + else if (Get0To9() < 2) + { + I=7; + Z=23; + } } - _io.WriteLine(); + if (Z <= 1) + { + _computerTotalBet = 0; + _io.WriteLine("I check."); + } + else + { + V=Z+Get0To9(); + if (ComputerCantContinue()) { return false; } + _io.WriteLine($"I'll open with ${V}"); + _computerTotalBet = V; + _playerTotalBet = 0; + } + if (GetWager()) { return false; } + if (CheckIfSomeoneFolded() is {} response) { return response; } + + table.Draw(); + V=I; - (_, I) = _computerHand.Analyze(1); + (_, I) = table.Computer.Hand.Analyze(1); if (V == 7) { Z = 28; @@ -149,13 +128,13 @@ _630: if (CheckIfSomeoneFolded() is {} response) { return response; } { Z = 1; } - else if (_computerHand.Rank < 13) + else if (table.Computer.Hand.Rank < 13) { Z = Get0To9() == 6 ? 19 : 2; } else { - if (_computerHand.Rank >= 16) + if (table.Computer.Hand.Rank >= 16) { Z = 2; } @@ -187,15 +166,15 @@ _630: if (CheckIfSomeoneFolded() is {} response) { return response; } _io.WriteLine(); _io.WriteLine("Now we compare hands:"); _io.WriteLine("My hand:"); - _io.Write(_computerHand); - _playerHand.Analyze(0); + _io.Write(table.Computer.Hand); + table.Human.Hand.Analyze(0); _io.WriteLine(); - _io.Write($"You have {_playerHand.Name}"); - _io.Write($"and I have {_computerHand.Name}"); - if (_computerHand > _playerHand) { return ComputerWins(); } - if (_playerHand > _computerHand) { return PlayerWins(); } + _io.Write($"You have {table.Human.Hand.Name}"); + _io.Write($"and I have {table.Computer.Hand.Name}"); + if (table.Computer.Hand > table.Human.Hand) { return ComputerWins(); } + if (table.Human.Hand > table.Computer.Hand) { return PlayerWins(); } _io.WriteLine("The hand is drawn."); - _io.WriteLine($"All $ {_pot} remains in the pot."); + _io.WriteLine($"All $ {table.Pot} remains in the pot."); } bool? CheckIfSomeoneFolded() @@ -219,20 +198,20 @@ _630: if (CheckIfSomeoneFolded() is {} response) { return response; } bool ComputerWins() { _io.WriteLine("I win."); - _computerBalance += _pot; + table.Computer.Balance += table.Pot; return ShouldContinue(); } bool ShouldContinue() { - _io.WriteLine($"Now I have ${_computerBalance}and you have ${_playerBalance}"); + _io.WriteLine($"Now I have ${table.Computer.Balance}and you have ${table.Human.Balance}"); return _io.ReadYesNo("Do you wish to continue"); } bool PlayerWins() { _io.WriteLine("You win."); - _playerBalance += _pot; + table.Human.Balance += table.Pot; return ShouldContinue(); } @@ -248,7 +227,7 @@ _630: if (CheckIfSomeoneFolded() is {} response) { return response; } _io.WriteLine("If you can't see my bet, then fold."); continue; } - if (_playerBalance - _playerTotalBet - bet.Amount >= 0) + if (table.Human.Balance - _playerTotalBet - bet.Amount >= 0) { _playerBet = bet.Amount; _playerTotalBet += bet.Amount; @@ -292,9 +271,9 @@ _630: if (CheckIfSomeoneFolded() is {} response) { return response; } bool UpdatePot() { - _playerBalance -= _playerTotalBet; - _computerBalance -= _computerTotalBet; - _pot += _playerTotalBet + _computerTotalBet; + table.Human.Balance -= _playerTotalBet; + table.Computer.Balance -= _computerTotalBet; + table.Pot += _playerTotalBet + _computerTotalBet; return false; } @@ -315,12 +294,12 @@ _630: if (CheckIfSomeoneFolded() is {} response) { return response; } bool ComputerCantContinue() { - if (_computerBalance - _playerTotalBet - V >= 0) { return false; } + if (table.Computer.Balance - _playerTotalBet - V >= 0) { return false; } if (_playerTotalBet == 0) { - V = _computerBalance; + V = table.Computer.Balance; } - else if (_computerBalance - _playerTotalBet >= 0) + else if (table.Computer.Balance - _playerTotalBet >= 0) { return Line_3360(); } @@ -330,7 +309,7 @@ _630: if (CheckIfSomeoneFolded() is {} response) { return response; } if (!response.StartsWith("N", InvariantCultureIgnoreCase)) { // The original code does not deduct $50 from the player - _computerBalance += 50; + table.Computer.Balance += 50; _hasWatch = true; return false; } @@ -357,12 +336,12 @@ _630: if (CheckIfSomeoneFolded() is {} response) { return response; } if (Get0To9() < 7) { _io.WriteLine("I'll give you $75 for it."); - _playerBalance += 75; + table.Human.Balance += 75; } else { _io.WriteLine("That's a pretty crummy watch - I'll give you $25."); - _playerBalance += 25; + table.Human.Balance += 25; } _hasWatch = false; return false; @@ -387,3 +366,121 @@ internal record Bet (int Amount) : IAction { } } + +internal abstract class Player +{ + 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 void Pay(int amount) + { + Balance -= amount; + } +} + +internal class Human : Player +{ + public Human(int bank) + : base(bank) + { + } + + public void DrawCards(Deck deck, IReadWrite io) + { + var count = io.ReadNumber( + "Now we draw -- 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); + } +} + +internal class Computer : Player +{ + public Computer(int bank) + : base(bank) + { + } + + public int KeepMask { get; set; } + + public void DrawCards(Deck deck, IReadWrite io) + { + 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"); + } + } +} + +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; + } + + public Human Human { get; } + public Computer Computer { get; } + + public void Deal() + { + Pot += 10; + Human.Pay(5); + Computer.Pay(5); + + Human.Hand = _deck.DealHand(); + Computer.Hand = _deck.DealHand(); + + _io.WriteLine("Your hand:"); + _io.Write(Human.Hand); + } + + public void Draw() + { + _io.WriteLine(); + Human.DrawCards(_deck, _io); + Computer.DrawCards(_deck, _io); + _io.WriteLine(); + } + + public void AcceptBets() + { + + } +} \ No newline at end of file diff --git a/71_Poker/csharp/Hand.cs b/71_Poker/csharp/Hand.cs index 2064cb9b..c806e490 100644 --- a/71_Poker/csharp/Hand.cs +++ b/71_Poker/csharp/Hand.cs @@ -4,6 +4,8 @@ namespace Poker; internal class Hand { + public static readonly Hand Empty = new Hand(); + private readonly Card[] _cards; private readonly Card _highCard; private readonly string _name1; @@ -11,6 +13,15 @@ internal class Hand private readonly int _keepMask; private readonly Func _iTransform; + private Hand() + { + _cards = Array.Empty(); + _name1 = ""; + _name2 = ""; + _iTransform = Identity; + Name = ""; + } + public Hand(IEnumerable cards) { _cards = cards.ToArray(); @@ -101,12 +112,12 @@ internal class Hand iTransform = To6; } return (handRank, handName1, handName2, highCard, keepMask, iTransform); - - int Identity(int x) => x; - int To6(int _) => 6; - int To6If1(int x) => x == 1 ? 6 : x; } + private int Identity(int x) => x; + private int To6(int _) => 6; + private int To6If1(int x) => x == 1 ? 6 : x; + private string GetHandName() { var sb = new StringBuilder(_name1).Append(_name2); From 6a08b747971d739dc4199ce54a49989d6fd78b4b Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Wed, 15 Jun 2022 21:04:27 +1000 Subject: [PATCH 16/29] Move watch transactions to player classes --- 71_Poker/csharp/Games.cs | 93 ++++++++++++++++++++++++---------------- 1 file changed, 55 insertions(+), 38 deletions(-) diff --git a/71_Poker/csharp/Games.cs b/71_Poker/csharp/Games.cs index 3035fbbf..28d69e2e 100644 --- a/71_Poker/csharp/Games.cs +++ b/71_Poker/csharp/Games.cs @@ -8,7 +8,6 @@ internal class Game private readonly IReadWrite _io; private readonly IRandom _random; - private bool _hasWatch; private int _playerBet; private int _playerTotalBet; @@ -37,8 +36,6 @@ internal class Game _io.Write(Resource.Streams.Title); _io.Write(Resource.Streams.Instructions); - _hasWatch = true; - do { deck.Shuffle(_random); @@ -59,7 +56,7 @@ internal class Game } _io.WriteLine("The ante is $5. I will deal:"); _io.WriteLine(); - if (table.Human.Balance <= 5 && PlayerCantRaiseFunds()) { return false; } + if (table.Human.Balance <= 5 && PlayerIsBroke()) { return false; } table.Deal(); @@ -233,7 +230,7 @@ internal class Game _playerTotalBet += bet.Amount; break; } - if (PlayerCantRaiseFunds()) { return true; } + if (PlayerIsBroke()) { return true; } continue; } else @@ -303,16 +300,9 @@ internal class Game { return Line_3360(); } - else if (!_hasWatch) + else if (table.Computer.TrySellWatch(table.Human, _io)) { - var response = _io.ReadString("Would you like to buy back your watch for $50"); - if (!response.StartsWith("N", InvariantCultureIgnoreCase)) - { - // The original code does not deduct $50 from the player - table.Computer.Balance += 50; - _hasWatch = true; - return false; - } + return false; } return CongratulatePlayer(); } @@ -323,30 +313,12 @@ internal class Game return true; } - bool PlayerCantRaiseFunds() + bool PlayerIsBroke() { _io.WriteLine(); _io.WriteLine("You can't bet with what you haven't got."); - if (_hasWatch) - { - var response = _io.ReadString("Would you like to sell your watch"); - if (!response.StartsWith("N", InvariantCultureIgnoreCase)) - { - if (Get0To9() < 7) - { - _io.WriteLine("I'll give you $75 for it."); - table.Human.Balance += 75; - } - else - { - _io.WriteLine("That's a pretty crummy watch - I'll give you $25."); - table.Human.Balance += 25; - } - _hasWatch = false; - return false; - } - } + if (Computer.TryBuyWatch(table.Human, _io, _random)) { 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. @@ -390,14 +362,14 @@ internal class Human : Player public Human(int bank) : base(bank) { + HasWatch = true; } + public bool HasWatch { get; set; } + public void DrawCards(Deck deck, IReadWrite io) { - var count = io.ReadNumber( - "Now we draw -- How many cards do you want", - 3, - "You can't draw more than three cards."); + 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:"); @@ -409,6 +381,18 @@ internal class Human : Player io.WriteLine("Your new hand:"); io.Write(Hand); } + + 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; + } } internal class Computer : Player @@ -439,6 +423,38 @@ internal class Computer : Player io.WriteLine("s"); } } + + public static bool TryBuyWatch(Human human, IReadWrite io, IRandom random) + { + 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); + + return true; + } + + public bool TrySellWatch(Human human, IReadWrite io) + { + 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; + } } internal class Table @@ -474,6 +490,7 @@ internal class Table public void Draw() { _io.WriteLine(); + _io.Write("Now we draw -- "); Human.DrawCards(_deck, _io); Computer.DrawCards(_deck, _io); _io.WriteLine(); From ac079fff75860b4995af26b0bcd3a22c4fd31bac Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Fri, 17 Jun 2022 23:44:09 +1000 Subject: [PATCH 17/29] Simplify hand analysis --- 71_Poker/csharp/Games.cs | 335 +++++++++++++++++++++------------------ 71_Poker/csharp/Hand.cs | 57 +++---- 2 files changed, 201 insertions(+), 191 deletions(-) diff --git a/71_Poker/csharp/Games.cs b/71_Poker/csharp/Games.cs index 28d69e2e..099690d0 100644 --- a/71_Poker/csharp/Games.cs +++ b/71_Poker/csharp/Games.cs @@ -8,15 +8,11 @@ internal class Game private readonly IReadWrite _io; private readonly IRandom _random; - private int _playerBet; private int _playerTotalBet; - private int I; private int Z; private int _computerTotalBet; private int V; - private bool _playerFolds; - private bool _computerFolds; public Game(IReadWrite io, IRandom random) { @@ -29,8 +25,8 @@ internal class Game internal void Play() { var deck = new Deck(); - var human = new Human(200); - var computer = new Computer(200); + var human = new Human(200, _io); + var computer = new Computer(200, _io, _random); var table = new Table(_io, deck, human, computer); _io.Write(Resource.Streams.Title); @@ -44,8 +40,6 @@ internal class Game internal bool PlayHand(Table table) { - _playerFolds = _computerFolds = false; - table.Pot=0; while(true) { _io.WriteLine(); @@ -56,47 +50,23 @@ internal class Game } _io.WriteLine("The ante is $5. I will deal:"); _io.WriteLine(); - if (table.Human.Balance <= 5 && PlayerIsBroke()) { return false; } + if (table.Human.Balance <= 5 && table.Human.IsBroke()) { return false; } table.Deal(); - (table.Computer.KeepMask, I) = table.Computer.Hand.Analyze(2); _io.WriteLine(); - if (I == 6) + Z = table.Computer.Hand.Rank switch { - Z=1; - if (Get0To9() > 7) - { - table.Computer.KeepMask = 0b11100; - I=7; - Z=23; - } - else if (Get0To9() > 7) - { - table.Computer.KeepMask = 0b11110; - I=7; - Z=23; - } - else if (Get0To9() < 1) - { - table.Computer.KeepMask = 0b11111; - I=7; - Z=23; - } - } - else - { - Z=0; - if (table.Computer.Hand.Rank >= 13) - { - Z = table.Computer.Hand.Rank <= 16 || Get0To9() < 1 ? 35 : 2; - } - else if (Get0To9() < 2) - { - I=7; - Z=23; - } - } + _ when table.Computer.Hand.IsWeak => + table.Computer.BluffIf(Get0To9() > 7, 0b11100) ?? + table.Computer.BluffIf(Get0To9() > 7, 0b11110) ?? + table.Computer.BluffIf(Get0To9() < 1, 0b11111) ?? + 1, + < 13 => table.Computer.BluffIf(Get0To9() < 2) ?? 0, + <= 16 => 35, + _ when Get0To9() < 1 => 35, + _ => 2 + }; if (Z <= 1) { _computerTotalBet = 0; @@ -111,43 +81,27 @@ internal class Game _playerTotalBet = 0; } if (GetWager()) { return false; } - if (CheckIfSomeoneFolded() is {} response) { return response; } + if (table.SomeoneHasFolded()) { return ShouldContinue(); } table.Draw(); - V=I; - (_, I) = table.Computer.Hand.Analyze(1); - if (V == 7) + Z = table.Computer.Hand.Rank switch { - Z = 28; - } - else if (I == 6) - { - Z = 1; - } - else if (table.Computer.Hand.Rank < 13) - { - Z = Get0To9() == 6 ? 19 : 2; - } - else - { - if (table.Computer.Hand.Rank >= 16) - { - Z = 2; - } - else - { - Z = Get0To9() == 8 ? 11 : 19; - } - } + _ when table.Computer.IsBluffing => 28, + _ when table.Computer.Hand.IsWeak => 1, + < 13 => Get0To9() == 0 ? 19 : 2, + < 16 => Get0To9() == 8 ? 11 : 19, + _ => 2 + }; + _computerTotalBet = 0; _playerTotalBet = 0; if (GetWager()) { return false; } if (_playerBet != 0) { - if (CheckIfSomeoneFolded() is {} response2) { return response2; } + if (table.SomeoneHasFolded()) { return ShouldContinue(); } } - else if (V != 7 && I == 6) + else if (!table.Computer.IsBluffing && table.Computer.Hand.IsWeak) { _io.WriteLine("I'll check"); } @@ -158,60 +112,21 @@ internal class Game _io.WriteLine($"I'll bet ${V}"); _computerTotalBet = V; if (GetWager()) { return false; } - if (CheckIfSomeoneFolded() is {} response3) { return response3; } + if (table.SomeoneHasFolded()) { return ShouldContinue(); } } - _io.WriteLine(); - _io.WriteLine("Now we compare hands:"); - _io.WriteLine("My hand:"); - _io.Write(table.Computer.Hand); - table.Human.Hand.Analyze(0); - _io.WriteLine(); - _io.Write($"You have {table.Human.Hand.Name}"); - _io.Write($"and I have {table.Computer.Hand.Name}"); - if (table.Computer.Hand > table.Human.Hand) { return ComputerWins(); } - if (table.Human.Hand > table.Computer.Hand) { return PlayerWins(); } - _io.WriteLine("The hand is drawn."); - _io.WriteLine($"All $ {table.Pot} remains in the pot."); - } - - bool? CheckIfSomeoneFolded() - { - if (_playerFolds) + if (table.GetWinner() is { } winner) { - _io.WriteLine(); - return ComputerWins(); + winner.TakeWinnings(); + return ShouldContinue(); } - else if (_computerFolds) - { - _io.WriteLine(); - return PlayerWins(); - } - else - { - return null; - } - } - - bool ComputerWins() - { - _io.WriteLine("I win."); - table.Computer.Balance += table.Pot; - return ShouldContinue(); } bool ShouldContinue() { - _io.WriteLine($"Now I have ${table.Computer.Balance}and you have ${table.Human.Balance}"); + _io.WriteLine($"Now I have $ {table.Computer.Balance} and you have $ {table.Human.Balance} "); return _io.ReadYesNo("Do you wish to continue"); } - bool PlayerWins() - { - _io.WriteLine("You win."); - table.Human.Balance += table.Pot; - return ShouldContinue(); - } - bool GetWager() { _playerBet = 0; @@ -230,12 +145,12 @@ internal class Game _playerTotalBet += bet.Amount; break; } - if (PlayerIsBroke()) { return true; } + if (table.Human.IsBroke()) { return true; } continue; } else { - _playerFolds = true; + table.Human.Fold(); return UpdatePot(); } } @@ -244,7 +159,7 @@ internal class Game { if (_playerTotalBet > 5) { - _computerFolds = true; + table.Computer.Fold(); _io.WriteLine("I fold."); return false; } @@ -300,7 +215,7 @@ internal class Game { return Line_3360(); } - else if (table.Computer.TrySellWatch(table.Human, _io)) + else if (table.Computer.TrySellWatch(table.Human)) { return false; } @@ -312,20 +227,6 @@ internal class Game _io.WriteLine("I'm busted. Congratulations!"); return true; } - - bool PlayerIsBroke() - { - _io.WriteLine(); - _io.WriteLine("You can't bet with what you haven't got."); - - if (Computer.TryBuyWatch(table.Human, _io, _random)) { 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; - } } } @@ -341,6 +242,9 @@ internal record Bet (int Amount) : IAction internal abstract class Player { + private Table? _table; + private bool _hasFolded; + protected Player(int bank) { Hand = Hand.Empty; @@ -350,36 +254,76 @@ internal abstract class Player 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 { - public Human(int bank) + 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, IReadWrite io) + public void DrawCards(Deck deck) { - var count = io.ReadNumber("How many cards do you want", 3, "You can't draw more than three cards."); + 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:"); + _io.WriteLine("What are their numbers:"); for (var i = 1; i <= count; i++) { - Hand = Hand.Replace((int)io.ReadNumber(), deck.DealCard()); + Hand = Hand.Replace((int)_io.ReadNumber(), deck.DealCard()); } - io.WriteLine("Your new hand:"); - io.Write(Hand); + _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() @@ -393,61 +337,90 @@ internal class Human : Player HasWatch = false; Balance += amount; } + + public override void TakeWinnings() + { + _io.WriteLine("You win."); + base.TakeWinnings(); + } } internal class Computer : Player { - public Computer(int bank) + 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 int KeepMask { get; set; } + public bool IsBluffing => _isBluffing; - public void DrawCards(Deck deck, IReadWrite io) + 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) + if ((keepMask & (1 << (i - 1))) == 0) { Hand = Hand.Replace(i, deck.DealCard()); count++; } } - io.WriteLine(); - io.Write($"I am taking {count} card"); + _io.WriteLine(); + _io.Write($"I am taking {count} card"); if (count != 1) { - io.WriteLine("s"); + _io.WriteLine("s"); } } - public static bool TryBuyWatch(Human human, IReadWrite io, IRandom random) + public bool TryBuyWatch(Human human) { if (!human.HasWatch) { return false; } - var response = io.ReadString("Would you like to sell your watch"); + 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 + 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); + _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, IReadWrite io) + public bool TrySellWatch(Human human) { if (human.HasWatch) { return false; } - var response = io.ReadString("Would you like to buy back your watch for $50"); + 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 @@ -455,6 +428,12 @@ internal class Computer : Player human.ReceiveWatch(); return true; } + + public override void TakeWinnings() + { + _io.WriteLine("I win."); + base.TakeWinnings(); + } } internal class Table @@ -469,6 +448,9 @@ internal class Table _deck = deck; Human = human; Computer = computer; + + human.Sit(this); + computer.Sit(this); } public Human Human { get; } @@ -476,12 +458,12 @@ internal class Table public void Deal() { - Pot += 10; + Pot = 10; Human.Pay(5); Computer.Pay(5); - Human.Hand = _deck.DealHand(); - Computer.Hand = _deck.DealHand(); + Human.NewHand(_deck.DealHand()); + Computer.NewHand(_deck.DealHand()); _io.WriteLine("Your hand:"); _io.Write(Human.Hand); @@ -491,8 +473,8 @@ internal class Table { _io.WriteLine(); _io.Write("Now we draw -- "); - Human.DrawCards(_deck, _io); - Computer.DrawCards(_deck, _io); + Human.DrawCards(_deck); + Computer.DrawCards(_deck); _io.WriteLine(); } @@ -500,4 +482,41 @@ internal class Table { } + + 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; + } } \ No newline at end of file diff --git a/71_Poker/csharp/Hand.cs b/71_Poker/csharp/Hand.cs index c806e490..6e078089 100644 --- a/71_Poker/csharp/Hand.cs +++ b/71_Poker/csharp/Hand.cs @@ -7,42 +7,48 @@ internal class Hand public static readonly Hand Empty = new Hand(); private readonly Card[] _cards; - private readonly Card _highCard; private readonly string _name1; private readonly string _name2; - private readonly int _keepMask; - private readonly Func _iTransform; private Hand() { _cards = Array.Empty(); _name1 = ""; _name2 = ""; - _iTransform = Identity; Name = ""; } public Hand(IEnumerable cards) + : this(cards, isAfterDraw: false) + { + } + + private Hand(IEnumerable cards, bool isAfterDraw) { _cards = cards.ToArray(); - (Rank, _name1, _name2, _highCard, _keepMask, _iTransform) = Analyze(); + (Rank, _name1, _name2, HighCard, KeepMask) = Analyze(); Name = GetHandName(); + + IsWeak = Rank < 10 + || Rank == 10 && isAfterDraw + || Rank <= 12 && HighCard.Rank <= 6; } public string Name { get; } public int Rank { get; } + public Card HighCard { get; } + public int KeepMask { get; set; } + public bool IsWeak { get; } public Hand Replace(int cardNumber, Card newCard) { if (cardNumber < 1 || cardNumber > _cards.Length) { return this; } _cards[cardNumber - 1] = newCard; - return new Hand(_cards); + return new Hand(_cards, isAfterDraw: true); } - public (int, int) Analyze(int i) => (_keepMask, _iTransform(i)); - - private (int, string, string, Card, int, Func) Analyze() + private (int, string, string, Card, int) Analyze() { var suitMatchCount = 0; for (var i = 0; i < _cards.Length; i++) @@ -54,7 +60,7 @@ internal class Hand } if (suitMatchCount == 4) { - return (15, "A Flus", "h in", _cards[0], 0b11111, Identity); + return (15, "A Flus", "h in", _cards[0], 0b11111); } var sortedCards = _cards.OrderBy(c => c.Rank).ToArray(); @@ -92,42 +98,27 @@ internal class Hand { if (handRank == 10) { - return (14, "Straig", "ht", sortedCards[4], 0b11111, Identity); + return (14, "Straig", "ht", sortedCards[4], 0b11111); } handRank=10; keepMask=0b11110; } } - if (handRank < 10) - { - return (9, "Schmal", "tz, ", sortedCards[4], 0b11000, To6); - } - var iTransform = Identity; - if (handRank == 10) - { - iTransform = To6If1; - } - else if (handRank <= 12 && highCard.Rank <= 6) - { - iTransform = To6; - } - return (handRank, handName1, handName2, highCard, keepMask, iTransform); + return handRank < 10 + ? (9, "Schmal", "tz, ", sortedCards[4], 0b11000) + : (handRank, handName1, handName2, highCard, keepMask); } - private int Identity(int x) => x; - private int To6(int _) => 6; - private int To6If1(int x) => x == 1 ? 6 : x; - private string GetHandName() { var sb = new StringBuilder(_name1).Append(_name2); if (_name1 == "A Flus") { - sb.Append(_highCard.Suit).AppendLine(); + sb.Append(HighCard.Suit).AppendLine(); } else { - sb.Append(_highCard.Rank) + sb.Append(HighCard.Rank) .AppendLine(_name1 == "Schmal" || _name1 == "Straig" ? " High" : "'s"); } return sb.ToString(); @@ -152,9 +143,9 @@ internal class Hand public static bool operator >(Hand x, Hand y) => x.Rank > y.Rank || - x.Rank == y.Rank && x._highCard > y._highCard; + x.Rank == y.Rank && x.HighCard > y.HighCard; public static bool operator <(Hand x, Hand y) => x.Rank < y.Rank || - x.Rank == y.Rank && x._highCard < y._highCard; + x.Rank == y.Rank && x.HighCard < y.HighCard; } From fc65452ae63ec36318eb08edba81e892a0a4eef2 Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Sat, 18 Jun 2022 22:15:05 +1000 Subject: [PATCH 18/29] Reorganise classes --- 71_Poker/csharp/{ => Cards}/Card.cs | 2 +- 71_Poker/csharp/{ => Cards}/Deck.cs | 4 +- 71_Poker/csharp/{ => Cards}/Hand.cs | 2 +- 71_Poker/csharp/{ => Cards}/Rank.cs | 6 +- 71_Poker/csharp/{ => Cards}/Suit.cs | 2 +- 71_Poker/csharp/{Games.cs => Game.cs} | 284 +------------------------- 71_Poker/csharp/Players/Computer.cs | 95 +++++++++ 71_Poker/csharp/Players/Human.cs | 64 ++++++ 71_Poker/csharp/Players/Player.cs | 47 +++++ 71_Poker/csharp/Table.cs | 89 ++++++++ 10 files changed, 307 insertions(+), 288 deletions(-) rename 71_Poker/csharp/{ => Cards}/Card.cs (93%) rename 71_Poker/csharp/{ => Cards}/Deck.cs (91%) rename 71_Poker/csharp/{ => Cards}/Hand.cs (99%) rename 71_Poker/csharp/{ => Cards}/Rank.cs (90%) rename 71_Poker/csharp/{ => Cards}/Suit.cs (75%) rename 71_Poker/csharp/{Games.cs => Game.cs} (51%) create mode 100644 71_Poker/csharp/Players/Computer.cs create mode 100644 71_Poker/csharp/Players/Human.cs create mode 100644 71_Poker/csharp/Players/Player.cs create mode 100644 71_Poker/csharp/Table.cs diff --git a/71_Poker/csharp/Card.cs b/71_Poker/csharp/Cards/Card.cs similarity index 93% rename from 71_Poker/csharp/Card.cs rename to 71_Poker/csharp/Cards/Card.cs index 95721142..d3176213 100644 --- a/71_Poker/csharp/Card.cs +++ b/71_Poker/csharp/Cards/Card.cs @@ -1,4 +1,4 @@ -namespace Poker; +namespace Poker.Cards; internal record struct Card (Rank Rank, Suit Suit) { diff --git a/71_Poker/csharp/Deck.cs b/71_Poker/csharp/Cards/Deck.cs similarity index 91% rename from 71_Poker/csharp/Deck.cs rename to 71_Poker/csharp/Cards/Deck.cs index 38a72244..d3a101b4 100644 --- a/71_Poker/csharp/Deck.cs +++ b/71_Poker/csharp/Cards/Deck.cs @@ -1,6 +1,6 @@ -using static Poker.Rank; +using static Poker.Cards.Rank; -namespace Poker; +namespace Poker.Cards; internal class Deck { diff --git a/71_Poker/csharp/Hand.cs b/71_Poker/csharp/Cards/Hand.cs similarity index 99% rename from 71_Poker/csharp/Hand.cs rename to 71_Poker/csharp/Cards/Hand.cs index 6e078089..d697853a 100644 --- a/71_Poker/csharp/Hand.cs +++ b/71_Poker/csharp/Cards/Hand.cs @@ -1,6 +1,6 @@ using System.Text; -namespace Poker; +namespace Poker.Cards; internal class Hand { diff --git a/71_Poker/csharp/Rank.cs b/71_Poker/csharp/Cards/Rank.cs similarity index 90% rename from 71_Poker/csharp/Rank.cs rename to 71_Poker/csharp/Cards/Rank.cs index ab642cd4..cd44922a 100644 --- a/71_Poker/csharp/Rank.cs +++ b/71_Poker/csharp/Cards/Rank.cs @@ -1,4 +1,4 @@ -namespace Poker; +namespace Poker.Cards; internal struct Rank : IComparable { @@ -43,4 +43,8 @@ internal struct Rank : IComparable 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(); } diff --git a/71_Poker/csharp/Suit.cs b/71_Poker/csharp/Cards/Suit.cs similarity index 75% rename from 71_Poker/csharp/Suit.cs rename to 71_Poker/csharp/Cards/Suit.cs index 616febb3..0a246999 100644 --- a/71_Poker/csharp/Suit.cs +++ b/71_Poker/csharp/Cards/Suit.cs @@ -1,4 +1,4 @@ -namespace Poker; +namespace Poker.Cards; internal enum Suit { diff --git a/71_Poker/csharp/Games.cs b/71_Poker/csharp/Game.cs similarity index 51% rename from 71_Poker/csharp/Games.cs rename to 71_Poker/csharp/Game.cs index 099690d0..1f6c639f 100644 --- a/71_Poker/csharp/Games.cs +++ b/71_Poker/csharp/Game.cs @@ -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; - } -} \ No newline at end of file diff --git a/71_Poker/csharp/Players/Computer.cs b/71_Poker/csharp/Players/Computer.cs new file mode 100644 index 00000000..350e9785 --- /dev/null +++ b/71_Poker/csharp/Players/Computer.cs @@ -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(); + } +} diff --git a/71_Poker/csharp/Players/Human.cs b/71_Poker/csharp/Players/Human.cs new file mode 100644 index 00000000..ac3674bd --- /dev/null +++ b/71_Poker/csharp/Players/Human.cs @@ -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(); + } +} diff --git a/71_Poker/csharp/Players/Player.cs b/71_Poker/csharp/Players/Player.cs new file mode 100644 index 00000000..d12e92c1 --- /dev/null +++ b/71_Poker/csharp/Players/Player.cs @@ -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; + } +} diff --git a/71_Poker/csharp/Table.cs b/71_Poker/csharp/Table.cs new file mode 100644 index 00000000..7b7524bc --- /dev/null +++ b/71_Poker/csharp/Table.cs @@ -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; + } +} \ No newline at end of file From 7199cdbb4d8476a588208e6e71c68faf0adec694 Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Sun, 19 Jun 2022 23:09:02 +1000 Subject: [PATCH 19/29] Introduce HandRank --- 71_Poker/csharp/Cards/Hand.cs | 82 ++++++++++++------------------- 71_Poker/csharp/Cards/HandRank.cs | 34 +++++++++++++ 71_Poker/csharp/Game.cs | 12 ++--- 3 files changed, 71 insertions(+), 57 deletions(-) create mode 100644 71_Poker/csharp/Cards/HandRank.cs diff --git a/71_Poker/csharp/Cards/Hand.cs b/71_Poker/csharp/Cards/Hand.cs index d697853a..34c14ac4 100644 --- a/71_Poker/csharp/Cards/Hand.cs +++ b/71_Poker/csharp/Cards/Hand.cs @@ -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(); - _name1 = ""; - _name2 = ""; - Name = ""; + Rank = None; } public Hand(IEnumerable cards) @@ -26,16 +22,15 @@ internal class Hand private Hand(IEnumerable 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() diff --git a/71_Poker/csharp/Cards/HandRank.cs b/71_Poker/csharp/Cards/HandRank.cs new file mode 100644 index 00000000..878746ee --- /dev/null +++ b/71_Poker/csharp/Cards/HandRank.cs @@ -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 _suffixSelector; + + private HandRank(int value, string displayName, Func? 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; +} diff --git a/71_Poker/csharp/Game.cs b/71_Poker/csharp/Game.cs index 1f6c639f..d99a4baa 100644 --- a/71_Poker/csharp/Game.cs +++ b/71_Poker/csharp/Game.cs @@ -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 }; From 6354bf1293fb70edad7d92298349ca815a03d897 Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Mon, 20 Jun 2022 22:33:07 +1000 Subject: [PATCH 20/29] Simplify some logic --- 71_Poker/csharp/Game.cs | 135 +++++++++++++--------------- 71_Poker/csharp/Players/Computer.cs | 12 +-- 71_Poker/csharp/Players/Human.cs | 2 +- 71_Poker/csharp/Players/Player.cs | 5 +- 71_Poker/csharp/Table.cs | 5 +- 5 files changed, 76 insertions(+), 83 deletions(-) diff --git a/71_Poker/csharp/Game.cs b/71_Poker/csharp/Game.cs index d99a4baa..c902ffeb 100644 --- a/71_Poker/csharp/Game.cs +++ b/71_Poker/csharp/Game.cs @@ -44,19 +44,19 @@ internal class Game while(true) { _io.WriteLine(); - if (table.Computer.Balance<=5) + if (table.Computer.Balance <= table.Ante) { CongratulatePlayer(); return false; } - _io.WriteLine("The ante is $5. I will deal:"); + _io.WriteLine($"The ante is ${table.Ante}. I will deal:"); _io.WriteLine(); - if (table.Human.Balance <= 5 && table.Human.IsBroke()) { return false; } + if (table.Human.Balance <= table.Ante && table.Human.IsBroke()) { return false; } table.Deal(); _io.WriteLine(); - Z = table.Computer.Hand.Rank switch + Z = true switch { _ when table.Computer.Hand.IsWeak => table.Computer.BluffIf(Get0To9() < 2, 0b11100) ?? @@ -76,7 +76,7 @@ internal class Game else { V=Z+Get0To9(); - if (ComputerCantContinue()) { return false; } + if (ComputerIsBroke()) { return false; } _io.WriteLine($"I'll open with ${V}"); _computerTotalBet = V; _playerTotalBet = 0; @@ -86,7 +86,7 @@ internal class Game table.Draw(); - Z = table.Computer.Hand.Rank switch + Z = true switch { _ when table.Computer.IsBluffing => 28, _ when table.Computer.Hand.IsWeak => 1, @@ -109,7 +109,7 @@ internal class Game else { V=Z+Get0To9(); - if (ComputerCantContinue()) { return false; } + if (ComputerIsBroke()) { return false; } _io.WriteLine($"I'll bet ${V}"); _computerTotalBet = V; if (GetWager()) { return false; } @@ -130,82 +130,75 @@ internal class Game bool GetWager() { - _playerBet = 0; - while(true) + while (true) { - if (_io.ReadPlayerAction(_computerTotalBet == 0 && _playerTotalBet == 0) is Bet bet) + _playerBet = 0; + while(true) { - if (_playerTotalBet + bet.Amount < _computerTotalBet) + if (_io.ReadPlayerAction(_computerTotalBet == 0 && _playerTotalBet == 0) is Bet bet) { - _io.WriteLine("If you can't see my bet, then fold."); + if (_playerTotalBet + bet.Amount < _computerTotalBet) + { + _io.WriteLine("If you can't see my bet, then fold."); + continue; + } + if (table.Human.Balance - _playerTotalBet - bet.Amount >= 0) + { + _playerBet = bet.Amount; + _playerTotalBet += bet.Amount; + break; + } + if (table.Human.IsBroke()) { return true; } continue; } - if (table.Human.Balance - _playerTotalBet - bet.Amount >= 0) + else { - _playerBet = bet.Amount; - _playerTotalBet += bet.Amount; - break; + table.Human.Fold(); + UpdatePot(); + return false; } - if (table.Human.IsBroke()) { return true; } - continue; } - else + if (_playerTotalBet == _computerTotalBet) { - table.Human.Fold(); - return UpdatePot(); - } - } - if (_playerTotalBet == _computerTotalBet) { return UpdatePot(); } - if (Z == 1) - { - if (_playerTotalBet > 5) - { - table.Computer.Fold(); - _io.WriteLine("I fold."); + UpdatePot(); return false; } - V = 5; + if (Z == 1) + { + if (_playerTotalBet > 5) + { + table.Computer.Fold(); + _io.WriteLine("I fold."); + return false; + } + V = 5; + } + if (_playerTotalBet > 3 * Z) + { + if (Z != 2) + { + _io.WriteLine("I'll see you."); + _computerTotalBet = _playerTotalBet; + UpdatePot(); + return false; + } + } + + V = _playerTotalBet - _computerTotalBet + Get0To9(); + if (ComputerIsBroke()) { return true; } + _io.WriteLine($"I'll see you, and raise you{V}"); + _computerTotalBet = _playerTotalBet + V; } - return Line_3420(); } - bool Line_3350() - { - if (Z==2) { return Line_3430(); } - return Line_3360(); - } - - bool Line_3360() - { - _io.WriteLine("I'll see you."); - _computerTotalBet = _playerTotalBet; - return UpdatePot(); - } - - bool UpdatePot() + void UpdatePot() { table.Human.Balance -= _playerTotalBet; table.Computer.Balance -= _computerTotalBet; table.Pot += _playerTotalBet + _computerTotalBet; - return false; } - bool Line_3420() - { - if (_playerTotalBet>3*Z) { return Line_3350(); } - return Line_3430(); - } - - bool Line_3430() - { - V = _playerTotalBet - _computerTotalBet + Get0To9(); - if (ComputerCantContinue()) { return true; } - _io.WriteLine($"I'll see you, and raise you{V}"); - _computerTotalBet = _playerTotalBet + V; - return GetWager(); - } - - bool ComputerCantContinue() + bool ComputerIsBroke() { if (table.Computer.Balance - _playerTotalBet - V >= 0) { return false; } if (_playerTotalBet == 0) @@ -214,20 +207,20 @@ internal class Game } else if (table.Computer.Balance - _playerTotalBet >= 0) { - return Line_3360(); + _io.WriteLine("I'll see you."); + _computerTotalBet = _playerTotalBet; + UpdatePot(); + return false; } - else if (table.Computer.TrySellWatch(table.Human)) + else if (table.Computer.TrySellWatch()) { return false; } - return CongratulatePlayer(); - } - - bool CongratulatePlayer() - { - _io.WriteLine("I'm busted. Congratulations!"); + CongratulatePlayer(); return true; } + + void CongratulatePlayer() => _io.WriteLine("I'm busted. Congratulations!"); } } diff --git a/71_Poker/csharp/Players/Computer.cs b/71_Poker/csharp/Players/Computer.cs index 350e9785..11e2005e 100644 --- a/71_Poker/csharp/Players/Computer.cs +++ b/71_Poker/csharp/Players/Computer.cs @@ -54,9 +54,9 @@ internal class Computer : Player } } - public bool TryBuyWatch(Human human) + public bool TryBuyWatch() { - if (!human.HasWatch) { return false; } + if (!Table.Human.HasWatch) { return false; } var response = _io.ReadString("Would you like to sell your watch"); if (response.StartsWith("N", InvariantCultureIgnoreCase)) { return false; } @@ -68,22 +68,22 @@ internal class Computer : Player }; _io.WriteLine(message); - human.SellWatch(value); + Table.Human.SellWatch(value); // The original code does not have the computer part with any money return true; } - public bool TrySellWatch(Human human) + public bool TrySellWatch() { - if (human.HasWatch) { return false; } + if (Table.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(); + Table.Human.ReceiveWatch(); return true; } diff --git a/71_Poker/csharp/Players/Human.cs b/71_Poker/csharp/Players/Human.cs index ac3674bd..f4a4af1a 100644 --- a/71_Poker/csharp/Players/Human.cs +++ b/71_Poker/csharp/Players/Human.cs @@ -35,7 +35,7 @@ internal class Human : Player _io.WriteLine(); _io.WriteLine("You can't bet with what you haven't got."); - if (Table.Computer.TryBuyWatch(this)) { return false; } + if (Table.Computer.TryBuyWatch()) { 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. diff --git a/71_Poker/csharp/Players/Player.cs b/71_Poker/csharp/Players/Player.cs index d12e92c1..313dc0ab 100644 --- a/71_Poker/csharp/Players/Player.cs +++ b/71_Poker/csharp/Players/Player.cs @@ -29,9 +29,10 @@ internal abstract class Player _hasFolded = false; } - public void Pay(int amount) + public int AnteUp() { - Balance -= amount; + Balance -= Table.Ante; + return Table.Ante; } public virtual void TakeWinnings() diff --git a/71_Poker/csharp/Table.cs b/71_Poker/csharp/Table.cs index 7b7524bc..28cf6919 100644 --- a/71_Poker/csharp/Table.cs +++ b/71_Poker/csharp/Table.cs @@ -20,14 +20,13 @@ internal class Table computer.Sit(this); } + public int Ante { get; } = 5; public Human Human { get; } public Computer Computer { get; } public void Deal() { - Pot = 10; - Human.Pay(5); - Computer.Pay(5); + Pot = Human.AnteUp() + Computer.AnteUp(); Human.NewHand(_deck.DealHand()); Computer.NewHand(_deck.DealHand()); From 9d3f5691fb169c7effc3a0df51b23dcabf841648 Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Mon, 20 Jun 2022 22:58:39 +1000 Subject: [PATCH 21/29] Move bet variables --- 71_Poker/csharp/Game.cs | 51 +++++++++++++---------------- 71_Poker/csharp/Players/Computer.cs | 6 ++-- 71_Poker/csharp/Players/Human.cs | 2 +- 71_Poker/csharp/Players/Player.cs | 16 +++++++-- 71_Poker/csharp/Table.cs | 12 +++---- 5 files changed, 45 insertions(+), 42 deletions(-) diff --git a/71_Poker/csharp/Game.cs b/71_Poker/csharp/Game.cs index c902ffeb..8fa11b7b 100644 --- a/71_Poker/csharp/Game.cs +++ b/71_Poker/csharp/Game.cs @@ -9,10 +9,7 @@ internal class Game private readonly IReadWrite _io; private readonly IRandom _random; - private int _playerBet; - private int _playerTotalBet; private int Z; - private int _computerTotalBet; private int V; public Game(IReadWrite io, IRandom random) @@ -70,7 +67,6 @@ internal class Game }; if (Z <= 1) { - _computerTotalBet = 0; _io.WriteLine("I check."); } else @@ -78,8 +74,7 @@ internal class Game V=Z+Get0To9(); if (ComputerIsBroke()) { return false; } _io.WriteLine($"I'll open with ${V}"); - _computerTotalBet = V; - _playerTotalBet = 0; + table.Computer.Bet = V; } if (GetWager()) { return false; } if (table.SomeoneHasFolded()) { return ShouldContinue(); } @@ -95,10 +90,8 @@ internal class Game _ => 2 }; - _computerTotalBet = 0; - _playerTotalBet = 0; if (GetWager()) { return false; } - if (_playerBet != 0) + if (table.Human.HasBet) { if (table.SomeoneHasFolded()) { return ShouldContinue(); } } @@ -111,7 +104,7 @@ internal class Game V=Z+Get0To9(); if (ComputerIsBroke()) { return false; } _io.WriteLine($"I'll bet ${V}"); - _computerTotalBet = V; + table.Computer.Bet = V; if (GetWager()) { return false; } if (table.SomeoneHasFolded()) { return ShouldContinue(); } } @@ -132,20 +125,20 @@ internal class Game { while (true) { - _playerBet = 0; + table.Human.HasBet = false; while(true) { - if (_io.ReadPlayerAction(_computerTotalBet == 0 && _playerTotalBet == 0) is Bet bet) + if (_io.ReadPlayerAction(table.Computer.Bet == 0 && table.Human.Bet == 0) is Bet bet) { - if (_playerTotalBet + bet.Amount < _computerTotalBet) + if (table.Human.Bet + bet.Amount < table.Computer.Bet) { _io.WriteLine("If you can't see my bet, then fold."); continue; } - if (table.Human.Balance - _playerTotalBet - bet.Amount >= 0) + if (table.Human.Balance - table.Human.Bet - bet.Amount >= 0) { - _playerBet = bet.Amount; - _playerTotalBet += bet.Amount; + table.Human.HasBet = true; + table.Human.Bet += bet.Amount; break; } if (table.Human.IsBroke()) { return true; } @@ -158,14 +151,14 @@ internal class Game return false; } } - if (_playerTotalBet == _computerTotalBet) + if (table.Human.Bet == table.Computer.Bet) { UpdatePot(); return false; } if (Z == 1) { - if (_playerTotalBet > 5) + if (table.Human.Bet > 5) { table.Computer.Fold(); _io.WriteLine("I fold."); @@ -173,42 +166,42 @@ internal class Game } V = 5; } - if (_playerTotalBet > 3 * Z) + if (table.Human.Bet > 3 * Z) { if (Z != 2) { _io.WriteLine("I'll see you."); - _computerTotalBet = _playerTotalBet; + table.Computer.Bet = table.Human.Bet; UpdatePot(); return false; } } - V = _playerTotalBet - _computerTotalBet + Get0To9(); + V = table.Human.Bet - table.Computer.Bet + Get0To9(); if (ComputerIsBroke()) { return true; } _io.WriteLine($"I'll see you, and raise you{V}"); - _computerTotalBet = _playerTotalBet + V; + table.Computer.Bet = table.Human.Bet + V; } } void UpdatePot() { - table.Human.Balance -= _playerTotalBet; - table.Computer.Balance -= _computerTotalBet; - table.Pot += _playerTotalBet + _computerTotalBet; + table.Human.Balance -= table.Human.Bet; + table.Computer.Balance -= table.Computer.Bet; + table.Pot += table.Human.Bet + table.Computer.Bet; } bool ComputerIsBroke() { - if (table.Computer.Balance - _playerTotalBet - V >= 0) { return false; } - if (_playerTotalBet == 0) + if (table.Computer.Balance - table.Human.Bet - V >= 0) { return false; } + if (table.Human.Bet == 0) { V = table.Computer.Balance; } - else if (table.Computer.Balance - _playerTotalBet >= 0) + else if (table.Computer.Balance - table.Human.Bet >= 0) { _io.WriteLine("I'll see you."); - _computerTotalBet = _playerTotalBet; + table.Computer.Bet = table.Human.Bet; UpdatePot(); return false; } diff --git a/71_Poker/csharp/Players/Computer.cs b/71_Poker/csharp/Players/Computer.cs index 11e2005e..a5506853 100644 --- a/71_Poker/csharp/Players/Computer.cs +++ b/71_Poker/csharp/Players/Computer.cs @@ -18,9 +18,9 @@ internal class Computer : Player public bool IsBluffing => _isBluffing; - public override void NewHand(Hand hand) + public override void NewHand() { - base.NewHand(hand); + base.NewHand(); _isBluffing = false; } @@ -33,7 +33,7 @@ internal class Computer : Player return 23; } - public void DrawCards(Deck deck) + protected override void DrawCards(Deck deck) { var keepMask = Hand.KeepMask; var count = 0; diff --git a/71_Poker/csharp/Players/Human.cs b/71_Poker/csharp/Players/Human.cs index f4a4af1a..0a3f4234 100644 --- a/71_Poker/csharp/Players/Human.cs +++ b/71_Poker/csharp/Players/Human.cs @@ -15,7 +15,7 @@ internal class Human : Player public bool HasWatch { get; set; } - public void DrawCards(Deck deck) + protected override 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; } diff --git a/71_Poker/csharp/Players/Player.cs b/71_Poker/csharp/Players/Player.cs index 313dc0ab..4e9f7faf 100644 --- a/71_Poker/csharp/Players/Player.cs +++ b/71_Poker/csharp/Players/Player.cs @@ -15,7 +15,8 @@ internal abstract class Player public Hand Hand { get; set; } public int Balance { get; set; } - public int Bet { get; private set; } + public bool HasBet { get; set; } + public int Bet { get; set; } public bool HasFolded => _hasFolded; protected Table Table => @@ -23,9 +24,10 @@ internal abstract class Player public void Sit(Table table) => _table = table; - public virtual void NewHand(Hand hand) + public virtual void NewHand() { - Hand = hand; + Bet = 0; + Hand = Table.Deck.DealHand(); _hasFolded = false; } @@ -35,6 +37,14 @@ internal abstract class Player return Table.Ante; } + public void DrawCards() + { + Bet = 0; + DrawCards(Table.Deck); + } + + protected abstract void DrawCards(Deck deck); + public virtual void TakeWinnings() { Balance += Table.Pot; diff --git a/71_Poker/csharp/Table.cs b/71_Poker/csharp/Table.cs index 28cf6919..cb5bfc44 100644 --- a/71_Poker/csharp/Table.cs +++ b/71_Poker/csharp/Table.cs @@ -7,12 +7,11 @@ 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; + Deck = deck; Human = human; Computer = computer; @@ -21,6 +20,7 @@ internal class Table } public int Ante { get; } = 5; + public Deck Deck { get; } public Human Human { get; } public Computer Computer { get; } @@ -28,8 +28,8 @@ internal class Table { Pot = Human.AnteUp() + Computer.AnteUp(); - Human.NewHand(_deck.DealHand()); - Computer.NewHand(_deck.DealHand()); + Human.NewHand(); + Computer.NewHand(); _io.WriteLine("Your hand:"); _io.Write(Human.Hand); @@ -39,8 +39,8 @@ internal class Table { _io.WriteLine(); _io.Write("Now we draw -- "); - Human.DrawCards(_deck); - Computer.DrawCards(_deck); + Human.DrawCards(); + Computer.DrawCards(); _io.WriteLine(); } From 156b378a3f814134cae99aca386850bacd7b71e6 Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Tue, 21 Jun 2022 07:34:04 +1000 Subject: [PATCH 22/29] Move ShouldContinue check --- 71_Poker/csharp/Game.cs | 10 +++++++--- 71_Poker/csharp/Table.cs | 2 ++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/71_Poker/csharp/Game.cs b/71_Poker/csharp/Game.cs index 8fa11b7b..7f48fd5e 100644 --- a/71_Poker/csharp/Game.cs +++ b/71_Poker/csharp/Game.cs @@ -30,10 +30,14 @@ internal class Game _io.Write(Resource.Streams.Title); _io.Write(Resource.Streams.Instructions); - do + while (true) { - deck.Shuffle(_random); - } while (PlayHand(table)); + var gameOver = PlayHand(table); + if (gameOver) { break; } + + _io.WriteLine($"Now I have $ {table.Computer.Balance} and you have $ {table.Human.Balance}"); + if (!_io.ReadYesNo("Do you wish to continue")) { break; } + } } internal bool PlayHand(Table table) diff --git a/71_Poker/csharp/Table.cs b/71_Poker/csharp/Table.cs index cb5bfc44..686e18e2 100644 --- a/71_Poker/csharp/Table.cs +++ b/71_Poker/csharp/Table.cs @@ -26,6 +26,8 @@ internal class Table public void Deal() { + Deck.Shuffle(); + Pot = Human.AnteUp() + Computer.AnteUp(); Human.NewHand(); From cdc8797312d06a86c6106f19201f615f86b1e12c Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Tue, 21 Jun 2022 07:52:10 +1000 Subject: [PATCH 23/29] Consolidate logic --- 71_Poker/csharp/Game.cs | 130 ++++++++++++++++++++++----------------- 71_Poker/csharp/Table.cs | 7 +++ 2 files changed, 79 insertions(+), 58 deletions(-) diff --git a/71_Poker/csharp/Game.cs b/71_Poker/csharp/Game.cs index 7f48fd5e..63239bd6 100644 --- a/71_Poker/csharp/Game.cs +++ b/71_Poker/csharp/Game.cs @@ -42,17 +42,17 @@ internal class Game internal bool PlayHand(Table table) { - while(true) + while (true) { _io.WriteLine(); if (table.Computer.Balance <= table.Ante) { - CongratulatePlayer(); - return false; + _io.WriteLine("I'm busted. Congratulations!"); + return true; } _io.WriteLine($"The ante is ${table.Ante}. I will deal:"); _io.WriteLine(); - if (table.Human.Balance <= table.Ante && table.Human.IsBroke()) { return false; } + if (table.Human.Balance <= table.Ante && table.Human.IsBroke()) { return true; } table.Deal(); @@ -75,13 +75,30 @@ internal class Game } else { - V=Z+Get0To9(); - if (ComputerIsBroke()) { return false; } + V = Z + Get0To9(); + if (table.Computer.Balance - table.Human.Bet - V < 0) + { + if (table.Human.Bet == 0) + { + V = table.Computer.Balance; + } + else if (table.Computer.Balance - table.Human.Bet >= 0) + { + _io.WriteLine("I'll see you."); + table.Computer.Bet = table.Human.Bet; + table.UpdatePot(); + } + else if (!table.Computer.TrySellWatch()) + { + _io.WriteLine("I'm busted. Congratulations!"); + return true; + } + } _io.WriteLine($"I'll open with ${V}"); table.Computer.Bet = V; } - if (GetWager()) { return false; } - if (table.SomeoneHasFolded()) { return ShouldContinue(); } + if (GetWager()) { return true; } + if (table.SomeoneHasFolded()) { return false; } table.Draw(); @@ -94,10 +111,10 @@ internal class Game _ => 2 }; - if (GetWager()) { return false; } + if (GetWager()) { return true; } if (table.Human.HasBet) { - if (table.SomeoneHasFolded()) { return ShouldContinue(); } + if (table.SomeoneHasFolded()) { return false; } } else if (!table.Computer.IsBluffing && table.Computer.Hand.IsWeak) { @@ -105,32 +122,43 @@ internal class Game } else { - V=Z+Get0To9(); - if (ComputerIsBroke()) { return false; } + V = Z + Get0To9(); + if (table.Computer.Balance - table.Human.Bet - V < 0) + { + if (table.Human.Bet == 0) + { + V = table.Computer.Balance; + } + else if (table.Computer.Balance - table.Human.Bet >= 0) + { + _io.WriteLine("I'll see you."); + table.Computer.Bet = table.Human.Bet; + table.UpdatePot(); + } + else if (!table.Computer.TrySellWatch()) + { + _io.WriteLine("I'm busted. Congratulations!"); + return true; + } + } _io.WriteLine($"I'll bet ${V}"); table.Computer.Bet = V; - if (GetWager()) { return false; } - if (table.SomeoneHasFolded()) { return ShouldContinue(); } + if (GetWager()) { return true; } + if (table.SomeoneHasFolded()) { return false; } } if (table.GetWinner() is { } winner) { winner.TakeWinnings(); - return ShouldContinue(); + return false; } } - bool ShouldContinue() - { - _io.WriteLine($"Now I have $ {table.Computer.Balance} and you have $ {table.Human.Balance} "); - return _io.ReadYesNo("Do you wish to continue"); - } - bool GetWager() { while (true) { table.Human.HasBet = false; - while(true) + while (true) { if (_io.ReadPlayerAction(table.Computer.Bet == 0 && table.Human.Bet == 0) is Bet bet) { @@ -151,13 +179,13 @@ internal class Game else { table.Human.Fold(); - UpdatePot(); + table.UpdatePot(); return false; } } if (table.Human.Bet == table.Computer.Bet) { - UpdatePot(); + table.UpdatePot(); return false; } if (Z == 1) @@ -176,54 +204,40 @@ internal class Game { _io.WriteLine("I'll see you."); table.Computer.Bet = table.Human.Bet; - UpdatePot(); + table.UpdatePot(); return false; } } V = table.Human.Bet - table.Computer.Bet + Get0To9(); - if (ComputerIsBroke()) { return true; } + if (table.Computer.Balance - table.Human.Bet - V < 0) + { + if (table.Human.Bet == 0) + { + V = table.Computer.Balance; + } + else if (table.Computer.Balance - table.Human.Bet >= 0) + { + _io.WriteLine("I'll see you."); + table.Computer.Bet = table.Human.Bet; + table.UpdatePot(); + } + else if (!table.Computer.TrySellWatch()) + { + _io.WriteLine("I'm busted. Congratulations!"); + return true; + } + } _io.WriteLine($"I'll see you, and raise you{V}"); table.Computer.Bet = table.Human.Bet + V; } } - - void UpdatePot() - { - table.Human.Balance -= table.Human.Bet; - table.Computer.Balance -= table.Computer.Bet; - table.Pot += table.Human.Bet + table.Computer.Bet; - } - - bool ComputerIsBroke() - { - if (table.Computer.Balance - table.Human.Bet - V >= 0) { return false; } - if (table.Human.Bet == 0) - { - V = table.Computer.Balance; - } - else if (table.Computer.Balance - table.Human.Bet >= 0) - { - _io.WriteLine("I'll see you."); - table.Computer.Bet = table.Human.Bet; - UpdatePot(); - return false; - } - else if (table.Computer.TrySellWatch()) - { - return false; - } - CongratulatePlayer(); - return true; - } - - void CongratulatePlayer() => _io.WriteLine("I'm busted. Congratulations!"); } } internal interface IAction { } internal record Fold : IAction; -internal record Bet (int Amount) : IAction +internal record Bet(int Amount) : IAction { public Bet(float amount) : this((int)amount) diff --git a/71_Poker/csharp/Table.cs b/71_Poker/csharp/Table.cs index 686e18e2..60a3a89d 100644 --- a/71_Poker/csharp/Table.cs +++ b/71_Poker/csharp/Table.cs @@ -51,6 +51,13 @@ internal class Table } + public void UpdatePot() + { + Human.Balance -= Human.Bet; + Computer.Balance -= Computer.Bet; + Pot += Human.Bet + Computer.Bet; + } + public bool SomeoneHasFolded() { if (Human.HasFolded) From 3d8bae0a09e809f49e50dd2123fd2aeb905a5c17 Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Fri, 24 Jun 2022 08:33:41 +1000 Subject: [PATCH 24/29] Replace Z with strategy --- 71_Poker/csharp/Game.cs | 91 +++++++++++-------------- 71_Poker/csharp/IReadWriteExtensions.cs | 9 +-- 71_Poker/csharp/Players/Computer.cs | 17 ++--- 71_Poker/csharp/Strategies/Bet.cs | 8 +++ 71_Poker/csharp/Strategies/Bluff.cs | 12 ++++ 71_Poker/csharp/Strategies/Check.cs | 6 ++ 71_Poker/csharp/Strategies/Fold.cs | 6 ++ 71_Poker/csharp/Strategies/Raise.cs | 6 ++ 71_Poker/csharp/Strategies/Strategy.cs | 14 ++++ 71_Poker/csharp/Table.cs | 6 +- 10 files changed, 104 insertions(+), 71 deletions(-) create mode 100644 71_Poker/csharp/Strategies/Bet.cs create mode 100644 71_Poker/csharp/Strategies/Bluff.cs create mode 100644 71_Poker/csharp/Strategies/Check.cs create mode 100644 71_Poker/csharp/Strategies/Fold.cs create mode 100644 71_Poker/csharp/Strategies/Raise.cs create mode 100644 71_Poker/csharp/Strategies/Strategy.cs 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(); From 860dd402766037f2bc5fd9e2c30ac859b4833373 Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Sat, 25 Jun 2022 15:50:12 +1000 Subject: [PATCH 25/29] Move end game checks and text to main loop --- 71_Poker/csharp/Game.cs | 78 +++++++++++++------------- 71_Poker/csharp/Players/Computer.cs | 17 +++--- 71_Poker/csharp/Players/Human.cs | 6 +- 71_Poker/csharp/Players/Player.cs | 1 + 71_Poker/csharp/Strategies/Strategy.cs | 1 + 71_Poker/csharp/Table.cs | 20 +++++++ 6 files changed, 71 insertions(+), 52 deletions(-) diff --git a/71_Poker/csharp/Game.cs b/71_Poker/csharp/Game.cs index 65a3a131..ef7f6d76 100644 --- a/71_Poker/csharp/Game.cs +++ b/71_Poker/csharp/Game.cs @@ -30,29 +30,27 @@ internal class Game _io.Write(Resource.Streams.Title); _io.Write(Resource.Streams.Instructions); - while (true) + do { - var gameOver = PlayHand(table); - if (gameOver) { break; } - - _io.WriteLine($"Now I have $ {table.Computer.Balance} and you have $ {table.Human.Balance}"); - if (!_io.ReadYesNo("Do you wish to continue")) { break; } - } + PlayHand(table); + } while (!table.IsGameOver()); } - internal bool PlayHand(Table table) + internal void PlayHand(Table table) { while (true) { _io.WriteLine(); - if (table.Computer.Balance <= table.Ante) - { - _io.WriteLine("I'm busted. Congratulations!"); - return true; - } + table.Computer.CheckFunds(); + if (table.Computer.IsBroke) { return; } + _io.WriteLine($"The ante is ${table.Ante}. I will deal:"); _io.WriteLine(); - if (table.Human.Balance <= table.Ante && table.Human.IsBroke()) { return true; } + if (table.Human.Balance <= table.Ante) + { + table.Human.RaiseFunds(); + if (table.Human.IsBroke) { return; } + } table.Deal(_random); @@ -62,12 +60,12 @@ internal class Game (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, + (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 (table.Computer.Strategy is Strategies.Bet) + if (table.Computer.Strategy is Bet) { V = table.Computer.Strategy.Value + Get0To9(); if (table.Computer.Balance - table.Human.Bet - V < 0) @@ -82,10 +80,10 @@ internal class Game table.Computer.Bet = table.Human.Bet; table.UpdatePot(); } - else if (!table.Computer.TrySellWatch()) + else { - _io.WriteLine("I'm busted. Congratulations!"); - return true; + table.Computer.RaiseFunds(); + if (table.Computer.IsBroke) { return; } } } _io.WriteLine($"I'll open with ${V}"); @@ -95,8 +93,8 @@ internal class Game { _io.WriteLine("I check."); } - if (GetWager(table.Computer.Strategy)) { return true; } - if (table.SomeoneHasFolded()) { return false; } + GetWager(table.Computer.Strategy); + if (table.SomeoneIsBroke() || table.SomeoneHasFolded()) { return; } table.Draw(); @@ -109,12 +107,13 @@ internal class Game (false, false, false) => Strategy.Raise }; - if (GetWager(table.Computer.Strategy)) { return true; } + GetWager(table.Computer.Strategy); + if (table.SomeoneIsBroke()) { return; } if (table.Human.HasBet) { - if (table.SomeoneHasFolded()) { return false; } + if (table.SomeoneHasFolded()) { return; } } - else if (table.Computer.Strategy is Strategies.Bet) + else if (table.Computer.Strategy is Bet) { V = table.Computer.Strategy.Value + Get0To9(); if (table.Computer.Balance - table.Human.Bet - V < 0) @@ -129,16 +128,16 @@ internal class Game table.Computer.Bet = table.Human.Bet; table.UpdatePot(); } - else if (!table.Computer.TrySellWatch()) + else { - _io.WriteLine("I'm busted. Congratulations!"); - return true; + table.Computer.RaiseFunds(); + if (table.Computer.IsBroke) { return; } } } _io.WriteLine($"I'll bet ${V}"); table.Computer.Bet = V; - if (GetWager(table.Computer.Strategy)) { return true; } - if (table.SomeoneHasFolded()) { return false; } + GetWager(table.Computer.Strategy); + if (table.SomeoneIsBroke() || table.SomeoneHasFolded()) { return; } } else { @@ -147,11 +146,11 @@ internal class Game if (table.GetWinner() is { } winner) { winner.TakeWinnings(); - return false; + return; } } - bool GetWager(Strategy computerStrategy) + void GetWager(Strategy computerStrategy) { while (true) { @@ -172,20 +171,21 @@ internal class Game table.Human.Bet += humanStrategy.Value; break; } - if (table.Human.IsBroke()) { return true; } + table.Human.RaiseFunds(); + if (table.Human.IsBroke) { return; } continue; } else { table.Human.Fold(); table.UpdatePot(); - return false; + return; } } if (table.Human.Bet == table.Computer.Bet) { table.UpdatePot(); - return false; + return; } if (computerStrategy is Fold) { @@ -193,7 +193,7 @@ internal class Game { table.Computer.Fold(); _io.WriteLine("I fold."); - return false; + return; } V = 5; } @@ -204,7 +204,7 @@ internal class Game _io.WriteLine("I'll see you."); table.Computer.Bet = table.Human.Bet; table.UpdatePot(); - return false; + return; } } @@ -221,10 +221,10 @@ internal class Game table.Computer.Bet = table.Human.Bet; table.UpdatePot(); } - else if (!table.Computer.TrySellWatch()) + else { - _io.WriteLine("I'm busted. Congratulations!"); - return true; + table.Computer.RaiseFunds(); + if (table.Computer.IsBroke) { return; } } } _io.WriteLine($"I'll see you, and raise you{V}"); diff --git a/71_Poker/csharp/Players/Computer.cs b/71_Poker/csharp/Players/Computer.cs index 7a7cff0b..5f2ec399 100644 --- a/71_Poker/csharp/Players/Computer.cs +++ b/71_Poker/csharp/Players/Computer.cs @@ -14,16 +14,11 @@ internal class Computer : Player { _io = io; _random = random; - Strategy = Strategy.Check; + Strategy = Strategy.None; } public Strategy Strategy { get; set; } - public override void NewHand() - { - base.NewHand(); - } - protected override void DrawCards(Deck deck) { var keepMask = Strategy.KeepMask ?? Hand.KeepMask; @@ -65,19 +60,21 @@ internal class Computer : Player return true; } - public bool TrySellWatch() + public void RaiseFunds() { - if (Table.Human.HasWatch) { return false; } + if (Table.Human.HasWatch) { return; } var response = _io.ReadString("Would you like to buy back your watch for $50"); - if (response.StartsWith("N", InvariantCultureIgnoreCase)) { return false; } + if (response.StartsWith("N", InvariantCultureIgnoreCase)) { return; } // The original code does not deduct $50 from the player Balance += 50; Table.Human.ReceiveWatch(); - return true; + IsBroke = true; } + public void CheckFunds() { IsBroke = Balance <= Table.Ante; } + public override void TakeWinnings() { _io.WriteLine("I win."); diff --git a/71_Poker/csharp/Players/Human.cs b/71_Poker/csharp/Players/Human.cs index 0a3f4234..f7b4cfb2 100644 --- a/71_Poker/csharp/Players/Human.cs +++ b/71_Poker/csharp/Players/Human.cs @@ -30,18 +30,18 @@ internal class Human : Player _io.Write(Hand); } - public bool IsBroke() + public void RaiseFunds() { _io.WriteLine(); _io.WriteLine("You can't bet with what you haven't got."); - if (Table.Computer.TryBuyWatch()) { return false; } + if (Table.Computer.TryBuyWatch()) { return; } // 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; + IsBroke = true; } public void ReceiveWatch() diff --git a/71_Poker/csharp/Players/Player.cs b/71_Poker/csharp/Players/Player.cs index 4e9f7faf..65e7e685 100644 --- a/71_Poker/csharp/Players/Player.cs +++ b/71_Poker/csharp/Players/Player.cs @@ -18,6 +18,7 @@ internal abstract class Player public bool HasBet { get; set; } public int Bet { get; set; } public bool HasFolded => _hasFolded; + public bool IsBroke { get; protected set; } protected Table Table => _table ?? throw new InvalidOperationException("The player must be sitting at the table."); diff --git a/71_Poker/csharp/Strategies/Strategy.cs b/71_Poker/csharp/Strategies/Strategy.cs index 9a5d6842..ae6c93d2 100644 --- a/71_Poker/csharp/Strategies/Strategy.cs +++ b/71_Poker/csharp/Strategies/Strategy.cs @@ -2,6 +2,7 @@ namespace Poker.Strategies; internal abstract class Strategy { + public static Strategy None = new None(); public static Strategy Fold = new Fold(); public static Strategy Check = new Check(); public static Strategy Raise = new Raise(); diff --git a/71_Poker/csharp/Table.cs b/71_Poker/csharp/Table.cs index 059d2fff..925e0469 100644 --- a/71_Poker/csharp/Table.cs +++ b/71_Poker/csharp/Table.cs @@ -79,6 +79,8 @@ internal class Table return true; } + public bool SomeoneIsBroke() => Human.IsBroke || Computer.IsBroke; + public Player? GetWinner() { _io.WriteLine(); @@ -94,4 +96,22 @@ internal class Table _io.WriteLine($"All $ {Pot} remains in the pot."); return null; } + + internal bool IsGameOver() + { + if (Computer.IsBroke) + { + _io.WriteLine("I'm busted. Congratulations!"); + return true; + } + + if (Human.IsBroke) + { + _io.WriteLine("Your wad is shot. So long, sucker!"); + return true; + } + + _io.WriteLine($"Now I have $ {Computer.Balance} and you have $ {Human.Balance}"); + return !_io.ReadYesNo("Do you wish to continue"); + } } \ No newline at end of file From a777b3888bb6dabe7c8ffd7b78a0a4085ff201bc Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Sat, 25 Jun 2022 16:12:20 +1000 Subject: [PATCH 26/29] Remove global V --- 71_Poker/csharp/Game.cs | 33 ++++++++++++++---------------- 71_Poker/csharp/Strategies/None.cs | 6 ++++++ 2 files changed, 21 insertions(+), 18 deletions(-) create mode 100644 71_Poker/csharp/Strategies/None.cs diff --git a/71_Poker/csharp/Game.cs b/71_Poker/csharp/Game.cs index ef7f6d76..7bc3d0bb 100644 --- a/71_Poker/csharp/Game.cs +++ b/71_Poker/csharp/Game.cs @@ -10,8 +10,6 @@ internal class Game private readonly IReadWrite _io; private readonly IRandom _random; - private int V; - public Game(IReadWrite io, IRandom random) { _io = io; @@ -67,12 +65,12 @@ internal class Game }; if (table.Computer.Strategy is Bet) { - V = table.Computer.Strategy.Value + Get0To9(); - if (table.Computer.Balance - table.Human.Bet - V < 0) + var bet = table.Computer.Strategy.Value + Get0To9(); + if (table.Computer.Balance - table.Human.Bet - bet < 0) { if (table.Human.Bet == 0) { - V = table.Computer.Balance; + bet = table.Computer.Balance; } else if (table.Computer.Balance - table.Human.Bet >= 0) { @@ -86,8 +84,8 @@ internal class Game if (table.Computer.IsBroke) { return; } } } - _io.WriteLine($"I'll open with ${V}"); - table.Computer.Bet = V; + _io.WriteLine($"I'll open with ${bet}"); + table.Computer.Bet = bet; } else { @@ -115,12 +113,12 @@ internal class Game } else if (table.Computer.Strategy is Bet) { - V = table.Computer.Strategy.Value + Get0To9(); - if (table.Computer.Balance - table.Human.Bet - V < 0) + var bet = table.Computer.Strategy.Value + Get0To9(); + if (table.Computer.Balance - table.Human.Bet - bet < 0) { if (table.Human.Bet == 0) { - V = table.Computer.Balance; + bet = table.Computer.Balance; } else if (table.Computer.Balance - table.Human.Bet >= 0) { @@ -134,8 +132,8 @@ internal class Game if (table.Computer.IsBroke) { return; } } } - _io.WriteLine($"I'll bet ${V}"); - table.Computer.Bet = V; + _io.WriteLine($"I'll bet ${bet}"); + table.Computer.Bet = bet; GetWager(table.Computer.Strategy); if (table.SomeoneIsBroke() || table.SomeoneHasFolded()) { return; } } @@ -195,7 +193,6 @@ internal class Game _io.WriteLine("I fold."); return; } - V = 5; } if (table.Human.Bet > 3 * computerStrategy.Value) { @@ -208,12 +205,12 @@ internal class Game } } - V = table.Human.Bet - table.Computer.Bet + Get0To9(); - if (table.Computer.Balance - table.Human.Bet - V < 0) + var raise = table.Human.Bet - table.Computer.Bet + Get0To9(); + if (table.Computer.Balance - table.Human.Bet - raise < 0) { if (table.Human.Bet == 0) { - V = table.Computer.Balance; + raise = table.Computer.Balance; } else if (table.Computer.Balance - table.Human.Bet >= 0) { @@ -227,8 +224,8 @@ internal class Game if (table.Computer.IsBroke) { return; } } } - _io.WriteLine($"I'll see you, and raise you{V}"); - table.Computer.Bet = table.Human.Bet + V; + _io.WriteLine($"I'll see you, and raise you {raise}"); + table.Computer.Bet = table.Human.Bet + raise; } } } diff --git a/71_Poker/csharp/Strategies/None.cs b/71_Poker/csharp/Strategies/None.cs new file mode 100644 index 00000000..4be351a8 --- /dev/null +++ b/71_Poker/csharp/Strategies/None.cs @@ -0,0 +1,6 @@ +namespace Poker.Strategies; + +internal class None : Strategy +{ + public override int Value => -1; +} From e47864c47f8c3c1ff811ed0c0cf340c3f5470c1b Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Sat, 25 Jun 2022 16:16:31 +1000 Subject: [PATCH 27/29] Fix hand comparison text --- 71_Poker/csharp/Game.cs | 2 +- 71_Poker/csharp/Players/Human.cs | 1 - 71_Poker/csharp/Table.cs | 8 ++++---- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/71_Poker/csharp/Game.cs b/71_Poker/csharp/Game.cs index 7bc3d0bb..4d363253 100644 --- a/71_Poker/csharp/Game.cs +++ b/71_Poker/csharp/Game.cs @@ -31,7 +31,7 @@ internal class Game do { PlayHand(table); - } while (!table.IsGameOver()); + } while (table.ShouldPlayAnotherHand()); } internal void PlayHand(Table table) diff --git a/71_Poker/csharp/Players/Human.cs b/71_Poker/csharp/Players/Human.cs index f7b4cfb2..cf42413e 100644 --- a/71_Poker/csharp/Players/Human.cs +++ b/71_Poker/csharp/Players/Human.cs @@ -40,7 +40,6 @@ internal class Human : Player // 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!"); IsBroke = true; } diff --git a/71_Poker/csharp/Table.cs b/71_Poker/csharp/Table.cs index 925e0469..0bafb775 100644 --- a/71_Poker/csharp/Table.cs +++ b/71_Poker/csharp/Table.cs @@ -88,8 +88,8 @@ internal class Table _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}"); + _io.WriteLine($"You have {Human.Hand.Name}"); + _io.WriteLine($"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."); @@ -97,7 +97,7 @@ internal class Table return null; } - internal bool IsGameOver() + internal bool ShouldPlayAnotherHand() { if (Computer.IsBroke) { @@ -112,6 +112,6 @@ internal class Table } _io.WriteLine($"Now I have $ {Computer.Balance} and you have $ {Human.Balance}"); - return !_io.ReadYesNo("Do you wish to continue"); + return _io.ReadYesNo("Do you wish to continue"); } } \ No newline at end of file From a132e881fe1553ae9f0499b21a5b4331dee388d5 Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Fri, 1 Jul 2022 14:25:48 +1000 Subject: [PATCH 28/29] Move PlayHand logic to table --- 71_Poker/csharp/Game.cs | 211 +--------------------------- 71_Poker/csharp/Players/Computer.cs | 47 +++++++ 71_Poker/csharp/Table.cs | 135 ++++++++++++++++-- 3 files changed, 180 insertions(+), 213 deletions(-) diff --git a/71_Poker/csharp/Game.cs b/71_Poker/csharp/Game.cs index 4d363253..c7621a36 100644 --- a/71_Poker/csharp/Game.cs +++ b/71_Poker/csharp/Game.cs @@ -1,7 +1,6 @@ using Poker.Cards; using Poker.Players; using Poker.Resources; -using Poker.Strategies; namespace Poker; @@ -16,217 +15,19 @@ internal class Game _random = random; } - private int Get0To9() => _random.Next(10); - internal void Play() { - var deck = new Deck(); - var human = new Human(200, _io); - var computer = new Computer(200, _io, _random); - var table = new Table(_io, deck, human, computer); - _io.Write(Resource.Streams.Title); _io.Write(Resource.Streams.Instructions); + var deck = new Deck(); + var human = new Human(200, _io); + var computer = new Computer(200, _io, _random); + var table = new Table(_io, _random, deck, human, computer); + do { - PlayHand(table); + table.PlayHand(); } while (table.ShouldPlayAnotherHand()); } - - internal void PlayHand(Table table) - { - while (true) - { - _io.WriteLine(); - table.Computer.CheckFunds(); - if (table.Computer.IsBroke) { return; } - - _io.WriteLine($"The ante is ${table.Ante}. I will deal:"); - _io.WriteLine(); - if (table.Human.Balance <= table.Ante) - { - table.Human.RaiseFunds(); - if (table.Human.IsBroke) { return; } - } - - table.Deal(_random); - - _io.WriteLine(); - table.Computer.Strategy = (table.Computer.Hand.IsWeak, table.Computer.Hand.Rank < HandRank.Three, table.Computer.Hand.Rank < HandRank.FullHouse) switch - { - (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 (table.Computer.Strategy is Bet) - { - var bet = table.Computer.Strategy.Value + Get0To9(); - if (table.Computer.Balance - table.Human.Bet - bet < 0) - { - if (table.Human.Bet == 0) - { - bet = table.Computer.Balance; - } - else if (table.Computer.Balance - table.Human.Bet >= 0) - { - _io.WriteLine("I'll see you."); - table.Computer.Bet = table.Human.Bet; - table.UpdatePot(); - } - else - { - table.Computer.RaiseFunds(); - if (table.Computer.IsBroke) { return; } - } - } - _io.WriteLine($"I'll open with ${bet}"); - table.Computer.Bet = bet; - } - else - { - _io.WriteLine("I check."); - } - GetWager(table.Computer.Strategy); - if (table.SomeoneIsBroke() || table.SomeoneHasFolded()) { return; } - - table.Draw(); - - table.Computer.Strategy = (table.Computer.Hand.IsWeak, table.Computer.Hand.Rank < HandRank.Three, table.Computer.Hand.Rank < HandRank.FullHouse) switch - { - _ 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 - }; - - GetWager(table.Computer.Strategy); - if (table.SomeoneIsBroke()) { return; } - if (table.Human.HasBet) - { - if (table.SomeoneHasFolded()) { return; } - } - else if (table.Computer.Strategy is Bet) - { - var bet = table.Computer.Strategy.Value + Get0To9(); - if (table.Computer.Balance - table.Human.Bet - bet < 0) - { - if (table.Human.Bet == 0) - { - bet = table.Computer.Balance; - } - else if (table.Computer.Balance - table.Human.Bet >= 0) - { - _io.WriteLine("I'll see you."); - table.Computer.Bet = table.Human.Bet; - table.UpdatePot(); - } - else - { - table.Computer.RaiseFunds(); - if (table.Computer.IsBroke) { return; } - } - } - _io.WriteLine($"I'll bet ${bet}"); - table.Computer.Bet = bet; - GetWager(table.Computer.Strategy); - if (table.SomeoneIsBroke() || table.SomeoneHasFolded()) { return; } - } - else - { - _io.WriteLine("I'll check"); - } - if (table.GetWinner() is { } winner) - { - winner.TakeWinnings(); - return; - } - } - - void GetWager(Strategy computerStrategy) - { - while (true) - { - table.Human.HasBet = false; - while (true) - { - var humanStrategy = _io.ReadHumanStrategy(table.Computer.Bet == 0 && table.Human.Bet == 0); - if (humanStrategy is Bet or Check) - { - 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 - humanStrategy.Value >= 0) - { - table.Human.HasBet = true; - table.Human.Bet += humanStrategy.Value; - break; - } - table.Human.RaiseFunds(); - if (table.Human.IsBroke) { return; } - continue; - } - else - { - table.Human.Fold(); - table.UpdatePot(); - return; - } - } - if (table.Human.Bet == table.Computer.Bet) - { - table.UpdatePot(); - return; - } - if (computerStrategy is Fold) - { - if (table.Human.Bet > 5) - { - table.Computer.Fold(); - _io.WriteLine("I fold."); - return; - } - } - if (table.Human.Bet > 3 * computerStrategy.Value) - { - if (computerStrategy is not Raise) - { - _io.WriteLine("I'll see you."); - table.Computer.Bet = table.Human.Bet; - table.UpdatePot(); - return; - } - } - - var raise = table.Human.Bet - table.Computer.Bet + Get0To9(); - if (table.Computer.Balance - table.Human.Bet - raise < 0) - { - if (table.Human.Bet == 0) - { - raise = table.Computer.Balance; - } - else if (table.Computer.Balance - table.Human.Bet >= 0) - { - _io.WriteLine("I'll see you."); - table.Computer.Bet = table.Human.Bet; - table.UpdatePot(); - } - else - { - table.Computer.RaiseFunds(); - if (table.Computer.IsBroke) { return; } - } - } - _io.WriteLine($"I'll see you, and raise you {raise}"); - table.Computer.Bet = table.Human.Bet + raise; - } - } - } } diff --git a/71_Poker/csharp/Players/Computer.cs b/71_Poker/csharp/Players/Computer.cs index 5f2ec399..af82eef8 100644 --- a/71_Poker/csharp/Players/Computer.cs +++ b/71_Poker/csharp/Players/Computer.cs @@ -19,6 +19,22 @@ internal class Computer : Player public Strategy Strategy { get; set; } + public override void NewHand() + { + base.NewHand(); + + Strategy = (Hand.IsWeak, Hand.Rank < HandRank.Three, Hand.Rank < HandRank.FullHouse) switch + { + (true, _, _) when _random.Next(10) < 2 => Strategy.Bluff(23, 0b11100), + (true, _, _) when _random.Next(10) < 2 => Strategy.Bluff(23, 0b11110), + (true, _, _) when _random.Next(10) < 1 => Strategy.Bluff(23, 0b11111), + (true, _, _) => Strategy.Fold, + (false, true, _) => _random.Next(10) < 2 ? Strategy.Bluff(23) : Strategy.Check, + (false, false, true) => Strategy.Bet(35), + (false, false, false) => _random.Next(10) < 1 ? Strategy.Bet(35) : Strategy.Raise + }; + } + protected override void DrawCards(Deck deck) { var keepMask = Strategy.KeepMask ?? Hand.KeepMask; @@ -38,6 +54,37 @@ internal class Computer : Player { _io.WriteLine("s"); } + + Strategy = (Hand.IsWeak, Hand.Rank < HandRank.Three, Hand.Rank < HandRank.FullHouse) switch + { + _ when Strategy is Bluff => Strategy.Bluff(28), + (true, _, _) => Strategy.Fold, + (false, true, _) => _random.Next(10) == 0 ? Strategy.Bet(19) : Strategy.Raise, + (false, false, true) => _random.Next(10) == 0 ? Strategy.Bet(11) : Strategy.Bet(19), + (false, false, false) => Strategy.Raise + }; + } + + public int GetWager(int wager) + { + wager += _random.Next(10); + if (Balance < Table.Human.Bet + wager) + { + if (Table.Human.Bet == 0) { return Balance; } + + if (Balance >= Table.Human.Bet) + { + _io.WriteLine("I'll see you."); + Bet = Table.Human.Bet; + Table.UpdatePot(); + } + else + { + RaiseFunds(); + } + } + + return wager; } public bool TryBuyWatch() diff --git a/71_Poker/csharp/Table.cs b/71_Poker/csharp/Table.cs index 0bafb775..b0510a8e 100644 --- a/71_Poker/csharp/Table.cs +++ b/71_Poker/csharp/Table.cs @@ -1,16 +1,19 @@ using Poker.Cards; using Poker.Players; +using Poker.Strategies; namespace Poker; internal class Table { private readonly IReadWrite _io; + private readonly IRandom _random; public int Pot; - public Table(IReadWrite io, Deck deck, Human human, Computer computer) + public Table(IReadWrite io, IRandom random, Deck deck, Human human, Computer computer) { _io = io; + _random = random; Deck = deck; Human = human; Computer = computer; @@ -24,7 +27,46 @@ internal class Table public Human Human { get; } public Computer Computer { get; } - public void Deal(IRandom random) + internal void PlayHand() + { + while (true) + { + _io.WriteLine(); + Computer.CheckFunds(); + if (Computer.IsBroke) { return; } + + _io.WriteLine($"The ante is ${Ante}. I will deal:"); + _io.WriteLine(); + if (Human.Balance <= Ante) + { + Human.RaiseFunds(); + if (Human.IsBroke) { return; } + } + + Deal(_random); + + _io.WriteLine(); + GetWagers("I'll open with ${0}", "I check.", allowRaiseAfterCheck: true); + if (SomeoneIsBroke() || SomeoneHasFolded()) { return; } + + Draw(); + + GetWagers(); + if (SomeoneIsBroke()) { return; } + if (!Human.HasBet) + { + GetWagers("I'll bet ${0}", "I'll check"); + } + if (SomeoneIsBroke() || SomeoneHasFolded()) { return; } + if (GetWinner() is { } winner) + { + winner.TakeWinnings(); + return; + } + } + } + + private void Deal(IRandom random) { Deck.Shuffle(random); @@ -37,7 +79,7 @@ internal class Table _io.Write(Human.Hand); } - public void Draw() + private void Draw() { _io.WriteLine(); _io.Write("Now we draw -- "); @@ -46,19 +88,96 @@ internal class Table _io.WriteLine(); } - public void AcceptBets() + private void GetWagers(string betFormat, string checkMessage, bool allowRaiseAfterCheck = false) { + if (Computer.Strategy is Bet) + { + Computer.Bet = Computer.GetWager(Computer.Strategy.Value); + if (Computer.IsBroke) { return; } + _io.WriteLine(betFormat, Computer.Bet); + } + else + { + _io.WriteLine(checkMessage); + if (!allowRaiseAfterCheck) { return; } + } + + GetWagers(); } - public void UpdatePot() + private void GetWagers() + { + while (true) + { + Human.HasBet = false; + while (true) + { + var humanStrategy = _io.ReadHumanStrategy(Computer.Bet == 0 && Human.Bet == 0); + if (humanStrategy is Bet or Check) + { + if (Human.Bet + humanStrategy.Value < Computer.Bet) + { + _io.WriteLine("If you can't see my bet, then fold."); + continue; + } + if (Human.Balance - Human.Bet - humanStrategy.Value >= 0) + { + Human.HasBet = true; + Human.Bet += humanStrategy.Value; + break; + } + Human.RaiseFunds(); + if (Human.IsBroke) { return; } + continue; + } + else + { + Human.Fold(); + UpdatePot(); + return; + } + } + if (Human.Bet == Computer.Bet) + { + UpdatePot(); + return; + } + if (Computer.Strategy is Fold) + { + if (Human.Bet > 5) + { + Computer.Fold(); + _io.WriteLine("I fold."); + return; + } + } + if (Human.Bet > 3 * Computer.Strategy.Value) + { + if (Computer.Strategy is not Raise) + { + _io.WriteLine("I'll see you."); + Computer.Bet = Human.Bet; + UpdatePot(); + return; + } + } + + var raise = Computer.GetWager(Human.Bet - Computer.Bet); + if (Computer.IsBroke) { return; } + _io.WriteLine($"I'll see you, and raise you {raise}"); + Computer.Bet = Human.Bet + raise; + } + } + + private void UpdatePot() { Human.Balance -= Human.Bet; Computer.Balance -= Computer.Bet; Pot += Human.Bet + Computer.Bet; } - public bool SomeoneHasFolded() + private bool SomeoneHasFolded() { if (Human.HasFolded) { @@ -79,9 +198,9 @@ internal class Table return true; } - public bool SomeoneIsBroke() => Human.IsBroke || Computer.IsBroke; + private bool SomeoneIsBroke() => Human.IsBroke || Computer.IsBroke; - public Player? GetWinner() + private Player? GetWinner() { _io.WriteLine(); _io.WriteLine("Now we compare hands:"); From 1558bfbfe876ae81709d3d9cfa3337ba11ee2056 Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Fri, 1 Jul 2022 17:20:13 +1000 Subject: [PATCH 29/29] CSHARP-71 Move Human GetWager logic --- 71_Poker/csharp/Players/Computer.cs | 2 +- 71_Poker/csharp/Players/Human.cs | 27 ++++++++++++++++++++++++ 71_Poker/csharp/Table.cs | 32 +++++------------------------ 3 files changed, 33 insertions(+), 28 deletions(-) diff --git a/71_Poker/csharp/Players/Computer.cs b/71_Poker/csharp/Players/Computer.cs index af82eef8..5ab2e77d 100644 --- a/71_Poker/csharp/Players/Computer.cs +++ b/71_Poker/csharp/Players/Computer.cs @@ -76,7 +76,7 @@ internal class Computer : Player { _io.WriteLine("I'll see you."); Bet = Table.Human.Bet; - Table.UpdatePot(); + Table.CollectBets(); } else { diff --git a/71_Poker/csharp/Players/Human.cs b/71_Poker/csharp/Players/Human.cs index cf42413e..ec3e7d3c 100644 --- a/71_Poker/csharp/Players/Human.cs +++ b/71_Poker/csharp/Players/Human.cs @@ -1,4 +1,5 @@ using Poker.Cards; +using Poker.Strategies; namespace Poker.Players; @@ -30,6 +31,32 @@ internal class Human : Player _io.Write(Hand); } + internal bool SetWager() + { + var strategy = _io.ReadHumanStrategy(Table.Computer.Bet == 0 && Bet == 0); + if (strategy is Strategies.Bet or Check) + { + if (Bet + strategy.Value < Table.Computer.Bet) + { + _io.WriteLine("If you can't see my bet, then fold."); + return false; + } + if (Balance - Bet - strategy.Value >= 0) + { + HasBet = true; + Bet += strategy.Value; + return true; + } + RaiseFunds(); + } + else + { + Fold(); + Table.CollectBets(); + } + return false; + } + public void RaiseFunds() { _io.WriteLine(); diff --git a/71_Poker/csharp/Table.cs b/71_Poker/csharp/Table.cs index b0510a8e..da819801 100644 --- a/71_Poker/csharp/Table.cs +++ b/71_Poker/csharp/Table.cs @@ -113,34 +113,12 @@ internal class Table Human.HasBet = false; while (true) { - var humanStrategy = _io.ReadHumanStrategy(Computer.Bet == 0 && Human.Bet == 0); - if (humanStrategy is Bet or Check) - { - if (Human.Bet + humanStrategy.Value < Computer.Bet) - { - _io.WriteLine("If you can't see my bet, then fold."); - continue; - } - if (Human.Balance - Human.Bet - humanStrategy.Value >= 0) - { - Human.HasBet = true; - Human.Bet += humanStrategy.Value; - break; - } - Human.RaiseFunds(); - if (Human.IsBroke) { return; } - continue; - } - else - { - Human.Fold(); - UpdatePot(); - return; - } + if (Human.SetWager()) { break; } + if (Human.IsBroke || Human.HasFolded) { return; } } if (Human.Bet == Computer.Bet) { - UpdatePot(); + CollectBets(); return; } if (Computer.Strategy is Fold) @@ -158,7 +136,7 @@ internal class Table { _io.WriteLine("I'll see you."); Computer.Bet = Human.Bet; - UpdatePot(); + CollectBets(); return; } } @@ -170,7 +148,7 @@ internal class Table } } - private void UpdatePot() + internal void CollectBets() { Human.Balance -= Human.Bet; Computer.Balance -= Computer.Bet;