mirror of
https://github.com/coding-horror/basic-computer-games.git
synced 2025-12-22 23:26:40 -08:00
Initial port of Bullfight to C#
This commit is contained in:
25
17 Bullfight/csharp/Bullfight.sln
Normal file
25
17 Bullfight/csharp/Bullfight.sln
Normal file
@@ -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
|
||||
7
17 Bullfight/csharp/Game.csproj
Normal file
7
17 Bullfight/csharp/Game.csproj
Normal file
@@ -0,0 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
24
17 Bullfight/csharp/src/Action.cs
Normal file
24
17 Bullfight/csharp/src/Action.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
namespace Game
|
||||
{
|
||||
/// <summary>
|
||||
/// Enumerates the different actions that the player can take on each round
|
||||
/// of the fight.
|
||||
/// </summary>
|
||||
public enum Action
|
||||
{
|
||||
/// <summary>
|
||||
/// Dodge the bull.
|
||||
/// </summary>
|
||||
Dodge,
|
||||
|
||||
/// <summary>
|
||||
/// Kill the bull.
|
||||
/// </summary>
|
||||
Kill,
|
||||
|
||||
/// <summary>
|
||||
/// Freeze in place and don't do anything.
|
||||
/// </summary>
|
||||
Panic
|
||||
}
|
||||
}
|
||||
44
17 Bullfight/csharp/src/ActionResult.cs
Normal file
44
17 Bullfight/csharp/src/ActionResult.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Game
|
||||
{
|
||||
/// <summary>
|
||||
/// Enumerates the different possible outcomes of the player's action.
|
||||
/// </summary>
|
||||
public enum ActionResult
|
||||
{
|
||||
/// <summary>
|
||||
/// The fight continues.
|
||||
/// </summary>
|
||||
FightContinues,
|
||||
|
||||
/// <summary>
|
||||
/// The player fled from the ring.
|
||||
/// </summary>
|
||||
PlayerFlees,
|
||||
|
||||
/// <summary>
|
||||
/// The bull has gored the player.
|
||||
/// </summary>
|
||||
BullGoresPlayer,
|
||||
|
||||
/// <summary>
|
||||
/// The bull killed the player.
|
||||
/// </summary>
|
||||
BullKillsPlayer,
|
||||
|
||||
/// <summary>
|
||||
/// The player killed the bull.
|
||||
/// </summary>
|
||||
PlayerKillsBull,
|
||||
|
||||
/// <summary>
|
||||
/// The player attempted to kill the bull and both survived.
|
||||
/// </summary>
|
||||
Draw
|
||||
}
|
||||
}
|
||||
129
17 Bullfight/csharp/src/Controller.cs
Normal file
129
17 Bullfight/csharp/src/Controller.cs
Normal file
@@ -0,0 +1,129 @@
|
||||
using System;
|
||||
|
||||
namespace Game
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains functions for getting input from the user.
|
||||
/// </summary>
|
||||
public static class Controller
|
||||
{
|
||||
/// <summary>
|
||||
/// Handles the initial interaction with the player.
|
||||
/// </summary>
|
||||
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();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the player's action for the current round.
|
||||
/// </summary>
|
||||
/// <param name="passNumber">
|
||||
/// The current pass number.
|
||||
/// </param>
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the player's intention to flee (or not).
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// True if the player flees; otherwise, false.
|
||||
/// </returns>
|
||||
public static bool PlayerRunsFromRing()
|
||||
{
|
||||
View.PromptRunFromRing();
|
||||
return GetYesOrNo();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a yes or no response from the player.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// True if the user answered yes; otherwise, false.
|
||||
/// </returns>
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
41
17 Bullfight/csharp/src/MatchConditions.cs
Normal file
41
17 Bullfight/csharp/src/MatchConditions.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
namespace Game
|
||||
{
|
||||
/// <summary>
|
||||
/// Stores the initial conditions of a match.
|
||||
/// </summary>
|
||||
public record MatchConditions
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the quality of the bull.
|
||||
/// </summary>
|
||||
public Quality BullQuality { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the quality of help received from the toreadores.
|
||||
/// </summary>
|
||||
public Quality ToreadorePerformance { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the quality of help received from the picadores.
|
||||
/// </summary>
|
||||
public Quality PicadorePerformance { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of toreadores killed while preparing for the
|
||||
/// final round.
|
||||
/// </summary>
|
||||
public int ToreadoresKilled { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of picadores killed while preparing for the
|
||||
/// final round.
|
||||
/// </summary>
|
||||
public int PicadoresKilled { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of horses killed while preparing for the final
|
||||
/// round.
|
||||
/// </summary>
|
||||
public int HorsesKilled { get; init; }
|
||||
}
|
||||
}
|
||||
28
17 Bullfight/csharp/src/MatchState.cs
Normal file
28
17 Bullfight/csharp/src/MatchState.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
namespace Game
|
||||
{
|
||||
/// <summary>
|
||||
/// Stores the current state of the match.
|
||||
/// </summary>
|
||||
public record MatchState(MatchConditions Conditions)
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the number of times the bull has charged.
|
||||
/// </summary>
|
||||
public int PassNumber { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Measures the player's bravery during the match.
|
||||
/// </summary>
|
||||
public double Bravery { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Measures how much style the player showed during the match.
|
||||
/// </summary>
|
||||
public double Style { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the result of the player's last action.
|
||||
/// </summary>
|
||||
public ActionResult Result { get; init; }
|
||||
}
|
||||
}
|
||||
56
17 Bullfight/csharp/src/Program.cs
Normal file
56
17 Bullfight/csharp/src/Program.cs
Normal file
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
19
17 Bullfight/csharp/src/Quality.cs
Normal file
19
17 Bullfight/csharp/src/Quality.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
namespace Game
|
||||
{
|
||||
/// <summary>
|
||||
/// Enumerates the different levels of quality in the game.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 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).
|
||||
/// </remarks>
|
||||
public enum Quality
|
||||
{
|
||||
Superb = 1,
|
||||
Good = 2,
|
||||
Fair = 3,
|
||||
Poor = 4,
|
||||
Awful = 5
|
||||
}
|
||||
}
|
||||
13
17 Bullfight/csharp/src/Reward.cs
Normal file
13
17 Bullfight/csharp/src/Reward.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
namespace Game
|
||||
{
|
||||
/// <summary>
|
||||
/// Enumerates the different things the player can be awarded.
|
||||
/// </summary>
|
||||
public enum Reward
|
||||
{
|
||||
Nothing,
|
||||
OneEar,
|
||||
TwoEars,
|
||||
CarriedFromRing
|
||||
}
|
||||
}
|
||||
12
17 Bullfight/csharp/src/RiskLevel.cs
Normal file
12
17 Bullfight/csharp/src/RiskLevel.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
namespace Game
|
||||
{
|
||||
/// <summary>
|
||||
/// Enumerates the different levels of risk for manoeuvres in the game.
|
||||
/// </summary>
|
||||
public enum RiskLevel
|
||||
{
|
||||
Low,
|
||||
Medium,
|
||||
High
|
||||
}
|
||||
}
|
||||
258
17 Bullfight/csharp/src/Rules.cs
Normal file
258
17 Bullfight/csharp/src/Rules.cs
Normal file
@@ -0,0 +1,258 @@
|
||||
using System;
|
||||
|
||||
namespace Game
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides functions implementing the rules of the game.
|
||||
/// </summary>
|
||||
public static class Rules
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the state of a new match.
|
||||
/// </summary>
|
||||
/// <param name="random">
|
||||
/// The random number generator.
|
||||
/// </param>
|
||||
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
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines the result when the player attempts to dodge the bull.
|
||||
/// </summary>
|
||||
/// <param name="random">
|
||||
/// The random number generator.
|
||||
/// </param>
|
||||
/// <param name="riskLevel">
|
||||
/// The level of risk in the dodge manoeuvre chosen.
|
||||
/// </param>
|
||||
/// <param name="match">
|
||||
/// The current match state.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// The updated match state.
|
||||
/// </returns>
|
||||
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 };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines the result when the player attempts to kill the bull.
|
||||
/// </summary>
|
||||
/// <param name="random">
|
||||
/// The random number generator.
|
||||
/// </param>
|
||||
/// <param name="riskLevel">
|
||||
/// The level of risk in the manoeuvre chosen.
|
||||
/// </param>
|
||||
/// <param name="match">
|
||||
/// The current match state.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// The updated match state.
|
||||
/// </returns>
|
||||
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 };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines if the player survives being gored by the bull.
|
||||
/// </summary>
|
||||
/// <param name="random">
|
||||
/// The random number generator.
|
||||
/// </param>
|
||||
/// <param name="match">
|
||||
/// The current match state.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// The updated match state.
|
||||
/// </returns>
|
||||
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 };
|
||||
|
||||
/// <summary>
|
||||
/// Determines the result when the player panics and fails to do anything.
|
||||
/// </summary>
|
||||
/// <param name="match">
|
||||
/// The match state.
|
||||
/// </param>
|
||||
public static MatchState Panic(MatchState match) =>
|
||||
match with { Result = ActionResult.BullGoresPlayer };
|
||||
|
||||
/// <summary>
|
||||
/// Determines the result when the player flees the ring.
|
||||
/// </summary>
|
||||
/// <param name="match">
|
||||
/// The current match state.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// The updated match state.
|
||||
/// </returns>
|
||||
public static MatchState Flee(MatchState match) =>
|
||||
match with { Result = ActionResult.PlayerFlees, Bravery = 0.0 };
|
||||
|
||||
/// <summary>
|
||||
/// Determines the result when the player decides to continue fighting
|
||||
/// following an injury.
|
||||
/// </summary>
|
||||
/// <param name="random">
|
||||
/// The random number generator.
|
||||
/// </param>
|
||||
/// <param name="action">
|
||||
/// The action the player took that lead to the injury.
|
||||
/// </param>
|
||||
/// <param name="match">
|
||||
/// The current match state.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// The updated match state.
|
||||
/// </returns>
|
||||
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 };
|
||||
|
||||
/// <summary>
|
||||
/// Gets the player's reward for completing a match.
|
||||
/// </summary>
|
||||
/// <param name="random">
|
||||
/// The random number generator.
|
||||
/// </param>
|
||||
/// <param name="match">
|
||||
/// The final match state.
|
||||
/// </param>
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the strength of the bull in a match.
|
||||
/// </summary>
|
||||
private static double GetBullStrength(MatchState match) =>
|
||||
6 - (int)match.Conditions.BullQuality;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the amount of assistance received from the toreadores and
|
||||
/// picadores in a match.
|
||||
/// </summary>
|
||||
private static double GetAssisstance(MatchState match) =>
|
||||
GetPerformanceBonus(match.Conditions.ToreadorePerformance) +
|
||||
GetPerformanceBonus(match.Conditions.PicadorePerformance);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the amount of assistance rendered by a performance of the
|
||||
/// given quality.
|
||||
/// </summary>
|
||||
private static double GetPerformanceBonus(Quality performance) =>
|
||||
(6 - (int)performance) * 0.1;
|
||||
}
|
||||
}
|
||||
240
17 Bullfight/csharp/src/View.cs
Normal file
240
17 Bullfight/csharp/src/View.cs
Normal file
@@ -0,0 +1,240 @@
|
||||
using System;
|
||||
|
||||
namespace Game
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains functions for displaying information to the user.
|
||||
/// </summary>
|
||||
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? ");
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user