diff --git a/17 Bullfight/csharp/Bullfight.sln b/17 Bullfight/csharp/Bullfight.sln
new file mode 100644
index 00000000..29f5276f
--- /dev/null
+++ b/17 Bullfight/csharp/Bullfight.sln
@@ -0,0 +1,25 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.31321.278
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Game", "Game.csproj", "{8F7C450E-5F3A-45BA-9DB9-329744214931}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {8F7C450E-5F3A-45BA-9DB9-329744214931}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {8F7C450E-5F3A-45BA-9DB9-329744214931}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {8F7C450E-5F3A-45BA-9DB9-329744214931}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {8F7C450E-5F3A-45BA-9DB9-329744214931}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {C5BFC749-C7D8-4981-A7D4-1D401901A890}
+ EndGlobalSection
+EndGlobal
diff --git a/17 Bullfight/csharp/Game.csproj b/17 Bullfight/csharp/Game.csproj
new file mode 100644
index 00000000..849a99d4
--- /dev/null
+++ b/17 Bullfight/csharp/Game.csproj
@@ -0,0 +1,7 @@
+
+
+ Exe
+ net5.0
+ enable
+
+
diff --git a/17 Bullfight/csharp/src/Action.cs b/17 Bullfight/csharp/src/Action.cs
new file mode 100644
index 00000000..2a148683
--- /dev/null
+++ b/17 Bullfight/csharp/src/Action.cs
@@ -0,0 +1,24 @@
+namespace Game
+{
+ ///
+ /// Enumerates the different actions that the player can take on each round
+ /// of the fight.
+ ///
+ public enum Action
+ {
+ ///
+ /// Dodge the bull.
+ ///
+ Dodge,
+
+ ///
+ /// Kill the bull.
+ ///
+ Kill,
+
+ ///
+ /// Freeze in place and don't do anything.
+ ///
+ Panic
+ }
+}
diff --git a/17 Bullfight/csharp/src/ActionResult.cs b/17 Bullfight/csharp/src/ActionResult.cs
new file mode 100644
index 00000000..baa74f2e
--- /dev/null
+++ b/17 Bullfight/csharp/src/ActionResult.cs
@@ -0,0 +1,44 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Game
+{
+ ///
+ /// Enumerates the different possible outcomes of the player's action.
+ ///
+ public enum ActionResult
+ {
+ ///
+ /// The fight continues.
+ ///
+ FightContinues,
+
+ ///
+ /// The player fled from the ring.
+ ///
+ PlayerFlees,
+
+ ///
+ /// The bull has gored the player.
+ ///
+ BullGoresPlayer,
+
+ ///
+ /// The bull killed the player.
+ ///
+ BullKillsPlayer,
+
+ ///
+ /// The player killed the bull.
+ ///
+ PlayerKillsBull,
+
+ ///
+ /// The player attempted to kill the bull and both survived.
+ ///
+ Draw
+ }
+}
diff --git a/17 Bullfight/csharp/src/Controller.cs b/17 Bullfight/csharp/src/Controller.cs
new file mode 100644
index 00000000..2355e247
--- /dev/null
+++ b/17 Bullfight/csharp/src/Controller.cs
@@ -0,0 +1,129 @@
+using System;
+
+namespace Game
+{
+ ///
+ /// Contains functions for getting input from the user.
+ ///
+ public static class Controller
+ {
+ ///
+ /// Handles the initial interaction with the player.
+ ///
+ public static void StartGame()
+ {
+ View.ShowBanner();
+ View.PromptShowInstructions();
+
+ var input = Console.ReadLine();
+ if (input is null)
+ Environment.Exit(0);
+
+ if (input.ToUpperInvariant() != "NO")
+ View.ShowInstructions();
+
+ View.ShowSeparator();
+ }
+
+ ///
+ /// Gets the player's action for the current round.
+ ///
+ ///
+ /// The current pass number.
+ ///
+ public static (Action action, RiskLevel riskLevel) GetPlayerIntention(int passNumber)
+ {
+ if (passNumber < 3)
+ View.PromptKillBull();
+ else
+ View.PromptKillBullBrief();
+
+ var attemptToKill = GetYesOrNo();
+
+ if (attemptToKill)
+ {
+ View.PromptKillMethod();
+
+ var input = Console.ReadLine();
+ if (input is null)
+ Environment.Exit(0);
+
+ return input switch
+ {
+ "4" => (Action.Kill, RiskLevel.High),
+ "5" => (Action.Kill, RiskLevel.Low),
+ _ => (Action.Panic, default(RiskLevel))
+ };
+ }
+ else
+ {
+ if (passNumber < 2)
+ View.PromptCapeMove();
+ else
+ View.PromptCapeMoveBrief();
+
+ var action = Action.Panic;
+ var riskLevel = default(RiskLevel);
+
+ while (action == Action.Panic)
+ {
+ var input = Console.ReadLine();
+ if (input is null)
+ Environment.Exit(0);
+
+ (action, riskLevel) = input switch
+ {
+ "0" => (Action.Dodge, RiskLevel.High),
+ "1" => (Action.Dodge, RiskLevel.Medium),
+ "2" => (Action.Dodge, RiskLevel.Low),
+ _ => (Action.Panic, default(RiskLevel))
+ };
+
+ if (action == Action.Panic)
+ View.PromptDontPanic();
+ }
+
+ return (action, riskLevel);
+ }
+ }
+
+ ///
+ /// Gets the player's intention to flee (or not).
+ ///
+ ///
+ /// True if the player flees; otherwise, false.
+ ///
+ public static bool PlayerRunsFromRing()
+ {
+ View.PromptRunFromRing();
+ return GetYesOrNo();
+ }
+
+ ///
+ /// Gets a yes or no response from the player.
+ ///
+ ///
+ /// True if the user answered yes; otherwise, false.
+ ///
+ public static bool GetYesOrNo()
+ {
+ while (true)
+ {
+ var input = Console.ReadLine();
+ if (input is null)
+ Environment.Exit(0);
+
+ switch (input.ToUpperInvariant())
+ {
+ case "YES":
+ return true;
+ case "NO":
+ return false;
+ default:
+ Console.WriteLine("INCORRECT ANSWER - - PLEASE TYPE 'YES' OR 'NO'.");
+ break;
+ }
+ }
+ }
+ }
+}
diff --git a/17 Bullfight/csharp/src/MatchConditions.cs b/17 Bullfight/csharp/src/MatchConditions.cs
new file mode 100644
index 00000000..5d5d979c
--- /dev/null
+++ b/17 Bullfight/csharp/src/MatchConditions.cs
@@ -0,0 +1,41 @@
+namespace Game
+{
+ ///
+ /// Stores the initial conditions of a match.
+ ///
+ public record MatchConditions
+ {
+ ///
+ /// Gets the quality of the bull.
+ ///
+ public Quality BullQuality { get; init; }
+
+ ///
+ /// Gets the quality of help received from the toreadores.
+ ///
+ public Quality ToreadorePerformance { get; init; }
+
+ ///
+ /// Gets the quality of help received from the picadores.
+ ///
+ public Quality PicadorePerformance { get; init; }
+
+ ///
+ /// Gets the number of toreadores killed while preparing for the
+ /// final round.
+ ///
+ public int ToreadoresKilled { get; init; }
+
+ ///
+ /// Gets the number of picadores killed while preparing for the
+ /// final round.
+ ///
+ public int PicadoresKilled { get; init; }
+
+ ///
+ /// Gets the number of horses killed while preparing for the final
+ /// round.
+ ///
+ public int HorsesKilled { get; init; }
+ }
+}
diff --git a/17 Bullfight/csharp/src/MatchState.cs b/17 Bullfight/csharp/src/MatchState.cs
new file mode 100644
index 00000000..3eae6d5d
--- /dev/null
+++ b/17 Bullfight/csharp/src/MatchState.cs
@@ -0,0 +1,28 @@
+namespace Game
+{
+ ///
+ /// Stores the current state of the match.
+ ///
+ public record MatchState(MatchConditions Conditions)
+ {
+ ///
+ /// Gets the number of times the bull has charged.
+ ///
+ public int PassNumber { get; init; }
+
+ ///
+ /// Measures the player's bravery during the match.
+ ///
+ public double Bravery { get; init; }
+
+ ///
+ /// Measures how much style the player showed during the match.
+ ///
+ public double Style { get; init; }
+
+ ///
+ /// Gets the result of the player's last action.
+ ///
+ public ActionResult Result { get; init; }
+ }
+}
diff --git a/17 Bullfight/csharp/src/Program.cs b/17 Bullfight/csharp/src/Program.cs
new file mode 100644
index 00000000..17da736f
--- /dev/null
+++ b/17 Bullfight/csharp/src/Program.cs
@@ -0,0 +1,56 @@
+using System;
+
+namespace Game
+{
+ class Program
+ {
+ static void Main()
+ {
+ Controller.StartGame();
+
+ var random = new Random();
+ var match = Rules.StartMatch(random);
+ View.ShowStartingConditions(match.Conditions);
+
+ while (match.Result == ActionResult.FightContinues)
+ {
+ match = match with { PassNumber = match.PassNumber + 1 };
+
+ View.StartOfPass(match.PassNumber);
+
+ var (action, riskLevel) = Controller.GetPlayerIntention(match.PassNumber);
+ match = action switch
+ {
+ Action.Dodge => Rules.TryDodge(random, riskLevel, match),
+ Action.Kill => Rules.TryKill(random, riskLevel, match),
+ _ => Rules.Panic(match)
+ };
+
+ var first = true;
+ while (match.Result == ActionResult.BullGoresPlayer)
+ {
+ View.ShowPlayerGored(action == Action.Panic, first);
+ first = false;
+
+ match = Rules.TrySurvive(random, match);
+ if (match.Result == ActionResult.FightContinues)
+ {
+ View.ShowPlayerSurvives();
+
+ if (Controller.PlayerRunsFromRing())
+ {
+ match = Rules.Flee(match);
+ }
+ else
+ {
+ View.ShowPlayerFoolhardy();
+ match = Rules.IgnoreInjury(random, action, match);
+ }
+ }
+ }
+ }
+
+ View.ShowFinalResult(match.Result, match.Bravery, Rules.GetReward(random, match));
+ }
+ }
+}
diff --git a/17 Bullfight/csharp/src/Quality.cs b/17 Bullfight/csharp/src/Quality.cs
new file mode 100644
index 00000000..ee7bf6d9
--- /dev/null
+++ b/17 Bullfight/csharp/src/Quality.cs
@@ -0,0 +1,19 @@
+namespace Game
+{
+ ///
+ /// Enumerates the different levels of quality in the game.
+ ///
+ ///
+ /// Quality applies both to the bull and to the help received from the
+ /// toreadores and picadores. Note that the ordinal values are significant
+ /// (these are used in various calculations).
+ ///
+ public enum Quality
+ {
+ Superb = 1,
+ Good = 2,
+ Fair = 3,
+ Poor = 4,
+ Awful = 5
+ }
+}
diff --git a/17 Bullfight/csharp/src/Reward.cs b/17 Bullfight/csharp/src/Reward.cs
new file mode 100644
index 00000000..295789be
--- /dev/null
+++ b/17 Bullfight/csharp/src/Reward.cs
@@ -0,0 +1,13 @@
+namespace Game
+{
+ ///
+ /// Enumerates the different things the player can be awarded.
+ ///
+ public enum Reward
+ {
+ Nothing,
+ OneEar,
+ TwoEars,
+ CarriedFromRing
+ }
+}
diff --git a/17 Bullfight/csharp/src/RiskLevel.cs b/17 Bullfight/csharp/src/RiskLevel.cs
new file mode 100644
index 00000000..8048f663
--- /dev/null
+++ b/17 Bullfight/csharp/src/RiskLevel.cs
@@ -0,0 +1,12 @@
+namespace Game
+{
+ ///
+ /// Enumerates the different levels of risk for manoeuvres in the game.
+ ///
+ public enum RiskLevel
+ {
+ Low,
+ Medium,
+ High
+ }
+}
diff --git a/17 Bullfight/csharp/src/Rules.cs b/17 Bullfight/csharp/src/Rules.cs
new file mode 100644
index 00000000..463af1ed
--- /dev/null
+++ b/17 Bullfight/csharp/src/Rules.cs
@@ -0,0 +1,258 @@
+using System;
+
+namespace Game
+{
+ ///
+ /// Provides functions implementing the rules of the game.
+ ///
+ public static class Rules
+ {
+ ///
+ /// Gets the state of a new match.
+ ///
+ ///
+ /// The random number generator.
+ ///
+ public static MatchState StartMatch(Random random)
+ {
+ var bullQuality = GetBullQuality();
+ var toreadorePerformance = GetHelpQuality();
+ var picadorePerformance = GetHelpQuality();
+
+ var conditions = new MatchConditions
+ {
+ BullQuality = bullQuality,
+ ToreadorePerformance = toreadorePerformance,
+ PicadorePerformance = picadorePerformance,
+ ToreadoresKilled = GetHumanCasualties(toreadorePerformance),
+ PicadoresKilled = GetHumanCasualties(picadorePerformance),
+ HorsesKilled = GetHorseCasualties(picadorePerformance)
+ };
+
+ return new MatchState(conditions)
+ {
+ Bravery = 1.0,
+ Style = 1.0
+ };
+
+ Quality GetBullQuality() =>
+ (Quality)random.Next(1, 6);
+
+ Quality GetHelpQuality() =>
+ ((3.0 / (int)bullQuality) * random.NextDouble()) switch
+ {
+ < 0.37 => Quality.Superb,
+ < 0.50 => Quality.Good,
+ < 0.63 => Quality.Fair,
+ < 0.87 => Quality.Poor,
+ _ => Quality.Awful
+ };
+
+ int GetHumanCasualties(Quality performance) =>
+ performance switch
+ {
+ Quality.Poor => random.Next(0, 2),
+ Quality.Awful => random.Next(1, 3),
+ _ => 0
+ };
+
+ int GetHorseCasualties(Quality performance) =>
+ performance switch
+ {
+ // NOTE: The code for displaying a single horse casuality
+ // following a poor picadore peformance was unreachable
+ // in the original BASIC version. I've assumed this was
+ // a bug.
+ Quality.Poor => 1,
+ Quality.Awful => random.Next(1, 3),
+ _ => 0
+ };
+ }
+
+ ///
+ /// Determines the result when the player attempts to dodge the bull.
+ ///
+ ///
+ /// The random number generator.
+ ///
+ ///
+ /// The level of risk in the dodge manoeuvre chosen.
+ ///
+ ///
+ /// The current match state.
+ ///
+ ///
+ /// The updated match state.
+ ///
+ public static MatchState TryDodge(Random random, RiskLevel riskLevel, MatchState match)
+ {
+ var difficultyModifier = riskLevel switch
+ {
+ RiskLevel.High => 3.0,
+ RiskLevel.Medium => 2.0,
+ _ => 0.5
+ };
+
+ var outcome = (GetBullStrength(match) + (difficultyModifier / 10)) * random.NextDouble() /
+ ((GetAssisstance(match) + (match.PassNumber / 10.0)) * 5);
+
+ return outcome < 0.51 ?
+ match with { Result = ActionResult.FightContinues, Style = match.Style + difficultyModifier } :
+ match with { Result = ActionResult.BullGoresPlayer };
+ }
+
+ ///
+ /// Determines the result when the player attempts to kill the bull.
+ ///
+ ///
+ /// The random number generator.
+ ///
+ ///
+ /// The level of risk in the manoeuvre chosen.
+ ///
+ ///
+ /// The current match state.
+ ///
+ ///
+ /// The updated match state.
+ ///
+ public static MatchState TryKill(Random random, RiskLevel riskLevel, MatchState match)
+ {
+ var K = GetBullStrength(match) * 10 * random.NextDouble() / (GetAssisstance(match) * 5 * match.PassNumber);
+
+ return ((riskLevel == RiskLevel.High && K > 0.2) || K > 0.8) ?
+ match with { Result = ActionResult.BullGoresPlayer } :
+ match with { Result = ActionResult.PlayerKillsBull };
+ }
+
+ ///
+ /// Determines if the player survives being gored by the bull.
+ ///
+ ///
+ /// The random number generator.
+ ///
+ ///
+ /// The current match state.
+ ///
+ ///
+ /// The updated match state.
+ ///
+ public static MatchState TrySurvive(Random random, MatchState match) =>
+ (random.Next(2) == 0) ?
+ match with { Result = ActionResult.BullKillsPlayer, Bravery = 1.5 } :
+ match with { Result = ActionResult.FightContinues };
+
+ ///
+ /// Determines the result when the player panics and fails to do anything.
+ ///
+ ///
+ /// The match state.
+ ///
+ public static MatchState Panic(MatchState match) =>
+ match with { Result = ActionResult.BullGoresPlayer };
+
+ ///
+ /// Determines the result when the player flees the ring.
+ ///
+ ///
+ /// The current match state.
+ ///
+ ///
+ /// The updated match state.
+ ///
+ public static MatchState Flee(MatchState match) =>
+ match with { Result = ActionResult.PlayerFlees, Bravery = 0.0 };
+
+ ///
+ /// Determines the result when the player decides to continue fighting
+ /// following an injury.
+ ///
+ ///
+ /// The random number generator.
+ ///
+ ///
+ /// The action the player took that lead to the injury.
+ ///
+ ///
+ /// The current match state.
+ ///
+ ///
+ /// The updated match state.
+ ///
+ public static MatchState IgnoreInjury(Random random, Action action, MatchState match) =>
+ (random.Next(2) == 0) ?
+ match with { Result = action == Action.Dodge ? ActionResult.FightContinues : ActionResult.Draw, Bravery = 2.0 } :
+ match with { Result = ActionResult.BullGoresPlayer };
+
+ ///
+ /// Gets the player's reward for completing a match.
+ ///
+ ///
+ /// The random number generator.
+ ///
+ ///
+ /// The final match state.
+ ///
+ public static Reward GetReward(Random random, MatchState match)
+ {
+ var score = CalculateScore();
+
+ if (score * random.NextDouble() < 2.4)
+ return Reward.Nothing;
+ else
+ if (score * random.NextDouble() < 4.9)
+ return Reward.OneEar;
+ else
+ if (score * random.NextDouble() < 7.4)
+ return Reward.TwoEars;
+ else
+ return Reward.CarriedFromRing;
+
+ double CalculateScore()
+ {
+ var score = 4.5;
+
+ // Style
+ score += match.Style / 6;
+
+ // Assisstance
+ score -= GetAssisstance(match) * 2.5;
+
+ // Courage
+ score += 4 * match.Bravery;
+
+ // Kill bonus
+ score += (match.Result == ActionResult.PlayerKillsBull) ? 4 : 2;
+
+ // Match length
+ score -= Math.Pow(match.PassNumber, 2) / 120;
+
+ // Difficulty
+ score -= (int)match.Conditions.BullQuality;
+
+ return score;
+ }
+ }
+
+ ///
+ /// Calculates the strength of the bull in a match.
+ ///
+ private static double GetBullStrength(MatchState match) =>
+ 6 - (int)match.Conditions.BullQuality;
+
+ ///
+ /// Gets the amount of assistance received from the toreadores and
+ /// picadores in a match.
+ ///
+ private static double GetAssisstance(MatchState match) =>
+ GetPerformanceBonus(match.Conditions.ToreadorePerformance) +
+ GetPerformanceBonus(match.Conditions.PicadorePerformance);
+
+ ///
+ /// Gets the amount of assistance rendered by a performance of the
+ /// given quality.
+ ///
+ private static double GetPerformanceBonus(Quality performance) =>
+ (6 - (int)performance) * 0.1;
+ }
+}
diff --git a/17 Bullfight/csharp/src/View.cs b/17 Bullfight/csharp/src/View.cs
new file mode 100644
index 00000000..2bff39c8
--- /dev/null
+++ b/17 Bullfight/csharp/src/View.cs
@@ -0,0 +1,240 @@
+using System;
+
+namespace Game
+{
+ ///
+ /// Contains functions for displaying information to the user.
+ ///
+ public static class View
+ {
+ private static readonly string[] QualityString = { "SUPERB", "GOOD", "FAIR", "POOR", "AWFUL" };
+
+ public static void ShowBanner()
+ {
+ Console.WriteLine(" BULL");
+ Console.WriteLine(" CREATIVE COMPUTING MORRISTOWN, NEW JERSEY");
+ Console.WriteLine();
+ Console.WriteLine();
+ Console.WriteLine();
+ }
+
+ public static void ShowInstructions()
+ {
+ Console.WriteLine("HELLO, ALL YOU BLOODLOVERS AND AFICIONADOS.");
+ Console.WriteLine("HERE IS YOUR BIG CHANCE TO KILL A BULL.");
+ Console.WriteLine();
+ Console.WriteLine("ON EACH PASS OF THE BULL, YOU MAY TRY");
+ Console.WriteLine("0 - VERONICA (DANGEROUS INSIDE MOVE OF THE CAPE)");
+ Console.WriteLine("1 - LESS DANGEROUS OUTSIDE MOVE OF THE CAPE");
+ Console.WriteLine("2 - ORDINARY SWIRL OF THE CAPE.");
+ Console.WriteLine();
+ Console.WriteLine("INSTEAD OF THE ABOVE, YOU MAY TRY TO KILL THE BULL");
+ Console.WriteLine("ON ANY TURN: 4 (OVER THE HORNS), 5 (IN THE CHEST).");
+ Console.WriteLine("BUT IF I WERE YOU,");
+ Console.WriteLine("I WOULDN'T TRY IT BEFORE THE SEVENTH PASS.");
+ Console.WriteLine();
+ Console.WriteLine("THE CROWD WILL DETERMINE WHAT AWARD YOU DESERVE");
+ Console.WriteLine("(POSTHUMOUSLY IF NECESSARY).");
+ Console.WriteLine("THE BRAVER YOU ARE, THE BETTER THE AWARD YOU RECEIVE.");
+ Console.WriteLine();
+ Console.WriteLine("THE BETTER THE JOB THE PICADORES AND TOREADORES DO,");
+ Console.WriteLine("THE BETTER YOUR CHANCES ARE.");
+ }
+
+ public static void ShowSeparator()
+ {
+ Console.WriteLine();
+ Console.WriteLine();
+ }
+
+ public static void ShowStartingConditions(MatchConditions conditions)
+ {
+ ShowBullQuality();
+ ShowHelpQuality("TOREADORES", conditions.ToreadorePerformance, conditions.ToreadoresKilled, 0);
+ ShowHelpQuality("PICADORES", conditions.PicadorePerformance, conditions.PicadoresKilled, conditions.HorsesKilled);
+
+ void ShowBullQuality()
+ {
+ Console.WriteLine($"YOU HAVE DRAWN A {QualityString[(int)conditions.BullQuality - 1]} BULL.");
+
+ if (conditions.BullQuality > Quality.Poor)
+ {
+ Console.WriteLine("YOU'RE LUCKY");
+ }
+ else
+ if (conditions.BullQuality < Quality.Good)
+ {
+ Console.WriteLine("GOOD LUCK. YOU'LL NEED IT.");
+ Console.WriteLine();
+ }
+
+ Console.WriteLine();
+ }
+
+ static void ShowHelpQuality(string helperName, Quality helpQuality, int helpersKilled, int horsesKilled)
+ {
+ Console.WriteLine($"THE {helperName} DID A {QualityString[(int)helpQuality - 1]} JOB.");
+
+ // NOTE: The code below makes some *strong* assumptions about
+ // how the casualty numbers were generated. It is written
+ // this way to preserve the behaviour of the original BASIC
+ // version, but it would make more sense ignore the helpQuality
+ // parameter and just use the provided numbers to decide what
+ // to display.
+ switch (helpQuality)
+ {
+ case Quality.Poor:
+ if (horsesKilled > 0)
+ Console.WriteLine($"ONE OF THE HORSES OF THE {helperName} WAS KILLED.");
+
+ if (helpersKilled > 0)
+ Console.WriteLine($"ONE OF THE {helperName} WAS KILLED.");
+ break;
+
+ case Quality.Awful:
+ if (horsesKilled > 0)
+ Console.WriteLine($" {horsesKilled} OF THE HORSES OF THE {helperName} KILLED.");
+
+ Console.WriteLine($" {helpersKilled} OF THE {helperName} KILLED.");
+ break;
+ }
+ }
+ }
+
+ public static void StartOfPass(int passNumber)
+ {
+ Console.WriteLine();
+ Console.WriteLine();
+ Console.WriteLine($"PASS NUMBER {passNumber}");
+ }
+
+ public static void ShowPlayerGored(bool playerPanicked, bool firstGoring)
+ {
+ Console.WriteLine((playerPanicked, firstGoring) switch
+ {
+ (true, true) => "YOU PANICKED. THE BULL GORED YOU.",
+ (false, true) => "THE BULL HAS GORED YOU!",
+ (_, false) => "YOU ARE GORED AGAIN!"
+ });
+ }
+
+ public static void ShowPlayerSurvives()
+ {
+ Console.WriteLine("YOU ARE STILL ALIVE.");
+ Console.WriteLine();
+ }
+
+ public static void ShowPlayerFoolhardy()
+ {
+ Console.WriteLine("YOU ARE BRAVE. STUPID, BUT BRAVE.");
+ }
+
+ public static void ShowFinalResult(ActionResult result, double bravery, Reward reward)
+ {
+ Console.WriteLine();
+ Console.WriteLine();
+ Console.WriteLine();
+
+ switch (result)
+ {
+ case ActionResult.PlayerFlees:
+ Console.WriteLine("COWARD");
+ break;
+ case ActionResult.BullKillsPlayer:
+ Console.WriteLine("YOU ARE DEAD.");
+ break;
+ case ActionResult.PlayerKillsBull:
+ Console.WriteLine("YOU KILLED THE BULL!");
+ break;
+ }
+
+ if (result == ActionResult.PlayerFlees)
+ {
+ Console.WriteLine("THE CROWD BOOS FOR TEN MINUTES. IF YOU EVER DARE TO SHOW");
+ Console.WriteLine("YOUR FACE IN A RING AGAIN, THEY SWEAR THEY WILL KILL YOU--");
+ Console.WriteLine("UNLESS THE BULL DOES FIRST.");
+ }
+ else
+ {
+ if (bravery == 2) // You were gored by the bull but survived (and did not later die or flee)
+ Console.WriteLine("THE CROWD CHEERS WILDLY!");
+ else
+ if (result == ActionResult.PlayerKillsBull)
+ {
+ Console.WriteLine("THE CROWD CHEERS!");
+ Console.WriteLine();
+ }
+
+ Console.WriteLine("THE CROWD AWARDS YOU");
+ switch (reward)
+ {
+ case Reward.Nothing:
+ Console.WriteLine("NOTHING AT ALL.");
+ break;
+ case Reward.OneEar:
+ Console.WriteLine("ONE EAR OF THE BULL.");
+ break;
+ case Reward.TwoEars:
+ Console.WriteLine("BOTH EARS OF THE BULL!");
+ Console.WriteLine("OLE!");
+ break;
+ default:
+ Console.WriteLine("OLE! YOU ARE 'MUY HOMBRE'!! OLE! OLE!");
+ break;
+ }
+ }
+
+ Console.WriteLine();
+ Console.WriteLine("ADIOS");
+ Console.WriteLine();
+ Console.WriteLine();
+ Console.WriteLine();
+ }
+
+ public static void PromptShowInstructions()
+ {
+ Console.Write("DO YOU WANT INSTRUCTIONS? ");
+ }
+
+ public static void PromptKillBull()
+ {
+ Console.WriteLine("THE BULL IS CHARGING AT YOU! YOU ARE THE MATADOR--");
+ Console.Write("DO YOU WANT TO KILL THE BULL? ");
+ }
+
+ public static void PromptKillBullBrief()
+ {
+ Console.Write("HERE COMES THE BULL. TRY FOR A KILL? ");
+ }
+
+ public static void PromptKillMethod()
+ {
+ Console.WriteLine();
+ Console.WriteLine("IT IS THE MOMENT OF TRUTH.");
+ Console.WriteLine();
+
+ Console.Write("HOW DO YOU TRY TO KILL THE BULL? ");
+ }
+
+ public static void PromptCapeMove()
+ {
+ Console.Write("WHAT MOVE DO YOU MAKE WITH THE CAPE? ");
+ }
+
+ public static void PromptCapeMoveBrief()
+ {
+ Console.Write("CAPE MOVE? ");
+ }
+
+ public static void PromptDontPanic()
+ {
+ Console.WriteLine("DON'T PANIC, YOU IDIOT! PUT DOWN A CORRECT NUMBER");
+ Console.Write("? ");
+ }
+
+ public static void PromptRunFromRing()
+ {
+ Console.Write("DO YOU RUN FROM THE RING? ");
+ }
+ }
+}