From 8c397ea8f995128447dc8cce83c90ebdfcc22cd5 Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Mon, 1 Mar 2021 22:53:22 +1100 Subject: [PATCH 01/15] Add Damage Control --- 84 Super Star Trek/csharp/Game.cs | 38 +++++++++++--- 84 Super Star Trek/csharp/Input.cs | 21 ++++++++ .../csharp/Objects/Enterprise.cs | 25 +++------- 84 Super Star Trek/csharp/Objects/Starbase.cs | 31 ++++++++++++ 84 Super Star Trek/csharp/Output.cs | 35 +++++++++++-- .../csharp/Resources/AcceptCommand.txt | 0 .../csharp/Resources/Congratulations.txt | 4 ++ .../csharp/Resources/Destroyed.txt | 1 + .../csharp/Resources/EndOfMission.txt | 3 ++ .../csharp/Resources/Instructions.txt | 1 + .../csharp/Resources/RepairEstimate.txt | 2 + .../csharp/Resources/RepairPrompt.txt | 1 + .../csharp/Resources/ReplayPrompt.txt | 2 + .../csharp/Resources/Stranded.txt | 3 ++ .../csharp/Resources/Strings.cs | 6 +++ 84 Super Star Trek/csharp/Space/Quadrant.cs | 3 +- .../csharp/Systems/DamageControl.cs | 49 +++++++++++++++++++ .../csharp/Systems/ShortRangeSensors.cs | 4 +- .../csharp/Systems/Subsystem.cs | 7 ++- 19 files changed, 200 insertions(+), 36 deletions(-) delete mode 100644 84 Super Star Trek/csharp/Resources/AcceptCommand.txt create mode 100644 84 Super Star Trek/csharp/Resources/Congratulations.txt create mode 100644 84 Super Star Trek/csharp/Resources/Destroyed.txt create mode 100644 84 Super Star Trek/csharp/Resources/EndOfMission.txt create mode 100644 84 Super Star Trek/csharp/Resources/RepairEstimate.txt create mode 100644 84 Super Star Trek/csharp/Resources/RepairPrompt.txt create mode 100644 84 Super Star Trek/csharp/Resources/Stranded.txt create mode 100644 84 Super Star Trek/csharp/Systems/DamageControl.cs diff --git a/84 Super Star Trek/csharp/Game.cs b/84 Super Star Trek/csharp/Game.cs index d97b8198..eb9fe03c 100644 --- a/84 Super Star Trek/csharp/Game.cs +++ b/84 Super Star Trek/csharp/Game.cs @@ -33,11 +33,7 @@ namespace SuperStarTrek { _output.Write(Strings.Title); - _output.Write("Do you need instructions (Y/N)? "); - var response = Console.ReadLine(); - _output.WriteLine(); - - if (!response.Equals("N", InvariantCultureIgnoreCase)) + if (_input.GetYesNo("Do you need instructions", Input.YesNoMode.FalseOnN)) { _output.Write(Strings.Instructions); @@ -68,7 +64,16 @@ namespace SuperStarTrek { var command = _input.GetCommand(); - gameOver = command == Command.XXX || _enterprise.Execute(command); + gameOver = command == Command.XXX || _enterprise.Execute(command) || CheckIfStranded(); + } + + if (_galaxy.KlingonCount > 0) + { + _output.Write(Strings.EndOfMission, _currentStardate, _galaxy.KlingonCount); + } + else + { + _output.Write(Strings.Congratulations, GetEfficiency()); } } @@ -86,12 +91,29 @@ namespace SuperStarTrek _initialKlingonCount = _galaxy.KlingonCount; _enterprise = new Enterprise(3000, random.GetCoordinate()); - _enterprise.Add(new ShortRangeSensors(_enterprise, _galaxy, this, _output)) - .Add(new ShieldControl(_enterprise, _output, _input)); + _enterprise + .Add(new ShortRangeSensors(_enterprise, _galaxy, this, _output)) + .Add(new ShieldControl(_enterprise, _output, _input)) + .Add(new DamageControl(_enterprise, _output)); return new Quadrant(_galaxy[_currentQuadrant], _enterprise); } public bool Replay() => _galaxy.StarbaseCount > 0 && _input.GetString(Strings.ReplayPrompt, "Aye"); + + private bool CheckIfStranded() + { + if (_enterprise.TotalEnergy < 10 || + _enterprise.Energy < 10 && _enterprise.Shields.IsDamaged) + { + _output.Write(Strings.Stranded); + return true; + } + + return false; + } + + private double GetEfficiency() => + 1000 * Math.Pow(_initialKlingonCount / (_currentStardate - _initialStardate), 2); } } diff --git a/84 Super Star Trek/csharp/Input.cs b/84 Super Star Trek/csharp/Input.cs index 98e5b297..3e2d7972 100644 --- a/84 Super Star Trek/csharp/Input.cs +++ b/84 Super Star Trek/csharp/Input.cs @@ -72,5 +72,26 @@ namespace SuperStarTrek _output.WriteLine(); } } + + public bool GetYesNo(string prompt, YesNoMode mode) + { + _output.Prompt($"{prompt} (Y/N)"); + var response = Console.ReadLine().ToUpperInvariant(); + + return (mode, response) switch + { + (YesNoMode.FalseOnN, "N") => false, + (YesNoMode.FalseOnN, _) => true, + (YesNoMode.TrueOnY, "Y") => true, + (YesNoMode.TrueOnY, _) => false, + _ => throw new ArgumentOutOfRangeException(nameof(mode), mode, "Invalid value") + }; + } + + public enum YesNoMode + { + TrueOnY, + FalseOnN + } } } diff --git a/84 Super Star Trek/csharp/Objects/Enterprise.cs b/84 Super Star Trek/csharp/Objects/Enterprise.cs index 4f6055cc..e8447fca 100644 --- a/84 Super Star Trek/csharp/Objects/Enterprise.cs +++ b/84 Super Star Trek/csharp/Objects/Enterprise.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Text; using SuperStarTrek.Resources; using SuperStarTrek.Space; @@ -13,7 +14,6 @@ namespace SuperStarTrek.Objects private readonly List _systems; private readonly Dictionary _commandExecutors; private Quadrant _quadrant; - private ShieldControl _shieldControl; public Enterprise(int maxEnergy, Coordinates sector) { @@ -27,11 +27,12 @@ namespace SuperStarTrek.Objects public Coordinates Quadrant => _quadrant.Coordinates; public Coordinates Sector { get; } public string Condition => GetCondition(); - public double Shields => _shieldControl.Energy; - public double Energy => TotalEnergy - Shields; + public ShieldControl Shields => (ShieldControl)_commandExecutors[Command.SHE]; + public double Energy => TotalEnergy - Shields.Energy; public double TotalEnergy { get; private set; } + public int DamagedSystemCount => _systems.Count(s => s.IsDamaged); + public IEnumerable Systems => _systems; public int TorpedoCount { get; } - public bool IsDocked { get; private set; } public Enterprise Add(Subsystem system) @@ -39,23 +40,9 @@ namespace SuperStarTrek.Objects _systems.Add(system); _commandExecutors[system.Command] = system; - if (system is ShieldControl shieldControl) { _shieldControl = shieldControl; } - return this; } - public string GetDamageReport() - { - var report = new StringBuilder(); - report.AppendLine().AppendLine().AppendLine("Device State of Repair"); - foreach (var system in _systems) - { - report.Append(system.Name.PadRight(25)).AppendLine(system.Condition.ToString(" 0.00;-0.00")); - } - report.AppendLine(); - return report.ToString(); - } - public void Enter(Quadrant quadrant, string entryTextFormat) { _quadrant = quadrant; @@ -66,7 +53,7 @@ namespace SuperStarTrek.Objects if (quadrant.HasKlingons) { _output.Write(Strings.CombatArea); - if (Shields <= 200) { _output.Write(Strings.LowShields); } + if (Shields.Energy <= 200) { _output.Write(Strings.LowShields); } } IsDocked = quadrant.EnterpriseIsNextToStarbase; diff --git a/84 Super Star Trek/csharp/Objects/Starbase.cs b/84 Super Star Trek/csharp/Objects/Starbase.cs index 33110837..e11ca9f5 100644 --- a/84 Super Star Trek/csharp/Objects/Starbase.cs +++ b/84 Super Star Trek/csharp/Objects/Starbase.cs @@ -1,7 +1,38 @@ +using SuperStarTrek.Resources; + namespace SuperStarTrek.Objects { internal class Starbase { + private readonly Input _input; + private readonly Output _output; + private readonly double _repairDelay; + + public Starbase(Random random, Input input) + { + _repairDelay = random.GetDouble() * 0.5; + _input = input; + } + public override string ToString() => ">!<"; + + internal bool TryRepair(Enterprise enterprise, out double repairTime) + { + repairTime = enterprise.DamagedSystemCount * 0.1 + _repairDelay; + if (repairTime >= 1) { repairTime = 0.9; } + + _output.Write(Strings.RepairEstimate, repairTime); + if (_input.GetYesNo(Strings.RepairPrompt, Input.YesNoMode.TrueOnY)) + { + foreach (var system in enterprise.Systems) + { + system.Repair(); + } + return true; + } + + repairTime = 0; + return false; + } } } diff --git a/84 Super Star Trek/csharp/Output.cs b/84 Super Star Trek/csharp/Output.cs index 77e5e919..ed960eea 100644 --- a/84 Super Star Trek/csharp/Output.cs +++ b/84 Super Star Trek/csharp/Output.cs @@ -4,12 +4,37 @@ namespace SuperStarTrek { internal class Output { - public void Write(string text) => Console.Write(text); - public void Write(string format, params object[] args) => Console.Write(format, args); - public void WriteLine(string text = "") => Console.WriteLine(text); + public Output Write(string text) + { + Console.Write(text); + return this; + } - public void NextLine() => Console.WriteLine(); + public Output Write(string format, params object[] args) + { + Console.Write(format, args); + return this; + } + + public Output WriteLine(string text = "") + { + Console.WriteLine(text); + return this; + } + + + public Output NextLine() + { + Console.WriteLine(); + return this; + } + + + public Output Prompt(string text = "") + { + Console.Write($"{text}? "); + return this; + } - public void Prompt(string text = "") => Console.Write($"{text}? "); } } diff --git a/84 Super Star Trek/csharp/Resources/AcceptCommand.txt b/84 Super Star Trek/csharp/Resources/AcceptCommand.txt deleted file mode 100644 index e69de29b..00000000 diff --git a/84 Super Star Trek/csharp/Resources/Congratulations.txt b/84 Super Star Trek/csharp/Resources/Congratulations.txt new file mode 100644 index 00000000..767f8653 --- /dev/null +++ b/84 Super Star Trek/csharp/Resources/Congratulations.txt @@ -0,0 +1,4 @@ +Congratulations, Captain! The last Klingon battle cruiser +menacing the Federation has been destroyed. + +Your efficiency rating is {0}. diff --git a/84 Super Star Trek/csharp/Resources/Destroyed.txt b/84 Super Star Trek/csharp/Resources/Destroyed.txt new file mode 100644 index 00000000..881d7b49 --- /dev/null +++ b/84 Super Star Trek/csharp/Resources/Destroyed.txt @@ -0,0 +1 @@ +The Enterprise has been destroyed. The Federation will be conquered. diff --git a/84 Super Star Trek/csharp/Resources/EndOfMission.txt b/84 Super Star Trek/csharp/Resources/EndOfMission.txt new file mode 100644 index 00000000..f6995e31 --- /dev/null +++ b/84 Super Star Trek/csharp/Resources/EndOfMission.txt @@ -0,0 +1,3 @@ +Is is stardate {0}. +There were {1} Klingon battle cruisers left at +the end of your mission. diff --git a/84 Super Star Trek/csharp/Resources/Instructions.txt b/84 Super Star Trek/csharp/Resources/Instructions.txt index fd74857e..34b4169c 100644 --- a/84 Super Star Trek/csharp/Resources/Instructions.txt +++ b/84 Super Star Trek/csharp/Resources/Instructions.txt @@ -1,3 +1,4 @@ + INSTRUCTIONS FOR 'SUPER STAR TREK' 1. When you see "Command ?" printed, enter one of the legal diff --git a/84 Super Star Trek/csharp/Resources/RepairEstimate.txt b/84 Super Star Trek/csharp/Resources/RepairEstimate.txt new file mode 100644 index 00000000..12e167a5 --- /dev/null +++ b/84 Super Star Trek/csharp/Resources/RepairEstimate.txt @@ -0,0 +1,2 @@ +Technicians standing by to effect repairs to your ship; +Estimated time to repair: {0} stardates. diff --git a/84 Super Star Trek/csharp/Resources/RepairPrompt.txt b/84 Super Star Trek/csharp/Resources/RepairPrompt.txt new file mode 100644 index 00000000..feffdb27 --- /dev/null +++ b/84 Super Star Trek/csharp/Resources/RepairPrompt.txt @@ -0,0 +1 @@ +Will you authorize the repair order (Y/N) \ No newline at end of file diff --git a/84 Super Star Trek/csharp/Resources/ReplayPrompt.txt b/84 Super Star Trek/csharp/Resources/ReplayPrompt.txt index 52aca0d1..3ca3a102 100644 --- a/84 Super Star Trek/csharp/Resources/ReplayPrompt.txt +++ b/84 Super Star Trek/csharp/Resources/ReplayPrompt.txt @@ -1,3 +1,5 @@ + + The Federation is in need of a new starship commander for a similar mission -- if there is a volunteer let him step forward and enter 'Aye' \ No newline at end of file diff --git a/84 Super Star Trek/csharp/Resources/Stranded.txt b/84 Super Star Trek/csharp/Resources/Stranded.txt new file mode 100644 index 00000000..07c37952 --- /dev/null +++ b/84 Super Star Trek/csharp/Resources/Stranded.txt @@ -0,0 +1,3 @@ +** FATAL ERROR ** You've just stranded your ship in space +You have insufficient maneuvering energy, and shield control +is presently incapable of cross-circuiting to engine room!! diff --git a/84 Super Star Trek/csharp/Resources/Strings.cs b/84 Super Star Trek/csharp/Resources/Strings.cs index 930f1663..4592db31 100644 --- a/84 Super Star Trek/csharp/Resources/Strings.cs +++ b/84 Super Star Trek/csharp/Resources/Strings.cs @@ -7,14 +7,20 @@ namespace SuperStarTrek.Resources internal static class Strings { public static string CombatArea => GetResource(); + public static string Congratulations => GetResource(); + public static string Destroyed => GetResource(); + public static string EndOfMission => GetResource(); public static string Enterprise => GetResource(); public static string Instructions => GetResource(); public static string LowShields => GetResource(); public static string Orders => GetResource(); + public static string RepairEstimate => GetResource(); + public static string RepairPrompt => GetResource(); public static string ReplayPrompt => GetResource(); public static string ShieldsDropped => GetResource(); public static string ShortRangeSensorsOut => GetResource(); public static string StartText => GetResource(); + public static string Stranded => GetResource(); public static string Title => GetResource(); private static string GetResource([CallerMemberName] string name = "") diff --git a/84 Super Star Trek/csharp/Space/Quadrant.cs b/84 Super Star Trek/csharp/Space/Quadrant.cs index 2aa45b6d..f08fa18b 100644 --- a/84 Super Star Trek/csharp/Space/Quadrant.cs +++ b/84 Super Star Trek/csharp/Space/Quadrant.cs @@ -23,7 +23,7 @@ namespace SuperStarTrek.Space PositionObject(() => new Klingon(), _info.KlingonCount); if (_info.HasStarbase) { - _starbaseSector = PositionObject(() => new Starbase()); + _starbaseSector = PositionObject(() => new Starbase(_random, new Input(new Output()))); } PositionObject(() => new Star(), _info.StarCount); } @@ -31,6 +31,7 @@ namespace SuperStarTrek.Space public Coordinates Coordinates => _info.Coordinates; public bool HasKlingons => _info.KlingonCount > 0; public bool HasStarbase => _info.HasStarbase; + public Starbase Starbase => HasStarbase ? (Starbase)_sectors[_starbaseSector] : null; public bool EnterpriseIsNextToStarbase => _info.HasStarbase && Math.Abs(_enterpriseSector.X - _starbaseSector.X) <= 1 && diff --git a/84 Super Star Trek/csharp/Systems/DamageControl.cs b/84 Super Star Trek/csharp/Systems/DamageControl.cs new file mode 100644 index 00000000..5cfbda7e --- /dev/null +++ b/84 Super Star Trek/csharp/Systems/DamageControl.cs @@ -0,0 +1,49 @@ +using SuperStarTrek.Objects; +using SuperStarTrek.Space; + +namespace SuperStarTrek.Systems +{ + internal class DamageControl : Subsystem + { + private readonly Enterprise _enterprise; + private readonly Output _output; + + public DamageControl(Enterprise enterprise, Output output) + : base("Damage Control", Command.DAM) + { + _enterprise = enterprise; + _output = output; + } + + public override void ExecuteCommand(Quadrant quadrant) + { + if (IsDamaged) + { + _output.WriteLine("Damage Control report not available"); + } + else + { + WriteDamageReport(); + } + + if (_enterprise.DamagedSystemCount > 0 && _enterprise.IsDocked) + { + if (quadrant.Starbase.TryRepair(_enterprise, out var repairTime)) + { + WriteDamageReport(); + } + } + } + + public void WriteDamageReport() + { + _output.NextLine().NextLine().WriteLine("Device State of Repair"); + foreach (var system in _enterprise.Systems) + { + _output.Write(system.Name.PadRight(25)) + .WriteLine(((int)(system.Condition * 100) * 0.01).ToString(" 0.##;-0.##")); + } + _output.NextLine(); + } + } +} diff --git a/84 Super Star Trek/csharp/Systems/ShortRangeSensors.cs b/84 Super Star Trek/csharp/Systems/ShortRangeSensors.cs index d22dda70..6632705c 100644 --- a/84 Super Star Trek/csharp/Systems/ShortRangeSensors.cs +++ b/84 Super Star Trek/csharp/Systems/ShortRangeSensors.cs @@ -51,8 +51,8 @@ namespace SuperStarTrek.Systems yield return $"Quadrant {_enterprise.Quadrant}"; yield return $"Sector {_enterprise.Sector}"; yield return $"Photon torpedoes {_enterprise.TorpedoCount}"; - yield return $"Total energy {Math.Ceiling(_enterprise.Energy)}"; - yield return $"Shields {(int)_enterprise.Shields}"; + yield return $"Total energy {Math.Ceiling(_enterprise.TotalEnergy)}"; + yield return $"Shields {(int)_enterprise.Shields.Energy}"; yield return $"Klingons remaining {_galaxy.KlingonCount}"; } } diff --git a/84 Super Star Trek/csharp/Systems/Subsystem.cs b/84 Super Star Trek/csharp/Systems/Subsystem.cs index ae2ef7d6..9cb461ce 100644 --- a/84 Super Star Trek/csharp/Systems/Subsystem.cs +++ b/84 Super Star Trek/csharp/Systems/Subsystem.cs @@ -12,9 +12,14 @@ namespace SuperStarTrek.Systems } public string Name { get; } - public double Condition { get; } + public double Condition { get; private set; } + public bool IsDamaged => Condition < 0; public Command Command { get; } public abstract void ExecuteCommand(Quadrant quadrant); + public void Repair() + { + if (Condition < 0) { Condition = 0; } + } } } From 8782d714e8853827fa97890d55cc2aaca9a8349d Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Tue, 2 Mar 2021 15:24:23 +1100 Subject: [PATCH 02/15] Add CommandResult --- .../csharp/{ => Commands}/Command.cs | 2 +- .../{ => Commands}/CommandExtensions.cs | 2 +- .../csharp/Commands/CommandResult.cs | 23 +++++ 84 Super Star Trek/csharp/Game.cs | 91 +++++++++---------- 84 Super Star Trek/csharp/Input.cs | 2 + .../csharp/Objects/Enterprise.cs | 24 ++--- .../csharp/Systems/DamageControl.cs | 6 +- .../csharp/Systems/ShieldControl.cs | 26 ++++-- .../csharp/Systems/ShortRangeSensors.cs | 7 +- .../csharp/Systems/Subsystem.cs | 3 +- 10 files changed, 114 insertions(+), 72 deletions(-) rename 84 Super Star Trek/csharp/{ => Commands}/Command.cs (95%) rename 84 Super Star Trek/csharp/{ => Commands}/CommandExtensions.cs (91%) create mode 100644 84 Super Star Trek/csharp/Commands/CommandResult.cs diff --git a/84 Super Star Trek/csharp/Command.cs b/84 Super Star Trek/csharp/Commands/Command.cs similarity index 95% rename from 84 Super Star Trek/csharp/Command.cs rename to 84 Super Star Trek/csharp/Commands/Command.cs index 33d9fd01..f0d569f8 100644 --- a/84 Super Star Trek/csharp/Command.cs +++ b/84 Super Star Trek/csharp/Commands/Command.cs @@ -1,6 +1,6 @@ using System.ComponentModel; -namespace SuperStarTrek +namespace SuperStarTrek.Commands { internal enum Command { diff --git a/84 Super Star Trek/csharp/CommandExtensions.cs b/84 Super Star Trek/csharp/Commands/CommandExtensions.cs similarity index 91% rename from 84 Super Star Trek/csharp/CommandExtensions.cs rename to 84 Super Star Trek/csharp/Commands/CommandExtensions.cs index 2b69ea31..f8f7e9da 100644 --- a/84 Super Star Trek/csharp/CommandExtensions.cs +++ b/84 Super Star Trek/csharp/Commands/CommandExtensions.cs @@ -1,7 +1,7 @@ using System.Reflection; using System.ComponentModel; -namespace SuperStarTrek +namespace SuperStarTrek.Commands { internal static class CommandExtensions { diff --git a/84 Super Star Trek/csharp/Commands/CommandResult.cs b/84 Super Star Trek/csharp/Commands/CommandResult.cs new file mode 100644 index 00000000..d92fba09 --- /dev/null +++ b/84 Super Star Trek/csharp/Commands/CommandResult.cs @@ -0,0 +1,23 @@ +namespace SuperStarTrek.Commands +{ + internal class CommandResult + { + public static readonly CommandResult Ok = new(false); + public static readonly CommandResult GameOver = new(true); + + private CommandResult(bool isGameOver) + { + IsGameOver = isGameOver; + } + + private CommandResult(double timeElapsed) + { + TimeElapsed = timeElapsed; + } + + public bool IsGameOver { get; } + public double TimeElapsed { get; } + + public static CommandResult Elapsed(double timeElapsed) => new(timeElapsed); + } +} diff --git a/84 Super Star Trek/csharp/Game.cs b/84 Super Star Trek/csharp/Game.cs index eb9fe03c..c9d9c778 100644 --- a/84 Super Star Trek/csharp/Game.cs +++ b/84 Super Star Trek/csharp/Game.cs @@ -43,9 +43,50 @@ namespace SuperStarTrek public void Play() { - var quadrant = Initialise(); + Initialise(); var gameOver = false; + while (!gameOver) + { + var command = _input.GetCommand(); + + var result = _enterprise.Execute(command); + + gameOver = result.IsGameOver || CheckIfStranded(); + _currentStardate += result.TimeElapsed; + } + + if (_galaxy.KlingonCount > 0) + { + _output.Write(Strings.EndOfMission, _currentStardate, _galaxy.KlingonCount); + } + else + { + _output.Write(Strings.Congratulations, GetEfficiency()); + } + } + + private void Initialise() + { + var random = new Random(); + + _currentStardate = _initialStardate = random.GetInt(20, 40) * 100; + _finalStarDate = _initialStardate + random.GetInt(25, 35); + + _currentQuadrant = random.GetCoordinate(); + _currentSector = random.GetCoordinate(); + + _galaxy = new Galaxy(); + _initialKlingonCount = _galaxy.KlingonCount; + + _enterprise = new Enterprise(3000, random.GetCoordinate(), _output); + _enterprise + .Add(new ShortRangeSensors(_enterprise, _galaxy, this, _output)) + .Add(new ShieldControl(_enterprise, _output, _input)) + .Add(new DamageControl(_enterprise, _output)); + + var quadrant = new Quadrant(_galaxy[_currentQuadrant], _enterprise); + _output.Write(Strings.Enterprise); _output.Write( Strings.Orders, @@ -59,58 +100,14 @@ namespace SuperStarTrek _input.WaitForAnyKeyButEnter("when ready to accept command"); _enterprise.Enter(quadrant, Strings.StartText); - - while (!gameOver) - { - var command = _input.GetCommand(); - - gameOver = command == Command.XXX || _enterprise.Execute(command) || CheckIfStranded(); - } - - if (_galaxy.KlingonCount > 0) - { - _output.Write(Strings.EndOfMission, _currentStardate, _galaxy.KlingonCount); - } - else - { - _output.Write(Strings.Congratulations, GetEfficiency()); - } - } - - private Quadrant Initialise() - { - var random = new Random(); - - _currentStardate = _initialStardate = random.GetInt(20, 40) * 100; - _finalStarDate = _initialStardate + random.GetInt(25, 35); - - _currentQuadrant = random.GetCoordinate(); - _currentSector = random.GetCoordinate(); - - _galaxy = new Galaxy(); - _initialKlingonCount = _galaxy.KlingonCount; - - _enterprise = new Enterprise(3000, random.GetCoordinate()); - _enterprise - .Add(new ShortRangeSensors(_enterprise, _galaxy, this, _output)) - .Add(new ShieldControl(_enterprise, _output, _input)) - .Add(new DamageControl(_enterprise, _output)); - - return new Quadrant(_galaxy[_currentQuadrant], _enterprise); } public bool Replay() => _galaxy.StarbaseCount > 0 && _input.GetString(Strings.ReplayPrompt, "Aye"); private bool CheckIfStranded() { - if (_enterprise.TotalEnergy < 10 || - _enterprise.Energy < 10 && _enterprise.Shields.IsDamaged) - { - _output.Write(Strings.Stranded); - return true; - } - - return false; + if (_enterprise.IsStranded) { _output.Write(Strings.Stranded); } + return _enterprise.IsStranded; } private double GetEfficiency() => diff --git a/84 Super Star Trek/csharp/Input.cs b/84 Super Star Trek/csharp/Input.cs index 3e2d7972..d86b7baf 100644 --- a/84 Super Star Trek/csharp/Input.cs +++ b/84 Super Star Trek/csharp/Input.cs @@ -1,5 +1,7 @@ using System; using System.Linq; +using SuperStarTrek.Commands; + using static System.StringComparison; namespace SuperStarTrek diff --git a/84 Super Star Trek/csharp/Objects/Enterprise.cs b/84 Super Star Trek/csharp/Objects/Enterprise.cs index e8447fca..97e5e3cd 100644 --- a/84 Super Star Trek/csharp/Objects/Enterprise.cs +++ b/84 Super Star Trek/csharp/Objects/Enterprise.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Linq; using System.Text; +using SuperStarTrek.Commands; using SuperStarTrek.Resources; using SuperStarTrek.Space; using SuperStarTrek.Systems; @@ -11,29 +12,32 @@ namespace SuperStarTrek.Objects internal class Enterprise { private readonly int _maxEnergy; + private readonly Output _output; private readonly List _systems; private readonly Dictionary _commandExecutors; private Quadrant _quadrant; - public Enterprise(int maxEnergy, Coordinates sector) + public Enterprise(int maxEnergy, Coordinates sector, Output output) { Sector = sector; TotalEnergy = _maxEnergy = maxEnergy; _systems = new List(); _commandExecutors = new Dictionary(); + _output = output; } public Coordinates Quadrant => _quadrant.Coordinates; public Coordinates Sector { get; } public string Condition => GetCondition(); - public ShieldControl Shields => (ShieldControl)_commandExecutors[Command.SHE]; - public double Energy => TotalEnergy - Shields.Energy; + public ShieldControl ShieldControl => (ShieldControl)_commandExecutors[Command.SHE]; + public double Energy => TotalEnergy - ShieldControl.ShieldEnergy; public double TotalEnergy { get; private set; } public int DamagedSystemCount => _systems.Count(s => s.IsDamaged); public IEnumerable Systems => _systems; public int TorpedoCount { get; } - public bool IsDocked { get; private set; } + public bool IsDocked => _quadrant.EnterpriseIsNextToStarbase; + public bool IsStranded => TotalEnergy < 10 || Energy < 10 && ShieldControl.IsDamaged; public Enterprise Add(Subsystem system) { @@ -47,17 +51,14 @@ namespace SuperStarTrek.Objects { _quadrant = quadrant; - var _output = new Output(); _output.Write(entryTextFormat, quadrant); if (quadrant.HasKlingons) { _output.Write(Strings.CombatArea); - if (Shields.Energy <= 200) { _output.Write(Strings.LowShields); } + if (ShieldControl.ShieldEnergy <= 200) { _output.Write(Strings.LowShields); } } - IsDocked = quadrant.EnterpriseIsNextToStarbase; - Execute(Command.SRS); } @@ -69,10 +70,11 @@ namespace SuperStarTrek.Objects _ => "Green" }; - public bool Execute(Command command) + public CommandResult Execute(Command command) { - _commandExecutors[command].ExecuteCommand(_quadrant); - return false; + if (command == Command.XXX) { return CommandResult.GameOver; } + + return _commandExecutors[command].ExecuteCommand(_quadrant); } internal bool Recognises(string command) diff --git a/84 Super Star Trek/csharp/Systems/DamageControl.cs b/84 Super Star Trek/csharp/Systems/DamageControl.cs index 5cfbda7e..b4587add 100644 --- a/84 Super Star Trek/csharp/Systems/DamageControl.cs +++ b/84 Super Star Trek/csharp/Systems/DamageControl.cs @@ -1,3 +1,4 @@ +using SuperStarTrek.Commands; using SuperStarTrek.Objects; using SuperStarTrek.Space; @@ -15,7 +16,7 @@ namespace SuperStarTrek.Systems _output = output; } - public override void ExecuteCommand(Quadrant quadrant) + public override CommandResult ExecuteCommand(Quadrant quadrant) { if (IsDamaged) { @@ -31,8 +32,11 @@ namespace SuperStarTrek.Systems if (quadrant.Starbase.TryRepair(_enterprise, out var repairTime)) { WriteDamageReport(); + return CommandResult.Elapsed(repairTime); } } + + return CommandResult.Ok; } public void WriteDamageReport() diff --git a/84 Super Star Trek/csharp/Systems/ShieldControl.cs b/84 Super Star Trek/csharp/Systems/ShieldControl.cs index e7aca413..9c4a3c16 100644 --- a/84 Super Star Trek/csharp/Systems/ShieldControl.cs +++ b/84 Super Star Trek/csharp/Systems/ShieldControl.cs @@ -1,3 +1,4 @@ +using SuperStarTrek.Commands; using SuperStarTrek.Objects; using SuperStarTrek.Space; @@ -17,26 +18,35 @@ namespace SuperStarTrek.Systems _input = input; } - public double Energy { get; private set; } + public double ShieldEnergy { get; private set; } - public override void ExecuteCommand(Quadrant quadrant) + public override CommandResult ExecuteCommand(Quadrant quadrant) { if (Condition < 0) { _output.WriteLine("Shield Control inoperable"); - return; + } + else + { + UpdateShields(); } + return CommandResult.Ok; + } + + private void UpdateShields() + { _output.WriteLine($"Energy available = {_enterprise.TotalEnergy}"); var requested = _input.GetNumber($"Number of units to shields"); if (Validate(requested)) { - Energy = requested; - return; + ShieldEnergy = requested; + } + else + { + _output.WriteLine(""); } - - _output.WriteLine(""); } private bool Validate(double requested) @@ -47,7 +57,7 @@ namespace SuperStarTrek.Systems return false; } - return requested >= 0 && requested != Energy; + return requested >= 0 && requested != ShieldEnergy; } } } diff --git a/84 Super Star Trek/csharp/Systems/ShortRangeSensors.cs b/84 Super Star Trek/csharp/Systems/ShortRangeSensors.cs index 6632705c..953ec66e 100644 --- a/84 Super Star Trek/csharp/Systems/ShortRangeSensors.cs +++ b/84 Super Star Trek/csharp/Systems/ShortRangeSensors.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Linq; +using SuperStarTrek.Commands; using SuperStarTrek.Objects; using SuperStarTrek.Resources; using SuperStarTrek.Space; @@ -24,7 +25,7 @@ namespace SuperStarTrek.Systems _output = output; } - public override void ExecuteCommand(Quadrant quadrant) + public override CommandResult ExecuteCommand(Quadrant quadrant) { if (_enterprise.IsDocked) { @@ -42,6 +43,8 @@ namespace SuperStarTrek.Systems .ToList() .ForEach(l => _output.WriteLine(l)); _output.WriteLine("---------------------------------"); + + return CommandResult.Ok; } public IEnumerable GetStatusLines() @@ -52,7 +55,7 @@ namespace SuperStarTrek.Systems yield return $"Sector {_enterprise.Sector}"; yield return $"Photon torpedoes {_enterprise.TorpedoCount}"; yield return $"Total energy {Math.Ceiling(_enterprise.TotalEnergy)}"; - yield return $"Shields {(int)_enterprise.Shields.Energy}"; + yield return $"Shields {(int)_enterprise.ShieldControl.ShieldEnergy}"; yield return $"Klingons remaining {_galaxy.KlingonCount}"; } } diff --git a/84 Super Star Trek/csharp/Systems/Subsystem.cs b/84 Super Star Trek/csharp/Systems/Subsystem.cs index 9cb461ce..53398b41 100644 --- a/84 Super Star Trek/csharp/Systems/Subsystem.cs +++ b/84 Super Star Trek/csharp/Systems/Subsystem.cs @@ -1,3 +1,4 @@ +using SuperStarTrek.Commands; using SuperStarTrek.Space; namespace SuperStarTrek.Systems @@ -16,7 +17,7 @@ namespace SuperStarTrek.Systems public bool IsDamaged => Condition < 0; public Command Command { get; } - public abstract void ExecuteCommand(Quadrant quadrant); + public abstract CommandResult ExecuteCommand(Quadrant quadrant); public void Repair() { if (Condition < 0) { Condition = 0; } From fb88b706fd1a318cd8faeec4289adb3dfd94f228 Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Tue, 2 Mar 2021 16:06:45 +1100 Subject: [PATCH 03/15] Fix command input for short input --- 84 Super Star Trek/csharp/Input.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/84 Super Star Trek/csharp/Input.cs b/84 Super Star Trek/csharp/Input.cs index d86b7baf..0fba2e4c 100644 --- a/84 Super Star Trek/csharp/Input.cs +++ b/84 Super Star Trek/csharp/Input.cs @@ -60,7 +60,7 @@ namespace SuperStarTrek { var response = GetString("Command"); - if (response != "" && + if (response.Length >= 3 && Enum.TryParse(response.Substring(0, 3), ignoreCase: true, out Command parsedCommand)) { return parsedCommand; From cbcfebfeb3059157d7331f446b1cff5b7cfdf0f6 Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Wed, 3 Mar 2021 09:21:40 +1100 Subject: [PATCH 04/15] Add quadrant names --- .../csharp/Resources/RegionNames.txt | 8 +++++++ .../csharp/Resources/Strings.cs | 1 + 84 Super Star Trek/csharp/Space/Coordinate.cs | 2 ++ 84 Super Star Trek/csharp/Space/Galaxy.cs | 23 +++++++++++++++++-- 4 files changed, 32 insertions(+), 2 deletions(-) create mode 100644 84 Super Star Trek/csharp/Resources/RegionNames.txt diff --git a/84 Super Star Trek/csharp/Resources/RegionNames.txt b/84 Super Star Trek/csharp/Resources/RegionNames.txt new file mode 100644 index 00000000..e2f47d79 --- /dev/null +++ b/84 Super Star Trek/csharp/Resources/RegionNames.txt @@ -0,0 +1,8 @@ +Antares Sirius +Rigel Deneb +Procyon Capella +Vega Betelgeuse +Canopus Aldebaran +Altair Regulus +Sagittarius Arcturus +Pollux Spica \ No newline at end of file diff --git a/84 Super Star Trek/csharp/Resources/Strings.cs b/84 Super Star Trek/csharp/Resources/Strings.cs index 4592db31..210d22ba 100644 --- a/84 Super Star Trek/csharp/Resources/Strings.cs +++ b/84 Super Star Trek/csharp/Resources/Strings.cs @@ -14,6 +14,7 @@ namespace SuperStarTrek.Resources public static string Instructions => GetResource(); public static string LowShields => GetResource(); public static string Orders => GetResource(); + public static string RegionNames => GetResource(); public static string RepairEstimate => GetResource(); public static string RepairPrompt => GetResource(); public static string ReplayPrompt => GetResource(); diff --git a/84 Super Star Trek/csharp/Space/Coordinate.cs b/84 Super Star Trek/csharp/Space/Coordinate.cs index b3328c24..87fe6e89 100644 --- a/84 Super Star Trek/csharp/Space/Coordinate.cs +++ b/84 Super Star Trek/csharp/Space/Coordinate.cs @@ -14,6 +14,8 @@ namespace SuperStarTrek.Space public int X { get; } public int Y { get; } + public int RegionIndex => ((X - 1) << 1) + ((Y - 1) >> 2); + public int SubRegionIndex => (Y - 1) % 4; private int Validated(int value, string argumentName) { diff --git a/84 Super Star Trek/csharp/Space/Galaxy.cs b/84 Super Star Trek/csharp/Space/Galaxy.cs index 171ecdea..88361645 100644 --- a/84 Super Star Trek/csharp/Space/Galaxy.cs +++ b/84 Super Star Trek/csharp/Space/Galaxy.cs @@ -1,17 +1,33 @@ using System.Linq; +using SuperStarTrek.Resources; + +using static System.StringSplitOptions; namespace SuperStarTrek.Space { internal class Galaxy { + private static readonly string[] _regionNames; + private static readonly string[] _subRegionIdentifiers; private readonly QuadrantInfo[][] _quadrants; + static Galaxy() + { + _regionNames = Strings.RegionNames.Split(new[] { ' ', '\n' }, RemoveEmptyEntries | TrimEntries); + _subRegionIdentifiers = new[] { "I", "II", "III", "IV" }; + } + public Galaxy() { var random = new Random(); - _quadrants = Enumerable.Range(1, 8).Select(x => - Enumerable.Range(1, 8).Select(y => QuadrantInfo.Create(new Coordinates(x, y), "")).ToArray()) + _quadrants = Enumerable + .Range(1, 8) + .Select(x => Enumerable + .Range(1, 8) + .Select(y => new Coordinates(x, y)) + .Select(c => QuadrantInfo.Create(c, GetQuadrantName(c))) + .ToArray()) .ToArray(); if (StarbaseCount == 0) @@ -30,5 +46,8 @@ namespace SuperStarTrek.Space public int KlingonCount => _quadrants.SelectMany(q => q).Sum(q => q.KlingonCount); public int StarbaseCount => _quadrants.SelectMany(q => q).Count(q => q.HasStarbase); + + private static string GetQuadrantName(Coordinates coordinates) => + $"{_regionNames[coordinates.RegionIndex]} {_subRegionIdentifiers[coordinates.SubRegionIndex]}"; } } From a1b257d5ae42ab95888955ccd732f23a811dd39e Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Wed, 3 Mar 2021 23:22:16 +1100 Subject: [PATCH 05/15] Add Long Range Sensors --- 84 Super Star Trek/csharp/Game.cs | 1 + 84 Super Star Trek/csharp/Random.cs | 2 +- 84 Super Star Trek/csharp/Space/Coordinate.cs | 10 ++--- 84 Super Star Trek/csharp/Space/Galaxy.cs | 17 +++++-- 84 Super Star Trek/csharp/Space/Quadrant.cs | 4 +- .../csharp/Space/QuadrantInfo.cs | 10 +++++ .../csharp/Systems/LongRangeSensors.cs | 44 +++++++++++++++++++ 7 files changed, 77 insertions(+), 11 deletions(-) create mode 100644 84 Super Star Trek/csharp/Systems/LongRangeSensors.cs diff --git a/84 Super Star Trek/csharp/Game.cs b/84 Super Star Trek/csharp/Game.cs index c9d9c778..0547103b 100644 --- a/84 Super Star Trek/csharp/Game.cs +++ b/84 Super Star Trek/csharp/Game.cs @@ -82,6 +82,7 @@ namespace SuperStarTrek _enterprise = new Enterprise(3000, random.GetCoordinate(), _output); _enterprise .Add(new ShortRangeSensors(_enterprise, _galaxy, this, _output)) + .Add(new LongRangeSensors(_galaxy, _output)) .Add(new ShieldControl(_enterprise, _output, _input)) .Add(new DamageControl(_enterprise, _output)); diff --git a/84 Super Star Trek/csharp/Random.cs b/84 Super Star Trek/csharp/Random.cs index 9b7e1bff..460c1cef 100644 --- a/84 Super Star Trek/csharp/Random.cs +++ b/84 Super Star Trek/csharp/Random.cs @@ -6,7 +6,7 @@ namespace SuperStarTrek { private static readonly System.Random _random = new(); - public Coordinates GetCoordinate() => new Coordinates(Get1To8Inclusive(), Get1To8Inclusive()); + public Coordinates GetCoordinate() => new Coordinates(Get1To8Inclusive() - 1, Get1To8Inclusive() - 1); // Duplicates the algorithm used in the original code to get an integer value from 1 to 8, inclusive: // 475 DEF FNR(R)=INT(RND(R)*7.98+1.01) diff --git a/84 Super Star Trek/csharp/Space/Coordinate.cs b/84 Super Star Trek/csharp/Space/Coordinate.cs index 87fe6e89..aa5b5285 100644 --- a/84 Super Star Trek/csharp/Space/Coordinate.cs +++ b/84 Super Star Trek/csharp/Space/Coordinate.cs @@ -14,16 +14,16 @@ namespace SuperStarTrek.Space public int X { get; } public int Y { get; } - public int RegionIndex => ((X - 1) << 1) + ((Y - 1) >> 2); - public int SubRegionIndex => (Y - 1) % 4; + public int RegionIndex => (X << 1) + (Y >> 2); + public int SubRegionIndex => Y % 4; private int Validated(int value, string argumentName) { - if (value >= 1 && value <= 8) { return value; } + if (value >= 0 && value <= 7) { return value; } - throw new ArgumentOutOfRangeException(argumentName, value, "Must be 1 to 8 inclusive"); + throw new ArgumentOutOfRangeException(argumentName, value, "Must be 0 to 7 inclusive"); } - public override string ToString() => $"{X} , {Y}"; + public override string ToString() => $"{X+1} , {Y+1}"; } } diff --git a/84 Super Star Trek/csharp/Space/Galaxy.cs b/84 Super Star Trek/csharp/Space/Galaxy.cs index 88361645..0392b335 100644 --- a/84 Super Star Trek/csharp/Space/Galaxy.cs +++ b/84 Super Star Trek/csharp/Space/Galaxy.cs @@ -1,3 +1,5 @@ +using System.Collections; +using System.Collections.Generic; using System.Linq; using SuperStarTrek.Resources; @@ -22,9 +24,9 @@ namespace SuperStarTrek.Space var random = new Random(); _quadrants = Enumerable - .Range(1, 8) + .Range(0, 8) .Select(x => Enumerable - .Range(1, 8) + .Range(0, 8) .Select(y => new Coordinates(x, y)) .Select(c => QuadrantInfo.Create(c, GetQuadrantName(c))) .ToArray()) @@ -42,12 +44,21 @@ namespace SuperStarTrek.Space } } - public QuadrantInfo this[Coordinates coordinate] => _quadrants[coordinate.X - 1][coordinate.Y - 1]; + public QuadrantInfo this[Coordinates coordinate] => _quadrants[coordinate.X][coordinate.Y]; public int KlingonCount => _quadrants.SelectMany(q => q).Sum(q => q.KlingonCount); public int StarbaseCount => _quadrants.SelectMany(q => q).Count(q => q.HasStarbase); private static string GetQuadrantName(Coordinates coordinates) => $"{_regionNames[coordinates.RegionIndex]} {_subRegionIdentifiers[coordinates.SubRegionIndex]}"; + + public IEnumerable> GetNeighborhood(Quadrant quadrant) => + Enumerable.Range(-1, 3) + .Select(dx => dx + quadrant.Coordinates.X) + .Select(x => GetNeighborhoodRow(quadrant, x)); + private IEnumerable GetNeighborhoodRow(Quadrant quadrant, int x) => + Enumerable.Range(-1, 3) + .Select(dy => dy + quadrant.Coordinates.Y) + .Select(y => y < 0 || y > 7 || x < 0 || x > 7 ? null : _quadrants[x][y]); } } diff --git a/84 Super Star Trek/csharp/Space/Quadrant.cs b/84 Super Star Trek/csharp/Space/Quadrant.cs index f08fa18b..e483604f 100644 --- a/84 Super Star Trek/csharp/Space/Quadrant.cs +++ b/84 Super Star Trek/csharp/Space/Quadrant.cs @@ -66,13 +66,13 @@ namespace SuperStarTrek.Space } } - public IEnumerable GetDisplayLines() => Enumerable.Range(1, 8).Select(x => GetDisplayLine(x)); + public IEnumerable GetDisplayLines() => Enumerable.Range(0, 8).Select(x => GetDisplayLine(x)); private string GetDisplayLine(int x) => string.Join( " ", Enumerable - .Range(1, 8) + .Range(0, 8) .Select(y => new Coordinates(x, y)) .Select(c => _sectors.GetValueOrDefault(c)) .Select(o => o?.ToString() ?? " ")); diff --git a/84 Super Star Trek/csharp/Space/QuadrantInfo.cs b/84 Super Star Trek/csharp/Space/QuadrantInfo.cs index ed9ed3fa..20f21ee2 100644 --- a/84 Super Star Trek/csharp/Space/QuadrantInfo.cs +++ b/84 Super Star Trek/csharp/Space/QuadrantInfo.cs @@ -2,6 +2,8 @@ namespace SuperStarTrek.Space { internal class QuadrantInfo { + private bool _isKnown; + private QuadrantInfo(Coordinates coordinates, string name, int klingonCount, int starCount, bool hasStarbase) { Coordinates = coordinates; @@ -36,5 +38,13 @@ namespace SuperStarTrek.Space internal void AddKlingon() => KlingonCount += 1; internal void AddStarbase() => HasStarbase = true; + + public string Scan() + { + _isKnown = true; + return ToString(); + } + + public override string ToString() => _isKnown ? $"{KlingonCount}{(HasStarbase ? 1 : 0)}{StarCount}" : "***"; } } diff --git a/84 Super Star Trek/csharp/Systems/LongRangeSensors.cs b/84 Super Star Trek/csharp/Systems/LongRangeSensors.cs new file mode 100644 index 00000000..233af4a6 --- /dev/null +++ b/84 Super Star Trek/csharp/Systems/LongRangeSensors.cs @@ -0,0 +1,44 @@ + +using System; +using System.Collections.Generic; +using System.Linq; +using SuperStarTrek.Commands; +using SuperStarTrek.Objects; +using SuperStarTrek.Resources; +using SuperStarTrek.Space; + +namespace SuperStarTrek.Systems +{ + internal class LongRangeSensors : Subsystem + { + private readonly Galaxy _galaxy; + private readonly Output _output; + + public LongRangeSensors(Galaxy galaxy, Output output) + : base("Long Range Sensors", Command.LRS) + { + _galaxy = galaxy; + _output = output; + } + + public override CommandResult ExecuteCommand(Quadrant quadrant) + { + if (Condition < 0) + { + _output.WriteLine("Long Range Sensors are inoperable"); + } + else + { + _output.WriteLine($"Long range scan for quadrant {quadrant.Coordinates}"); + _output.WriteLine("-------------------"); + foreach (var quadrants in _galaxy.GetNeighborhood(quadrant)) + { + _output.WriteLine(": " + string.Join(" : ", quadrants.Select(q => q?.Scan() ?? "***")) + " :"); + _output.WriteLine("-------------------"); + } + } + + return CommandResult.Ok; + } + } +} From 345545a27d452b5bda4b803bf992b711f6150242 Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Sun, 7 Mar 2021 14:36:11 +1100 Subject: [PATCH 06/15] Add Photon Tubes --- 84 Super Star Trek/csharp/Game.cs | 6 +- 84 Super Star Trek/csharp/Input.cs | 6 +- .../csharp/Objects/Enterprise.cs | 36 ++++++++- 84 Super Star Trek/csharp/Objects/Klingon.cs | 20 ++++- 84 Super Star Trek/csharp/Objects/Starbase.cs | 5 +- .../csharp/Resources/CourtMartial.txt | 3 + .../csharp/Resources/Protected.txt | 1 + .../csharp/Resources/RelievedOfCommand.txt | 3 + .../csharp/Resources/Strings.cs | 3 + 84 Super Star Trek/csharp/Space/Coordinate.cs | 28 +++++++ 84 Super Star Trek/csharp/Space/Course.cs | 25 +++++- 84 Super Star Trek/csharp/Space/Quadrant.cs | 80 ++++++++++++++++--- .../csharp/Space/QuadrantInfo.cs | 17 +++- .../csharp/Systems/DamageControl.cs | 4 +- .../csharp/Systems/LongRangeSensors.cs | 21 ++--- .../csharp/Systems/PhotonTubes.cs | 63 +++++++++++++++ .../csharp/Systems/ShieldControl.cs | 22 ++--- .../csharp/Systems/ShortRangeSensors.cs | 4 +- .../csharp/Systems/Subsystem.cs | 35 +++++++- 19 files changed, 319 insertions(+), 63 deletions(-) create mode 100644 84 Super Star Trek/csharp/Resources/CourtMartial.txt create mode 100644 84 Super Star Trek/csharp/Resources/Protected.txt create mode 100644 84 Super Star Trek/csharp/Resources/RelievedOfCommand.txt create mode 100644 84 Super Star Trek/csharp/Systems/PhotonTubes.cs diff --git a/84 Super Star Trek/csharp/Game.cs b/84 Super Star Trek/csharp/Game.cs index 0547103b..6473877e 100644 --- a/84 Super Star Trek/csharp/Game.cs +++ b/84 Super Star Trek/csharp/Game.cs @@ -79,15 +79,14 @@ namespace SuperStarTrek _galaxy = new Galaxy(); _initialKlingonCount = _galaxy.KlingonCount; - _enterprise = new Enterprise(3000, random.GetCoordinate(), _output); + _enterprise = new Enterprise(3000, random.GetCoordinate(), _output, random); _enterprise .Add(new ShortRangeSensors(_enterprise, _galaxy, this, _output)) .Add(new LongRangeSensors(_galaxy, _output)) + .Add(new PhotonTubes(10, _enterprise, _output, _input)) .Add(new ShieldControl(_enterprise, _output, _input)) .Add(new DamageControl(_enterprise, _output)); - var quadrant = new Quadrant(_galaxy[_currentQuadrant], _enterprise); - _output.Write(Strings.Enterprise); _output.Write( Strings.Orders, @@ -100,6 +99,7 @@ namespace SuperStarTrek _input.WaitForAnyKeyButEnter("when ready to accept command"); + var quadrant = _galaxy[_currentQuadrant].BuildQuadrant(_enterprise, random, _galaxy); _enterprise.Enter(quadrant, Strings.StartText); } diff --git a/84 Super Star Trek/csharp/Input.cs b/84 Super Star Trek/csharp/Input.cs index 0fba2e4c..c632007f 100644 --- a/84 Super Star Trek/csharp/Input.cs +++ b/84 Super Star Trek/csharp/Input.cs @@ -27,14 +27,14 @@ namespace SuperStarTrek return Console.ReadLine(); } - public double GetNumber(string prompt) + public float GetNumber(string prompt) { _output.Prompt(prompt); while (true) { var response = Console.ReadLine(); - if (double.TryParse(response, out var value)) + if (float.TryParse(response, out var value)) { return value; } @@ -44,7 +44,7 @@ namespace SuperStarTrek } } - public bool TryGetNumber(string prompt, double minValue, double maxValue, out double value) + public bool TryGetNumber(string prompt, float minValue, float maxValue, out float value) { value = GetNumber($"{prompt} ({minValue}-{maxValue})"); diff --git a/84 Super Star Trek/csharp/Objects/Enterprise.cs b/84 Super Star Trek/csharp/Objects/Enterprise.cs index 97e5e3cd..ddaa10a9 100644 --- a/84 Super Star Trek/csharp/Objects/Enterprise.cs +++ b/84 Super Star Trek/csharp/Objects/Enterprise.cs @@ -15,9 +15,10 @@ namespace SuperStarTrek.Objects private readonly Output _output; private readonly List _systems; private readonly Dictionary _commandExecutors; + private readonly Random _random; private Quadrant _quadrant; - public Enterprise(int maxEnergy, Coordinates sector, Output output) + public Enterprise(int maxEnergy, Coordinates sector, Output output, Random random) { Sector = sector; TotalEnergy = _maxEnergy = maxEnergy; @@ -25,6 +26,7 @@ namespace SuperStarTrek.Objects _systems = new List(); _commandExecutors = new Dictionary(); _output = output; + _random = random; } public Coordinates Quadrant => _quadrant.Coordinates; @@ -88,5 +90,37 @@ namespace SuperStarTrek.Objects } public override string ToString() => "<*>"; + + internal CommandResult TakeHit(Coordinates sector, int hitStrength) + { + _output.WriteLine($"{hitStrength} unit hit on Enterprise from sector {sector}"); + ShieldControl.AbsorbHit(hitStrength); + + if (ShieldControl.ShieldEnergy <= 0) + { + _output.WriteLine(Strings.Destroyed); + return CommandResult.GameOver; + } + + _output.WriteLine($" "); + + if (hitStrength >= 20) + { + TakeDamage(hitStrength); + } + + return CommandResult.Ok; + } + + private void TakeDamage(double hitStrength) + { + var hitShieldRatio = hitStrength / ShieldControl.ShieldEnergy; + if (_random.GetDouble() > 0.6 || hitShieldRatio <= 0.02) + { + return; + } + + _systems[_random.Get1To8Inclusive() - 1].TakeDamage(hitShieldRatio + 0.5 * _random.GetDouble()); + } } } diff --git a/84 Super Star Trek/csharp/Objects/Klingon.cs b/84 Super Star Trek/csharp/Objects/Klingon.cs index fdf47031..0bbaf984 100644 --- a/84 Super Star Trek/csharp/Objects/Klingon.cs +++ b/84 Super Star Trek/csharp/Objects/Klingon.cs @@ -1,14 +1,30 @@ +using SuperStarTrek.Commands; +using SuperStarTrek.Space; + namespace SuperStarTrek.Objects { internal class Klingon { private double _energy; + private Coordinates _sector; + private readonly Random _random; - public Klingon() + public Klingon(Coordinates sector, Random random) { - _energy = new Random().GetDouble(100, 300); + _sector = sector; + _random = random; + _energy = _random.GetDouble(100, 300); } public override string ToString() => "+K+"; + + public CommandResult FireOn(Enterprise enterprise) + { + var attackStrength = _random.GetDouble(); + var hitStrength = (int)(_energy * (2 + attackStrength) / _sector.GetDistanceTo(enterprise.Sector)); + _energy /= 3 + attackStrength; + + return enterprise.TakeHit(_sector, hitStrength); + } } } diff --git a/84 Super Star Trek/csharp/Objects/Starbase.cs b/84 Super Star Trek/csharp/Objects/Starbase.cs index e11ca9f5..b96ffab1 100644 --- a/84 Super Star Trek/csharp/Objects/Starbase.cs +++ b/84 Super Star Trek/csharp/Objects/Starbase.cs @@ -8,10 +8,11 @@ namespace SuperStarTrek.Objects private readonly Output _output; private readonly double _repairDelay; - public Starbase(Random random, Input input) + public Starbase(Random random, Input input, Output output) { _repairDelay = random.GetDouble() * 0.5; _input = input; + _output = output; } public override string ToString() => ">!<"; @@ -34,5 +35,7 @@ namespace SuperStarTrek.Objects repairTime = 0; return false; } + + internal void ProtectEnterprise() => _output.WriteLine(Strings.Protected); } } diff --git a/84 Super Star Trek/csharp/Resources/CourtMartial.txt b/84 Super Star Trek/csharp/Resources/CourtMartial.txt new file mode 100644 index 00000000..7d05a5b8 --- /dev/null +++ b/84 Super Star Trek/csharp/Resources/CourtMartial.txt @@ -0,0 +1,3 @@ + +Starfleet Command reviewing your record to consider +court martial! \ No newline at end of file diff --git a/84 Super Star Trek/csharp/Resources/Protected.txt b/84 Super Star Trek/csharp/Resources/Protected.txt new file mode 100644 index 00000000..27c4a5f8 --- /dev/null +++ b/84 Super Star Trek/csharp/Resources/Protected.txt @@ -0,0 +1 @@ +Starbase shields protect the Enterprise \ No newline at end of file diff --git a/84 Super Star Trek/csharp/Resources/RelievedOfCommand.txt b/84 Super Star Trek/csharp/Resources/RelievedOfCommand.txt new file mode 100644 index 00000000..8086e3ca --- /dev/null +++ b/84 Super Star Trek/csharp/Resources/RelievedOfCommand.txt @@ -0,0 +1,3 @@ + +That does it, Captain!! You are hereby relieved of command +and sentenced to 99 stardates at hard labor on Cygnus 12!! \ No newline at end of file diff --git a/84 Super Star Trek/csharp/Resources/Strings.cs b/84 Super Star Trek/csharp/Resources/Strings.cs index 210d22ba..c76fe691 100644 --- a/84 Super Star Trek/csharp/Resources/Strings.cs +++ b/84 Super Star Trek/csharp/Resources/Strings.cs @@ -8,13 +8,16 @@ namespace SuperStarTrek.Resources { public static string CombatArea => GetResource(); public static string Congratulations => GetResource(); + public static string CourtMartial => GetResource(); public static string Destroyed => GetResource(); public static string EndOfMission => GetResource(); public static string Enterprise => GetResource(); public static string Instructions => GetResource(); public static string LowShields => GetResource(); public static string Orders => GetResource(); + public static string Protected => GetResource(); public static string RegionNames => GetResource(); + public static string RelievedOfCommand => GetResource(); public static string RepairEstimate => GetResource(); public static string RepairPrompt => GetResource(); public static string ReplayPrompt => GetResource(); diff --git a/84 Super Star Trek/csharp/Space/Coordinate.cs b/84 Super Star Trek/csharp/Space/Coordinate.cs index aa5b5285..b103a528 100644 --- a/84 Super Star Trek/csharp/Space/Coordinate.cs +++ b/84 Super Star Trek/csharp/Space/Coordinate.cs @@ -24,6 +24,34 @@ namespace SuperStarTrek.Space throw new ArgumentOutOfRangeException(argumentName, value, "Must be 0 to 7 inclusive"); } + private static bool IsValid(int value) => value >= 0 && value <= 7; + public override string ToString() => $"{X+1} , {Y+1}"; + + internal void Deconstruct(out int x, out int y) + { + x = X; + y = Y; + } + + internal static bool TryCreate(float x, float y, out Coordinates coordinates) + { + var roundedX = Round(x); + var roundedY = Round(y); + + if (IsValid(roundedX) && IsValid(roundedY)) + { + coordinates = new Coordinates(roundedX, roundedY); + return true; + } + + coordinates = default; + return false; + + int Round(float value) => (int)Math.Round(value, MidpointRounding.AwayFromZero); + } + + internal float GetDistanceTo(Coordinates destination) => + (float)Math.Sqrt(Math.Pow(X - destination.X, 2) + Math.Pow(Y - destination.Y, 2)); } } diff --git a/84 Super Star Trek/csharp/Space/Course.cs b/84 Super Star Trek/csharp/Space/Course.cs index dd9ecfba..99c48c1a 100644 --- a/84 Super Star Trek/csharp/Space/Course.cs +++ b/84 Super Star Trek/csharp/Space/Course.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; namespace SuperStarTrek.Space { @@ -24,7 +25,7 @@ namespace SuperStarTrek.Space (0, 1) }; - public Course(double direction) + public Course(float direction) { if (direction < 1 || direction > 9) { @@ -44,7 +45,25 @@ namespace SuperStarTrek.Space DeltaY = baseCardinal.DeltaY + (nextCardinal.DeltaY - baseCardinal.DeltaY) * fractionalDirection; } - public double DeltaX { get; } - public double DeltaY { get; } + public float DeltaX { get; } + public float DeltaY { get; } + + public IEnumerable GetSectorsFrom(Coordinates start) + { + (double x, double y) = start; + + while(true) + { + x += DeltaX; + y += DeltaY; + + if (!Coordinates.TryCreate(x, y, out var coordinates)) + { + yield break; + } + + yield return coordinates; + } + } } } diff --git a/84 Super Star Trek/csharp/Space/Quadrant.cs b/84 Super Star Trek/csharp/Space/Quadrant.cs index e483604f..d89d60e0 100644 --- a/84 Super Star Trek/csharp/Space/Quadrant.cs +++ b/84 Super Star Trek/csharp/Space/Quadrant.cs @@ -1,7 +1,9 @@ using System; using System.Collections.Generic; using System.Linq; +using SuperStarTrek.Commands; using SuperStarTrek.Objects; +using SuperStarTrek.Resources; namespace SuperStarTrek.Space { @@ -10,43 +12,47 @@ namespace SuperStarTrek.Space private readonly QuadrantInfo _info; private readonly Random _random; private readonly Dictionary _sectors; - private readonly Coordinates _enterpriseSector; + private readonly Enterprise _enterprise; private readonly Coordinates _starbaseSector; + private readonly Galaxy _galaxy; - public Quadrant(QuadrantInfo info, Enterprise enterprise) + public Quadrant(QuadrantInfo info, Enterprise enterprise, Random random, Galaxy galaxy) { _info = info; - _random = new Random(); + _random = random; + _galaxy = galaxy; - _enterpriseSector = enterprise.Sector; - _sectors = new Dictionary { [enterprise.Sector] = enterprise }; - PositionObject(() => new Klingon(), _info.KlingonCount); + _sectors = new() { [enterprise.Sector] = _enterprise = enterprise }; + PositionObject(sector => new Klingon(sector, _random), _info.KlingonCount); if (_info.HasStarbase) { - _starbaseSector = PositionObject(() => new Starbase(_random, new Input(new Output()))); + _starbaseSector = PositionObject(_ => new Starbase(_random, new Input(new Output()), new Output())); } - PositionObject(() => new Star(), _info.StarCount); + PositionObject(_ => new Star(), _info.StarCount); } + public object this[Coordinates coordinates] => _sectors.GetValueOrDefault(coordinates); public Coordinates Coordinates => _info.Coordinates; public bool HasKlingons => _info.KlingonCount > 0; public bool HasStarbase => _info.HasStarbase; public Starbase Starbase => HasStarbase ? (Starbase)_sectors[_starbaseSector] : null; public bool EnterpriseIsNextToStarbase => _info.HasStarbase && - Math.Abs(_enterpriseSector.X - _starbaseSector.X) <= 1 && - Math.Abs(_enterpriseSector.Y - _starbaseSector.Y) <= 1; + Math.Abs(_enterprise.Sector.X - _starbaseSector.X) <= 1 && + Math.Abs(_enterprise.Sector.Y - _starbaseSector.Y) <= 1; + + private IEnumerable Klingons => _sectors.Values.OfType(); public override string ToString() => _info.Name; - private Coordinates PositionObject(Func objectFactory) + private Coordinates PositionObject(Func objectFactory) { var sector = GetRandomEmptySector(); - _sectors[sector] = objectFactory.Invoke(); + _sectors[sector] = objectFactory.Invoke(sector); return sector; } - private void PositionObject(Func objectFactory, int count) + private void PositionObject(Func objectFactory, int count) { for (int i = 0; i < count; i++) { @@ -54,6 +60,54 @@ namespace SuperStarTrek.Space } } + internal bool TorpedoCollisionAt(Coordinates coordinates, out string message, out bool gameOver) + { + gameOver = false; + message = default; + + switch (_sectors.GetValueOrDefault(coordinates)) + { + case Klingon _: + _sectors.Remove(coordinates); + _info.RemoveKlingon(); + message = "*** Klingon destroyed ***"; + gameOver = _galaxy.KlingonCount == 0; + return true; + + case Star _: + message = $"Star at {coordinates} absorbed torpedo energy."; + return true; + + case Starbase _: + _sectors.Remove(coordinates); + _info.RemoveStarbase(); + message = "*** Starbase destroyed ***" + + (_galaxy.StarbaseCount > 0 ? Strings.CourtMartial : Strings.RelievedOfCommand); + gameOver = _galaxy.StarbaseCount == 0; + return true; + + default: + return false; + } + } + + internal CommandResult KlingonsFireOnEnterprise() + { + if (EnterpriseIsNextToStarbase && Klingons.Any()) + { + Starbase.ProtectEnterprise(); + return CommandResult.Ok; + } + + foreach (var klingon in Klingons) + { + var result = klingon.FireOn(_enterprise); + if (result.IsGameOver) { return result; } + } + + return CommandResult.Ok; + } + private Coordinates GetRandomEmptySector() { while (true) diff --git a/84 Super Star Trek/csharp/Space/QuadrantInfo.cs b/84 Super Star Trek/csharp/Space/QuadrantInfo.cs index 20f21ee2..284c8c84 100644 --- a/84 Super Star Trek/csharp/Space/QuadrantInfo.cs +++ b/84 Super Star Trek/csharp/Space/QuadrantInfo.cs @@ -1,3 +1,5 @@ +using SuperStarTrek.Objects; + namespace SuperStarTrek.Space { internal class QuadrantInfo @@ -39,12 +41,25 @@ namespace SuperStarTrek.Space internal void AddStarbase() => HasStarbase = true; - public string Scan() + internal Quadrant BuildQuadrant(Enterprise enterprise, Random random, Galaxy galaxy) => + new(this, enterprise, random, galaxy); + + internal string Scan() { _isKnown = true; return ToString(); } public override string ToString() => _isKnown ? $"{KlingonCount}{(HasStarbase ? 1 : 0)}{StarCount}" : "***"; + + internal void RemoveKlingon() + { + if (KlingonCount > 0) + { + KlingonCount -= 1; + } + } + + internal void RemoveStarbase() => HasStarbase = false; } } diff --git a/84 Super Star Trek/csharp/Systems/DamageControl.cs b/84 Super Star Trek/csharp/Systems/DamageControl.cs index b4587add..25f5ad78 100644 --- a/84 Super Star Trek/csharp/Systems/DamageControl.cs +++ b/84 Super Star Trek/csharp/Systems/DamageControl.cs @@ -10,13 +10,13 @@ namespace SuperStarTrek.Systems private readonly Output _output; public DamageControl(Enterprise enterprise, Output output) - : base("Damage Control", Command.DAM) + : base("Damage Control", Command.DAM, output) { _enterprise = enterprise; _output = output; } - public override CommandResult ExecuteCommand(Quadrant quadrant) + protected override CommandResult ExecuteCommandCore(Quadrant quadrant) { if (IsDamaged) { diff --git a/84 Super Star Trek/csharp/Systems/LongRangeSensors.cs b/84 Super Star Trek/csharp/Systems/LongRangeSensors.cs index 233af4a6..84ed7a87 100644 --- a/84 Super Star Trek/csharp/Systems/LongRangeSensors.cs +++ b/84 Super Star Trek/csharp/Systems/LongRangeSensors.cs @@ -15,27 +15,22 @@ namespace SuperStarTrek.Systems private readonly Output _output; public LongRangeSensors(Galaxy galaxy, Output output) - : base("Long Range Sensors", Command.LRS) + : base("Long Range Sensors", Command.LRS, output) { _galaxy = galaxy; _output = output; } - public override CommandResult ExecuteCommand(Quadrant quadrant) + protected override bool CanExecuteCommand() => IsOperational("{name} are inoperable"); + + protected override CommandResult ExecuteCommandCore(Quadrant quadrant) { - if (Condition < 0) + _output.WriteLine($"Long range scan for quadrant {quadrant.Coordinates}"); + _output.WriteLine("-------------------"); + foreach (var quadrants in _galaxy.GetNeighborhood(quadrant)) { - _output.WriteLine("Long Range Sensors are inoperable"); - } - else - { - _output.WriteLine($"Long range scan for quadrant {quadrant.Coordinates}"); + _output.WriteLine(": " + string.Join(" : ", quadrants.Select(q => q?.Scan() ?? "***")) + " :"); _output.WriteLine("-------------------"); - foreach (var quadrants in _galaxy.GetNeighborhood(quadrant)) - { - _output.WriteLine(": " + string.Join(" : ", quadrants.Select(q => q?.Scan() ?? "***")) + " :"); - _output.WriteLine("-------------------"); - } } return CommandResult.Ok; diff --git a/84 Super Star Trek/csharp/Systems/PhotonTubes.cs b/84 Super Star Trek/csharp/Systems/PhotonTubes.cs new file mode 100644 index 00000000..034199c9 --- /dev/null +++ b/84 Super Star Trek/csharp/Systems/PhotonTubes.cs @@ -0,0 +1,63 @@ +using SuperStarTrek.Commands; +using SuperStarTrek.Objects; +using SuperStarTrek.Space; + +namespace SuperStarTrek.Systems +{ + internal class PhotonTubes : Subsystem + { + private readonly int _tubeCount; + private readonly Enterprise _enterprise; + private readonly Output _output; + private readonly Input _input; + + public PhotonTubes(int tubeCount, Enterprise enterprise, Output output, Input input) + : base("Photon Tubes", Command.TOR, output) + { + TorpedoCount = _tubeCount = tubeCount; + _enterprise = enterprise; + _output = output; + _input = input; + } + + public int TorpedoCount { get; private set; } + + protected override bool CanExecuteCommand() => HasTorpedoes() && IsOperational("{name} are not operational"); + + private bool HasTorpedoes() + { + if (TorpedoCount > 0) { return true; } + + _output.WriteLine("All photon torpedoes expended"); + return false; + } + + protected override CommandResult ExecuteCommandCore(Quadrant quadrant) + { + if (!_input.TryGetNumber("Photon torpedo course", 1, 9, out var direction)) + { + _output.WriteLine("Ensign Chekov reports, 'Incorrect course data, sir!'"); + return CommandResult.Ok; + } + + var isHit = false; + _output.WriteLine("Torpedo track:"); + foreach (var sector in new Course(direction).GetSectorsFrom(_enterprise.Sector)) + { + _output.WriteLine($" {sector}"); + + if (quadrant.TorpedoCollisionAt(sector, out var message, out var gameOver)) + { + _output.WriteLine(message); + isHit = true; + if (gameOver) { return CommandResult.GameOver; } + break; + } + } + + if (!isHit) { _output.WriteLine("Torpedo missed!"); } + + return quadrant.KlingonsFireOnEnterprise(); + } + } +} diff --git a/84 Super Star Trek/csharp/Systems/ShieldControl.cs b/84 Super Star Trek/csharp/Systems/ShieldControl.cs index 9c4a3c16..48320588 100644 --- a/84 Super Star Trek/csharp/Systems/ShieldControl.cs +++ b/84 Super Star Trek/csharp/Systems/ShieldControl.cs @@ -11,7 +11,7 @@ namespace SuperStarTrek.Systems private readonly Input _input; public ShieldControl(Enterprise enterprise, Output output, Input input) - : base("Shield Control", Command.SHE) + : base("Shield Control", Command.SHE, output) { _enterprise = enterprise; _output = output; @@ -20,21 +20,9 @@ namespace SuperStarTrek.Systems public double ShieldEnergy { get; private set; } - public override CommandResult ExecuteCommand(Quadrant quadrant) - { - if (Condition < 0) - { - _output.WriteLine("Shield Control inoperable"); - } - else - { - UpdateShields(); - } + protected override bool CanExecuteCommand() => IsOperational("{name} inoperable"); - return CommandResult.Ok; - } - - private void UpdateShields() + protected override CommandResult ExecuteCommandCore(Quadrant quadrant) { _output.WriteLine($"Energy available = {_enterprise.TotalEnergy}"); var requested = _input.GetNumber($"Number of units to shields"); @@ -47,6 +35,8 @@ namespace SuperStarTrek.Systems { _output.WriteLine(""); } + + return CommandResult.Ok; } private bool Validate(double requested) @@ -59,5 +49,7 @@ namespace SuperStarTrek.Systems return requested >= 0 && requested != ShieldEnergy; } + + internal void AbsorbHit(int hitStrength) => ShieldEnergy -= hitStrength; } } diff --git a/84 Super Star Trek/csharp/Systems/ShortRangeSensors.cs b/84 Super Star Trek/csharp/Systems/ShortRangeSensors.cs index 953ec66e..e01c829e 100644 --- a/84 Super Star Trek/csharp/Systems/ShortRangeSensors.cs +++ b/84 Super Star Trek/csharp/Systems/ShortRangeSensors.cs @@ -17,7 +17,7 @@ namespace SuperStarTrek.Systems private readonly Output _output; public ShortRangeSensors(Enterprise enterprise, Galaxy galaxy, Game game, Output output) - : base("Short Range Sensors", Command.SRS) + : base("Short Range Sensors", Command.SRS, output) { _enterprise = enterprise; _galaxy = galaxy; @@ -25,7 +25,7 @@ namespace SuperStarTrek.Systems _output = output; } - public override CommandResult ExecuteCommand(Quadrant quadrant) + protected override CommandResult ExecuteCommandCore(Quadrant quadrant) { if (_enterprise.IsDocked) { diff --git a/84 Super Star Trek/csharp/Systems/Subsystem.cs b/84 Super Star Trek/csharp/Systems/Subsystem.cs index 53398b41..88924a8c 100644 --- a/84 Super Star Trek/csharp/Systems/Subsystem.cs +++ b/84 Super Star Trek/csharp/Systems/Subsystem.cs @@ -1,3 +1,4 @@ +using System; using SuperStarTrek.Commands; using SuperStarTrek.Space; @@ -5,11 +6,14 @@ namespace SuperStarTrek.Systems { internal abstract class Subsystem { - protected Subsystem(string name, Command command) + private readonly Output _output; + + protected Subsystem(string name, Command command, Output output) { Name = name; Command = command; Condition = 0; + _output = output; } public string Name { get; } @@ -17,10 +21,33 @@ namespace SuperStarTrek.Systems public bool IsDamaged => Condition < 0; public Command Command { get; } - public abstract CommandResult ExecuteCommand(Quadrant quadrant); - public void Repair() + protected virtual bool CanExecuteCommand() => true; + + protected bool IsOperational(string notOperationalMessage) { - if (Condition < 0) { Condition = 0; } + if (IsDamaged) + { + _output.WriteLine(notOperationalMessage.Replace("{name}", Name)); + return false; + } + + return true; + } + + public CommandResult ExecuteCommand(Quadrant quadrant) + => CanExecuteCommand() ? ExecuteCommandCore(quadrant) : CommandResult.Ok; + + protected abstract CommandResult ExecuteCommandCore(Quadrant quadrant); + + public virtual void Repair() + { + if (IsDamaged) { Condition = 0; } + } + + internal void TakeDamage(double damage) + { + Condition -= damage; + _output.WriteLine($"Damage Control reports, '{Name} damaged by the hit.'"); } } } From d0ed8d2f35c74fe23fa2877320bd30e2842e8b60 Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Sun, 7 Mar 2021 18:27:55 +1100 Subject: [PATCH 07/15] Reduce precision to float --- 84 Super Star Trek/csharp/Commands/CommandResult.cs | 6 +++--- 84 Super Star Trek/csharp/Game.cs | 8 ++++---- 84 Super Star Trek/csharp/Objects/Enterprise.cs | 12 ++++++------ 84 Super Star Trek/csharp/Objects/Klingon.cs | 6 +++--- 84 Super Star Trek/csharp/Objects/Starbase.cs | 10 +++++----- 84 Super Star Trek/csharp/Random.cs | 8 ++++---- 84 Super Star Trek/csharp/Space/Course.cs | 2 +- 84 Super Star Trek/csharp/Space/QuadrantInfo.cs | 10 +++++----- 84 Super Star Trek/csharp/Systems/ShieldControl.cs | 4 ++-- 84 Super Star Trek/csharp/Systems/Subsystem.cs | 4 ++-- 10 files changed, 35 insertions(+), 35 deletions(-) diff --git a/84 Super Star Trek/csharp/Commands/CommandResult.cs b/84 Super Star Trek/csharp/Commands/CommandResult.cs index d92fba09..1b02780c 100644 --- a/84 Super Star Trek/csharp/Commands/CommandResult.cs +++ b/84 Super Star Trek/csharp/Commands/CommandResult.cs @@ -10,14 +10,14 @@ namespace SuperStarTrek.Commands IsGameOver = isGameOver; } - private CommandResult(double timeElapsed) + private CommandResult(float timeElapsed) { TimeElapsed = timeElapsed; } public bool IsGameOver { get; } - public double TimeElapsed { get; } + public float TimeElapsed { get; } - public static CommandResult Elapsed(double timeElapsed) => new(timeElapsed); + public static CommandResult Elapsed(float timeElapsed) => new(timeElapsed); } } diff --git a/84 Super Star Trek/csharp/Game.cs b/84 Super Star Trek/csharp/Game.cs index 6473877e..0d5539ba 100644 --- a/84 Super Star Trek/csharp/Game.cs +++ b/84 Super Star Trek/csharp/Game.cs @@ -14,7 +14,7 @@ namespace SuperStarTrek private int _initialStardate; private int _finalStarDate; - private double _currentStardate; + private float _currentStardate; private Coordinates _currentQuadrant; private Coordinates _currentSector; private Galaxy _galaxy; @@ -27,7 +27,7 @@ namespace SuperStarTrek _input = new Input(_output); } - public double Stardate => _currentStardate; + public float Stardate => _currentStardate; public void DoIntroduction() { @@ -111,7 +111,7 @@ namespace SuperStarTrek return _enterprise.IsStranded; } - private double GetEfficiency() => - 1000 * Math.Pow(_initialKlingonCount / (_currentStardate - _initialStardate), 2); + private float GetEfficiency() => + 1000 * (float)Math.Pow(_initialKlingonCount / (_currentStardate - _initialStardate), 2); } } diff --git a/84 Super Star Trek/csharp/Objects/Enterprise.cs b/84 Super Star Trek/csharp/Objects/Enterprise.cs index ddaa10a9..ed11bb1e 100644 --- a/84 Super Star Trek/csharp/Objects/Enterprise.cs +++ b/84 Super Star Trek/csharp/Objects/Enterprise.cs @@ -33,8 +33,8 @@ namespace SuperStarTrek.Objects public Coordinates Sector { get; } public string Condition => GetCondition(); public ShieldControl ShieldControl => (ShieldControl)_commandExecutors[Command.SHE]; - public double Energy => TotalEnergy - ShieldControl.ShieldEnergy; - public double TotalEnergy { get; private set; } + public float Energy => TotalEnergy - ShieldControl.ShieldEnergy; + public float TotalEnergy { get; private set; } public int DamagedSystemCount => _systems.Count(s => s.IsDamaged); public IEnumerable Systems => _systems; public int TorpedoCount { get; } @@ -68,7 +68,7 @@ namespace SuperStarTrek.Objects (_quadrant.HasKlingons, Energy / _maxEnergy) switch { (true, _) => "*Red*", - (_, < 0.1) => "Yellow", + (_, < 0.1f) => "Yellow", _ => "Green" }; @@ -112,15 +112,15 @@ namespace SuperStarTrek.Objects return CommandResult.Ok; } - private void TakeDamage(double hitStrength) + private void TakeDamage(float hitStrength) { var hitShieldRatio = hitStrength / ShieldControl.ShieldEnergy; - if (_random.GetDouble() > 0.6 || hitShieldRatio <= 0.02) + if (_random.GetFloat() > 0.6 || hitShieldRatio <= 0.02f) { return; } - _systems[_random.Get1To8Inclusive() - 1].TakeDamage(hitShieldRatio + 0.5 * _random.GetDouble()); + _systems[_random.Get1To8Inclusive() - 1].TakeDamage(hitShieldRatio + 0.5f * _random.GetFloat()); } } } diff --git a/84 Super Star Trek/csharp/Objects/Klingon.cs b/84 Super Star Trek/csharp/Objects/Klingon.cs index 0bbaf984..29584aec 100644 --- a/84 Super Star Trek/csharp/Objects/Klingon.cs +++ b/84 Super Star Trek/csharp/Objects/Klingon.cs @@ -5,7 +5,7 @@ namespace SuperStarTrek.Objects { internal class Klingon { - private double _energy; + private float _energy; private Coordinates _sector; private readonly Random _random; @@ -13,14 +13,14 @@ namespace SuperStarTrek.Objects { _sector = sector; _random = random; - _energy = _random.GetDouble(100, 300); + _energy = _random.GetFloat(100, 300); } public override string ToString() => "+K+"; public CommandResult FireOn(Enterprise enterprise) { - var attackStrength = _random.GetDouble(); + var attackStrength = _random.GetFloat(); var hitStrength = (int)(_energy * (2 + attackStrength) / _sector.GetDistanceTo(enterprise.Sector)); _energy /= 3 + attackStrength; diff --git a/84 Super Star Trek/csharp/Objects/Starbase.cs b/84 Super Star Trek/csharp/Objects/Starbase.cs index b96ffab1..4d854efd 100644 --- a/84 Super Star Trek/csharp/Objects/Starbase.cs +++ b/84 Super Star Trek/csharp/Objects/Starbase.cs @@ -6,21 +6,21 @@ namespace SuperStarTrek.Objects { private readonly Input _input; private readonly Output _output; - private readonly double _repairDelay; + private readonly float _repairDelay; public Starbase(Random random, Input input, Output output) { - _repairDelay = random.GetDouble() * 0.5; + _repairDelay = random.GetFloat() * 0.5f; _input = input; _output = output; } public override string ToString() => ">!<"; - internal bool TryRepair(Enterprise enterprise, out double repairTime) + internal bool TryRepair(Enterprise enterprise, out float repairTime) { - repairTime = enterprise.DamagedSystemCount * 0.1 + _repairDelay; - if (repairTime >= 1) { repairTime = 0.9; } + repairTime = enterprise.DamagedSystemCount * 0.1f + _repairDelay; + if (repairTime >= 1) { repairTime = 0.9f; } _output.Write(Strings.RepairEstimate, repairTime); if (_input.GetYesNo(Strings.RepairPrompt, Input.YesNoMode.TrueOnY)) diff --git a/84 Super Star Trek/csharp/Random.cs b/84 Super Star Trek/csharp/Random.cs index 460c1cef..5ed47805 100644 --- a/84 Super Star Trek/csharp/Random.cs +++ b/84 Super Star Trek/csharp/Random.cs @@ -12,14 +12,14 @@ namespace SuperStarTrek // 475 DEF FNR(R)=INT(RND(R)*7.98+1.01) // Returns a value from 1 to 8, inclusive. // Note there's a slight bias away from the extreme values, 1 and 8. - public int Get1To8Inclusive() => (int)(_random.NextDouble() * 7.98 + 1.01); + public int Get1To8Inclusive() => (int)(GetFloat() * 7.98 + 1.01); public int GetInt(int inclusiveMinValue, int exclusiveMaxValue) => _random.Next(inclusiveMinValue, exclusiveMaxValue); - public double GetDouble() => _random.NextDouble(); + public float GetFloat() => (float)_random.NextDouble(); - public double GetDouble(double inclusiveMinValue, double exclusiveMaxValue) - => _random.NextDouble() * (exclusiveMaxValue - inclusiveMinValue) + inclusiveMinValue; + public float GetFloat(float inclusiveMinValue, float exclusiveMaxValue) + => GetFloat() * (exclusiveMaxValue - inclusiveMinValue) + inclusiveMinValue; } } diff --git a/84 Super Star Trek/csharp/Space/Course.cs b/84 Super Star Trek/csharp/Space/Course.cs index 99c48c1a..40bf4bb2 100644 --- a/84 Super Star Trek/csharp/Space/Course.cs +++ b/84 Super Star Trek/csharp/Space/Course.cs @@ -50,7 +50,7 @@ namespace SuperStarTrek.Space public IEnumerable GetSectorsFrom(Coordinates start) { - (double x, double y) = start; + (float x, float y) = start; while(true) { diff --git a/84 Super Star Trek/csharp/Space/QuadrantInfo.cs b/84 Super Star Trek/csharp/Space/QuadrantInfo.cs index 284c8c84..04780a27 100644 --- a/84 Super Star Trek/csharp/Space/QuadrantInfo.cs +++ b/84 Super Star Trek/csharp/Space/QuadrantInfo.cs @@ -24,14 +24,14 @@ namespace SuperStarTrek.Space public static QuadrantInfo Create(Coordinates coordinates, string name) { var random = new Random(); - var klingonCount = random.GetDouble() switch + var klingonCount = random.GetFloat() switch { - > 0.98 => 3, - > 0.95 => 2, - > 0.80 => 1, + > 0.98f => 3, + > 0.95f => 2, + > 0.80f => 1, _ => 0 }; - var hasStarbase = random.GetDouble() > 0.96; + var hasStarbase = random.GetFloat() > 0.96f; var starCount = random.Get1To8Inclusive(); return new QuadrantInfo(coordinates, name, klingonCount, starCount, hasStarbase); diff --git a/84 Super Star Trek/csharp/Systems/ShieldControl.cs b/84 Super Star Trek/csharp/Systems/ShieldControl.cs index 48320588..6ceefcf4 100644 --- a/84 Super Star Trek/csharp/Systems/ShieldControl.cs +++ b/84 Super Star Trek/csharp/Systems/ShieldControl.cs @@ -18,7 +18,7 @@ namespace SuperStarTrek.Systems _input = input; } - public double ShieldEnergy { get; private set; } + public float ShieldEnergy { get; private set; } protected override bool CanExecuteCommand() => IsOperational("{name} inoperable"); @@ -39,7 +39,7 @@ namespace SuperStarTrek.Systems return CommandResult.Ok; } - private bool Validate(double requested) + private bool Validate(float requested) { if (requested > _enterprise.TotalEnergy) { diff --git a/84 Super Star Trek/csharp/Systems/Subsystem.cs b/84 Super Star Trek/csharp/Systems/Subsystem.cs index 88924a8c..ab7bef4c 100644 --- a/84 Super Star Trek/csharp/Systems/Subsystem.cs +++ b/84 Super Star Trek/csharp/Systems/Subsystem.cs @@ -17,7 +17,7 @@ namespace SuperStarTrek.Systems } public string Name { get; } - public double Condition { get; private set; } + public float Condition { get; private set; } public bool IsDamaged => Condition < 0; public Command Command { get; } @@ -44,7 +44,7 @@ namespace SuperStarTrek.Systems if (IsDamaged) { Condition = 0; } } - internal void TakeDamage(double damage) + internal void TakeDamage(float damage) { Condition -= damage; _output.WriteLine($"Damage Control reports, '{Name} damaged by the hit.'"); From b422db3f4a12a7904b55474a2d7843c3cdd69673 Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Thu, 11 Mar 2021 07:20:28 +1100 Subject: [PATCH 08/15] Add Library-Computer --- 84 Super Star Trek/csharp/Game.cs | 17 +++-- 84 Super Star Trek/csharp/Input.cs | 47 ++++++++++++++ 84 Super Star Trek/csharp/Objects/Klingon.cs | 10 +-- 84 Super Star Trek/csharp/Objects/Starbase.cs | 5 +- 84 Super Star Trek/csharp/Program.cs | 1 + .../csharp/Resources/ComputerFunctions.txt | 9 +++ .../csharp/Resources/NoEnemyShips.txt | 2 + .../csharp/Resources/NoStarbase.txt | 1 + .../csharp/Resources/RegionNames.txt | 16 ++--- .../csharp/Resources/Strings.cs | 3 + 84 Super Star Trek/csharp/Space/Coordinate.cs | 12 ++-- 84 Super Star Trek/csharp/Space/Galaxy.cs | 1 + 84 Super Star Trek/csharp/Space/Quadrant.cs | 25 ++++--- .../csharp/Space/QuadrantInfo.cs | 7 +- 84 Super Star Trek/csharp/StringExtensions.cs | 7 ++ .../ComputerFunctions/ComputerFunction.cs | 18 +++++ .../CumulativeGalacticRecord.cs | 21 ++++++ .../DirectionDistanceCalculator.cs | 32 +++++++++ .../ComputerFunctions/GalacticReport.cs | 34 ++++++++++ .../ComputerFunctions/GalaxyRegionMap.cs | 21 ++++++ .../ComputerFunctions/NavigationCalculator.cs | 29 +++++++++ .../StarbaseDataCalculator.cs | 30 +++++++++ .../Systems/ComputerFunctions/StatusReport.cs | 41 ++++++++++++ .../TorpedoDataCalculator.cs | 33 ++++++++++ .../csharp/Systems/DamageControl.cs | 3 +- .../csharp/Systems/LibraryComputer.cs | 47 ++++++++++++++ .../csharp/Utils/DirectionAndDistance.cs | 65 +++++++++++++++++++ 27 files changed, 503 insertions(+), 34 deletions(-) create mode 100644 84 Super Star Trek/csharp/Resources/ComputerFunctions.txt create mode 100644 84 Super Star Trek/csharp/Resources/NoEnemyShips.txt create mode 100644 84 Super Star Trek/csharp/Resources/NoStarbase.txt create mode 100644 84 Super Star Trek/csharp/StringExtensions.cs create mode 100644 84 Super Star Trek/csharp/Systems/ComputerFunctions/ComputerFunction.cs create mode 100644 84 Super Star Trek/csharp/Systems/ComputerFunctions/CumulativeGalacticRecord.cs create mode 100644 84 Super Star Trek/csharp/Systems/ComputerFunctions/DirectionDistanceCalculator.cs create mode 100644 84 Super Star Trek/csharp/Systems/ComputerFunctions/GalacticReport.cs create mode 100644 84 Super Star Trek/csharp/Systems/ComputerFunctions/GalaxyRegionMap.cs create mode 100644 84 Super Star Trek/csharp/Systems/ComputerFunctions/NavigationCalculator.cs create mode 100644 84 Super Star Trek/csharp/Systems/ComputerFunctions/StarbaseDataCalculator.cs create mode 100644 84 Super Star Trek/csharp/Systems/ComputerFunctions/StatusReport.cs create mode 100644 84 Super Star Trek/csharp/Systems/ComputerFunctions/TorpedoDataCalculator.cs create mode 100644 84 Super Star Trek/csharp/Systems/LibraryComputer.cs create mode 100644 84 Super Star Trek/csharp/Utils/DirectionAndDistance.cs diff --git a/84 Super Star Trek/csharp/Game.cs b/84 Super Star Trek/csharp/Game.cs index 0d5539ba..e32f15c8 100644 --- a/84 Super Star Trek/csharp/Game.cs +++ b/84 Super Star Trek/csharp/Game.cs @@ -3,6 +3,7 @@ using SuperStarTrek.Objects; using SuperStarTrek.Resources; using SuperStarTrek.Space; using SuperStarTrek.Systems; +using SuperStarTrek.Systems.ComputerFunctions; using static System.StringComparison; namespace SuperStarTrek @@ -16,7 +17,6 @@ namespace SuperStarTrek private int _finalStarDate; private float _currentStardate; private Coordinates _currentQuadrant; - private Coordinates _currentSector; private Galaxy _galaxy; private int _initialKlingonCount; private Enterprise _enterprise; @@ -28,6 +28,7 @@ namespace SuperStarTrek } public float Stardate => _currentStardate; + public float StardatesRemaining => _finalStarDate - _currentStardate; public void DoIntroduction() { @@ -74,7 +75,6 @@ namespace SuperStarTrek _finalStarDate = _initialStardate + random.GetInt(25, 35); _currentQuadrant = random.GetCoordinate(); - _currentSector = random.GetCoordinate(); _galaxy = new Galaxy(); _initialKlingonCount = _galaxy.KlingonCount; @@ -85,7 +85,16 @@ namespace SuperStarTrek .Add(new LongRangeSensors(_galaxy, _output)) .Add(new PhotonTubes(10, _enterprise, _output, _input)) .Add(new ShieldControl(_enterprise, _output, _input)) - .Add(new DamageControl(_enterprise, _output)); + .Add(new DamageControl(_enterprise, _output)) + .Add(new LibraryComputer( + _output, + _input, + new CumulativeGalacticRecord(_output, _galaxy), + new StatusReport(this, _galaxy, _enterprise, _output), + new TorpedoDataCalculator(_enterprise, _output), + new StarbaseDataCalculator(_enterprise, _output), + new DirectionDistanceCalculator(_enterprise, _output, _input), + new GalaxyRegionMap(_output, _galaxy))); _output.Write(Strings.Enterprise); _output.Write( @@ -99,7 +108,7 @@ namespace SuperStarTrek _input.WaitForAnyKeyButEnter("when ready to accept command"); - var quadrant = _galaxy[_currentQuadrant].BuildQuadrant(_enterprise, random, _galaxy); + var quadrant = _galaxy[_currentQuadrant].BuildQuadrant(_enterprise, random, _galaxy, _input, _output); _enterprise.Enter(quadrant, Strings.StartText); } diff --git a/84 Super Star Trek/csharp/Input.cs b/84 Super Star Trek/csharp/Input.cs index c632007f..af17f3c4 100644 --- a/84 Super Star Trek/csharp/Input.cs +++ b/84 Super Star Trek/csharp/Input.cs @@ -44,6 +44,13 @@ namespace SuperStarTrek } } + public (float X, float Y) GetCoordinates(string prompt) + { + _output.Prompt($"{prompt} (X,Y)"); + var responses = ReadNumbers(2); + return (responses[0], responses[1]); + } + public bool TryGetNumber(string prompt, float minValue, float maxValue, out float value) { value = GetNumber($"{prompt} ({minValue}-{maxValue})"); @@ -90,6 +97,46 @@ namespace SuperStarTrek }; } + private float[] ReadNumbers(int quantity) + { + var numbers = new float[quantity]; + var index = 0; + bool tryAgain; + + do + { + tryAgain = false; + var responses = Console.ReadLine().Split(','); + if (responses.Length > quantity) + { + _output.WriteLine("!Extra input ingored"); + } + + for (; index < responses.Length; index++) + { + if (!float.TryParse(responses[index], out numbers[index])) + { + _output.WriteLine("!Number expected - retry input line"); + _output.Prompt(); + tryAgain = true; + break; + } + } + } while (tryAgain); + + if (index < quantity) + { + _output.Prompt("?"); + var responses = ReadNumbers(quantity - index); + for (int i = 0; i < responses.Length; i++, index++) + { + numbers[index] = responses[i]; + } + } + + return numbers; + } + public enum YesNoMode { TrueOnY, diff --git a/84 Super Star Trek/csharp/Objects/Klingon.cs b/84 Super Star Trek/csharp/Objects/Klingon.cs index 29584aec..f722fe06 100644 --- a/84 Super Star Trek/csharp/Objects/Klingon.cs +++ b/84 Super Star Trek/csharp/Objects/Klingon.cs @@ -6,25 +6,27 @@ namespace SuperStarTrek.Objects internal class Klingon { private float _energy; - private Coordinates _sector; private readonly Random _random; public Klingon(Coordinates sector, Random random) { - _sector = sector; + Sector = sector; _random = random; _energy = _random.GetFloat(100, 300); } + public Coordinates Sector { get; private set; } + public override string ToString() => "+K+"; public CommandResult FireOn(Enterprise enterprise) { var attackStrength = _random.GetFloat(); - var hitStrength = (int)(_energy * (2 + attackStrength) / _sector.GetDistanceTo(enterprise.Sector)); + var (_, distanceToEnterprise) = Sector.GetDirectionAndDistanceTo(enterprise.Sector); + var hitStrength = (int)(_energy * (2 + attackStrength) / distanceToEnterprise); _energy /= 3 + attackStrength; - return enterprise.TakeHit(_sector, hitStrength); + return enterprise.TakeHit(Sector, hitStrength); } } } diff --git a/84 Super Star Trek/csharp/Objects/Starbase.cs b/84 Super Star Trek/csharp/Objects/Starbase.cs index 4d854efd..4befa73a 100644 --- a/84 Super Star Trek/csharp/Objects/Starbase.cs +++ b/84 Super Star Trek/csharp/Objects/Starbase.cs @@ -1,4 +1,5 @@ using SuperStarTrek.Resources; +using SuperStarTrek.Space; namespace SuperStarTrek.Objects { @@ -8,13 +9,15 @@ namespace SuperStarTrek.Objects private readonly Output _output; private readonly float _repairDelay; - public Starbase(Random random, Input input, Output output) + public Starbase(Coordinates sector, Random random, Input input, Output output) { + Sector = sector; _repairDelay = random.GetFloat() * 0.5f; _input = input; _output = output; } + internal Coordinates Sector { get; } public override string ToString() => ">!<"; internal bool TryRepair(Enterprise enterprise, out float repairTime) diff --git a/84 Super Star Trek/csharp/Program.cs b/84 Super Star Trek/csharp/Program.cs index 30360ee0..7f8395a6 100644 --- a/84 Super Star Trek/csharp/Program.cs +++ b/84 Super Star Trek/csharp/Program.cs @@ -29,6 +29,7 @@ namespace SuperStarTrek { static void Main() { + var foo = Utils.DirectionAndDistance.From(1,1).To(4,5); var game = new Game(); game.DoIntroduction(); diff --git a/84 Super Star Trek/csharp/Resources/ComputerFunctions.txt b/84 Super Star Trek/csharp/Resources/ComputerFunctions.txt new file mode 100644 index 00000000..4827b0fe --- /dev/null +++ b/84 Super Star Trek/csharp/Resources/ComputerFunctions.txt @@ -0,0 +1,9 @@ + +Functions available from Library-Computer: + 0 = Cumulative galactic record + 1 = Status report + 2 = Photon torpedo data + 3 = Starbase nav data + 4 = Direction/distance calculator + 5 = Galaxy 'region name' map + diff --git a/84 Super Star Trek/csharp/Resources/NoEnemyShips.txt b/84 Super Star Trek/csharp/Resources/NoEnemyShips.txt new file mode 100644 index 00000000..394f1057 --- /dev/null +++ b/84 Super Star Trek/csharp/Resources/NoEnemyShips.txt @@ -0,0 +1,2 @@ +Science Officer Spock reports, 'Sensors show no enemy ships + in this quadrant' \ No newline at end of file diff --git a/84 Super Star Trek/csharp/Resources/NoStarbase.txt b/84 Super Star Trek/csharp/Resources/NoStarbase.txt new file mode 100644 index 00000000..5bb4e5fb --- /dev/null +++ b/84 Super Star Trek/csharp/Resources/NoStarbase.txt @@ -0,0 +1 @@ +Mr. Spock reports, 'Sensors show no starbases in this quadrant.' \ No newline at end of file diff --git a/84 Super Star Trek/csharp/Resources/RegionNames.txt b/84 Super Star Trek/csharp/Resources/RegionNames.txt index e2f47d79..f84fe43b 100644 --- a/84 Super Star Trek/csharp/Resources/RegionNames.txt +++ b/84 Super Star Trek/csharp/Resources/RegionNames.txt @@ -1,8 +1,8 @@ -Antares Sirius -Rigel Deneb -Procyon Capella -Vega Betelgeuse -Canopus Aldebaran -Altair Regulus -Sagittarius Arcturus -Pollux Spica \ No newline at end of file + Antares Sirius + Rigel Deneb + Procyon Capella + Vega Betelgeuse + Canopus Aldebaran + Altair Regulus + Sagittarius Arcturus + Pollux Spica \ No newline at end of file diff --git a/84 Super Star Trek/csharp/Resources/Strings.cs b/84 Super Star Trek/csharp/Resources/Strings.cs index c76fe691..7b315545 100644 --- a/84 Super Star Trek/csharp/Resources/Strings.cs +++ b/84 Super Star Trek/csharp/Resources/Strings.cs @@ -7,6 +7,7 @@ namespace SuperStarTrek.Resources internal static class Strings { public static string CombatArea => GetResource(); + public static string ComputerFunctions => GetResource(); public static string Congratulations => GetResource(); public static string CourtMartial => GetResource(); public static string Destroyed => GetResource(); @@ -14,6 +15,8 @@ namespace SuperStarTrek.Resources public static string Enterprise => GetResource(); public static string Instructions => GetResource(); public static string LowShields => GetResource(); + public static string NoEnemyShips => GetResource(); + public static string NoStarbase => GetResource(); public static string Orders => GetResource(); public static string Protected => GetResource(); public static string RegionNames => GetResource(); diff --git a/84 Super Star Trek/csharp/Space/Coordinate.cs b/84 Super Star Trek/csharp/Space/Coordinate.cs index b103a528..b8660d52 100644 --- a/84 Super Star Trek/csharp/Space/Coordinate.cs +++ b/84 Super Star Trek/csharp/Space/Coordinate.cs @@ -1,4 +1,5 @@ using System; +using SuperStarTrek.Utils; namespace SuperStarTrek.Space { @@ -10,12 +11,15 @@ namespace SuperStarTrek.Space { X = Validated(x, nameof(x)); Y = Validated(y, nameof(y)); + + RegionIndex = (X << 1) + (Y >> 2); + SubRegionIndex = Y % 4; } public int X { get; } public int Y { get; } - public int RegionIndex => (X << 1) + (Y >> 2); - public int SubRegionIndex => Y % 4; + public int RegionIndex { get; } + public int SubRegionIndex { get; } private int Validated(int value, string argumentName) { @@ -51,7 +55,7 @@ namespace SuperStarTrek.Space int Round(float value) => (int)Math.Round(value, MidpointRounding.AwayFromZero); } - internal float GetDistanceTo(Coordinates destination) => - (float)Math.Sqrt(Math.Pow(X - destination.X, 2) + Math.Pow(Y - destination.Y, 2)); + internal (float Direction, float Distance) GetDirectionAndDistanceTo(Coordinates destination) => + DirectionAndDistance.From(this).To(destination); } } diff --git a/84 Super Star Trek/csharp/Space/Galaxy.cs b/84 Super Star Trek/csharp/Space/Galaxy.cs index 0392b335..38382754 100644 --- a/84 Super Star Trek/csharp/Space/Galaxy.cs +++ b/84 Super Star Trek/csharp/Space/Galaxy.cs @@ -48,6 +48,7 @@ namespace SuperStarTrek.Space public int KlingonCount => _quadrants.SelectMany(q => q).Sum(q => q.KlingonCount); public int StarbaseCount => _quadrants.SelectMany(q => q).Count(q => q.HasStarbase); + public IEnumerable> Quadrants => _quadrants; private static string GetQuadrantName(Coordinates coordinates) => $"{_regionNames[coordinates.RegionIndex]} {_subRegionIdentifiers[coordinates.SubRegionIndex]}"; diff --git a/84 Super Star Trek/csharp/Space/Quadrant.cs b/84 Super Star Trek/csharp/Space/Quadrant.cs index d89d60e0..efcaadb2 100644 --- a/84 Super Star Trek/csharp/Space/Quadrant.cs +++ b/84 Super Star Trek/csharp/Space/Quadrant.cs @@ -13,10 +13,15 @@ namespace SuperStarTrek.Space private readonly Random _random; private readonly Dictionary _sectors; private readonly Enterprise _enterprise; - private readonly Coordinates _starbaseSector; private readonly Galaxy _galaxy; - public Quadrant(QuadrantInfo info, Enterprise enterprise, Random random, Galaxy galaxy) + public Quadrant( + QuadrantInfo info, + Enterprise enterprise, + Random random, + Galaxy galaxy, + Input input, + Output output) { _info = info; _random = random; @@ -26,30 +31,30 @@ namespace SuperStarTrek.Space PositionObject(sector => new Klingon(sector, _random), _info.KlingonCount); if (_info.HasStarbase) { - _starbaseSector = PositionObject(_ => new Starbase(_random, new Input(new Output()), new Output())); + Starbase = PositionObject(sector => new Starbase(sector, _random, input, output)); } PositionObject(_ => new Star(), _info.StarCount); } - public object this[Coordinates coordinates] => _sectors.GetValueOrDefault(coordinates); public Coordinates Coordinates => _info.Coordinates; public bool HasKlingons => _info.KlingonCount > 0; + public int KlingonCount => _info.KlingonCount; public bool HasStarbase => _info.HasStarbase; - public Starbase Starbase => HasStarbase ? (Starbase)_sectors[_starbaseSector] : null; + public Starbase Starbase { get; } public bool EnterpriseIsNextToStarbase => _info.HasStarbase && - Math.Abs(_enterprise.Sector.X - _starbaseSector.X) <= 1 && - Math.Abs(_enterprise.Sector.Y - _starbaseSector.Y) <= 1; + Math.Abs(_enterprise.Sector.X - Starbase.Sector.X) <= 1 && + Math.Abs(_enterprise.Sector.Y - Starbase.Sector.Y) <= 1; - private IEnumerable Klingons => _sectors.Values.OfType(); + internal IEnumerable Klingons => _sectors.Values.OfType(); public override string ToString() => _info.Name; - private Coordinates PositionObject(Func objectFactory) + private T PositionObject(Func objectFactory) { var sector = GetRandomEmptySector(); _sectors[sector] = objectFactory.Invoke(sector); - return sector; + return (T)_sectors[sector]; } private void PositionObject(Func objectFactory, int count) diff --git a/84 Super Star Trek/csharp/Space/QuadrantInfo.cs b/84 Super Star Trek/csharp/Space/QuadrantInfo.cs index 04780a27..8b4357db 100644 --- a/84 Super Star Trek/csharp/Space/QuadrantInfo.cs +++ b/84 Super Star Trek/csharp/Space/QuadrantInfo.cs @@ -41,8 +41,11 @@ namespace SuperStarTrek.Space internal void AddStarbase() => HasStarbase = true; - internal Quadrant BuildQuadrant(Enterprise enterprise, Random random, Galaxy galaxy) => - new(this, enterprise, random, galaxy); + internal Quadrant BuildQuadrant(Enterprise enterprise, Random random, Galaxy galaxy, Input input, Output output) + { + _isKnown = true; + return new(this, enterprise, random, galaxy, input, output); + } internal string Scan() { diff --git a/84 Super Star Trek/csharp/StringExtensions.cs b/84 Super Star Trek/csharp/StringExtensions.cs new file mode 100644 index 00000000..02e9794f --- /dev/null +++ b/84 Super Star Trek/csharp/StringExtensions.cs @@ -0,0 +1,7 @@ +namespace SuperStarTrek +{ + internal static class StringExtensions + { + internal static string Pluralize(this string singular, int quantity) => singular + (quantity > 1 ? "s" : ""); + } +} \ No newline at end of file diff --git a/84 Super Star Trek/csharp/Systems/ComputerFunctions/ComputerFunction.cs b/84 Super Star Trek/csharp/Systems/ComputerFunctions/ComputerFunction.cs new file mode 100644 index 00000000..400c1f62 --- /dev/null +++ b/84 Super Star Trek/csharp/Systems/ComputerFunctions/ComputerFunction.cs @@ -0,0 +1,18 @@ +using SuperStarTrek.Space; + +namespace SuperStarTrek.Systems.ComputerFunctions +{ + internal abstract class ComputerFunction + { + protected ComputerFunction(string description, Output output) + { + Description = description; + Output = output; + } + + internal string Description { get; } + protected Output Output { get; } + + internal abstract void Execute(Quadrant quadrant); + } +} \ No newline at end of file diff --git a/84 Super Star Trek/csharp/Systems/ComputerFunctions/CumulativeGalacticRecord.cs b/84 Super Star Trek/csharp/Systems/ComputerFunctions/CumulativeGalacticRecord.cs new file mode 100644 index 00000000..f02677ca --- /dev/null +++ b/84 Super Star Trek/csharp/Systems/ComputerFunctions/CumulativeGalacticRecord.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using SuperStarTrek.Space; + +namespace SuperStarTrek.Systems.ComputerFunctions +{ + internal class CumulativeGalacticRecord : GalacticReport + { + internal CumulativeGalacticRecord(Output output, Galaxy galaxy) + : base("Cumulative galactic record", output, galaxy) + { + } + + protected override void WriteHeader(Quadrant quadrant) => + Output.NextLine().WriteLine($"Computer record of galaxy for quadrant {quadrant.Coordinates}").NextLine(); + + protected override IEnumerable GetRowData() => + Galaxy.Quadrants.Select(row => " " + string.Join(" ", row)); + } +} \ No newline at end of file diff --git a/84 Super Star Trek/csharp/Systems/ComputerFunctions/DirectionDistanceCalculator.cs b/84 Super Star Trek/csharp/Systems/ComputerFunctions/DirectionDistanceCalculator.cs new file mode 100644 index 00000000..c8b195f4 --- /dev/null +++ b/84 Super Star Trek/csharp/Systems/ComputerFunctions/DirectionDistanceCalculator.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using SuperStarTrek.Objects; +using SuperStarTrek.Space; + +namespace SuperStarTrek.Systems.ComputerFunctions +{ + internal class DirectionDistanceCalculator : NavigationCalculator + { + private readonly Enterprise _enterprise; + private readonly Input _input; + + public DirectionDistanceCalculator(Enterprise enterprise, Output output, Input input) + : base("Starbase nav data", output) + { + _enterprise = enterprise; + _input = input; + } + + internal override void Execute(Quadrant quadrant) + { + Output.WriteLine("Direction/distance calculator:") + .WriteLine($"You are at quadrant {_enterprise.Quadrant} sector {_enterprise.Sector}") + .WriteLine("Please enter"); + + WriteDirectionAndDistance( + _input.GetCoordinates(" Initial coordinates"), + _input.GetCoordinates(" Final coordinates")); + } + } +} \ No newline at end of file diff --git a/84 Super Star Trek/csharp/Systems/ComputerFunctions/GalacticReport.cs b/84 Super Star Trek/csharp/Systems/ComputerFunctions/GalacticReport.cs new file mode 100644 index 00000000..8b26cc2e --- /dev/null +++ b/84 Super Star Trek/csharp/Systems/ComputerFunctions/GalacticReport.cs @@ -0,0 +1,34 @@ +using System.Collections.Generic; +using System.Linq; +using SuperStarTrek.Space; + +namespace SuperStarTrek.Systems.ComputerFunctions +{ + internal abstract class GalacticReport : ComputerFunction + { + public GalacticReport(string description, Output output, Galaxy galaxy) + : base(description, output) + { + Galaxy = galaxy; + } + + protected Galaxy Galaxy { get; } + + protected abstract void WriteHeader(Quadrant quadrant); + + protected abstract IEnumerable GetRowData(); + + internal sealed override void Execute(Quadrant quadrant) + { + WriteHeader(quadrant); + Output.WriteLine(" 1 2 3 4 5 6 7 8") + .WriteLine(" ----- ----- ----- ----- ----- ----- ----- -----"); + + foreach (var (row, index) in GetRowData().Select((r, i) => (r, i))) + { + Output.WriteLine($" {index+1} {row}") + .WriteLine(" ----- ----- ----- ----- ----- ----- ----- -----"); + } + } + } +} \ No newline at end of file diff --git a/84 Super Star Trek/csharp/Systems/ComputerFunctions/GalaxyRegionMap.cs b/84 Super Star Trek/csharp/Systems/ComputerFunctions/GalaxyRegionMap.cs new file mode 100644 index 00000000..f6fe0305 --- /dev/null +++ b/84 Super Star Trek/csharp/Systems/ComputerFunctions/GalaxyRegionMap.cs @@ -0,0 +1,21 @@ +using System.Collections.Generic; +using System.Linq; +using SuperStarTrek.Resources; +using SuperStarTrek.Space; + +namespace SuperStarTrek.Systems.ComputerFunctions +{ + internal class GalaxyRegionMap : GalacticReport + { + internal GalaxyRegionMap(Output output, Galaxy galaxy) + : base("Galaxy 'region name' map", output, galaxy) + { + } + + protected override void WriteHeader(Quadrant quadrant) => + Output.WriteLine(" The Galaxy"); + + protected override IEnumerable GetRowData() => + Strings.RegionNames.Split('\n').Select(n => n.TrimEnd('\r')); + } +} \ No newline at end of file diff --git a/84 Super Star Trek/csharp/Systems/ComputerFunctions/NavigationCalculator.cs b/84 Super Star Trek/csharp/Systems/ComputerFunctions/NavigationCalculator.cs new file mode 100644 index 00000000..680f3d18 --- /dev/null +++ b/84 Super Star Trek/csharp/Systems/ComputerFunctions/NavigationCalculator.cs @@ -0,0 +1,29 @@ +using SuperStarTrek.Space; +using SuperStarTrek.Utils; + +namespace SuperStarTrek.Systems.ComputerFunctions +{ + internal abstract class NavigationCalculator : ComputerFunction + { + protected NavigationCalculator(string description, Output output) + : base(description, output) + { + } + + protected void WriteDirectionAndDistance(Coordinates from, Coordinates to) + { + var (direction, distance) = from.GetDirectionAndDistanceTo(to); + Write(direction, distance); + } + + protected void WriteDirectionAndDistance((float X, float Y) from, (float X, float Y) to) + { + var (direction, distance) = DirectionAndDistance.From(from.X, from.Y).To(to.X, to.Y); + Write(direction, distance); + } + + private void Write(float direction, float distance) => + Output.WriteLine($"Direction = {direction}") + .WriteLine($"Distance = {distance}"); + } +} \ No newline at end of file diff --git a/84 Super Star Trek/csharp/Systems/ComputerFunctions/StarbaseDataCalculator.cs b/84 Super Star Trek/csharp/Systems/ComputerFunctions/StarbaseDataCalculator.cs new file mode 100644 index 00000000..b81a353d --- /dev/null +++ b/84 Super Star Trek/csharp/Systems/ComputerFunctions/StarbaseDataCalculator.cs @@ -0,0 +1,30 @@ +using SuperStarTrek.Objects; +using SuperStarTrek.Resources; +using SuperStarTrek.Space; + +namespace SuperStarTrek.Systems.ComputerFunctions +{ + internal class StarbaseDataCalculator : NavigationCalculator + { + private readonly Enterprise _enterprise; + + public StarbaseDataCalculator(Enterprise enterprise, Output output) + : base("Starbase nav data", output) + { + _enterprise = enterprise; + } + + internal override void Execute(Quadrant quadrant) + { + if (!quadrant.HasStarbase) + { + Output.WriteLine(Strings.NoStarbase); + return; + } + + Output.WriteLine("From Enterprise to Starbase:"); + + WriteDirectionAndDistance(_enterprise.Sector, quadrant.Starbase.Sector); + } + } +} \ No newline at end of file diff --git a/84 Super Star Trek/csharp/Systems/ComputerFunctions/StatusReport.cs b/84 Super Star Trek/csharp/Systems/ComputerFunctions/StatusReport.cs new file mode 100644 index 00000000..f80ba7bb --- /dev/null +++ b/84 Super Star Trek/csharp/Systems/ComputerFunctions/StatusReport.cs @@ -0,0 +1,41 @@ +using SuperStarTrek.Commands; +using SuperStarTrek.Objects; +using SuperStarTrek.Space; + +namespace SuperStarTrek.Systems.ComputerFunctions +{ + internal class StatusReport : ComputerFunction + { + private readonly Game _game; + private readonly Galaxy _galaxy; + private readonly Enterprise _enterprise; + + public StatusReport(Game game, Galaxy galaxy, Enterprise enterprise, Output output) + : base("Status report", output) + { + _game = game; + _galaxy = galaxy; + _enterprise = enterprise; + } + + internal override void Execute(Quadrant quadrant) + { + Output.WriteLine(" Status report:") + .Write("Klingon".Pluralize(_galaxy.KlingonCount)).WriteLine($" left: {_galaxy.KlingonCount}") + .WriteLine($"Mission must be completed in {_game.StardatesRemaining:0.#} stardates."); + + if (_galaxy.StarbaseCount > 0) + { + Output.Write($"The Federation is maintaining {_galaxy.StarbaseCount} ") + .Write("starbase".Pluralize(_galaxy.StarbaseCount)).WriteLine(" in the galaxy."); + } + else + { + Output.WriteLine("Your stupidity has left you on your own in") + .WriteLine(" the galaxy -- you have no starbases left!"); + } + + _enterprise.Execute(Command.DAM); + } + } +} \ No newline at end of file diff --git a/84 Super Star Trek/csharp/Systems/ComputerFunctions/TorpedoDataCalculator.cs b/84 Super Star Trek/csharp/Systems/ComputerFunctions/TorpedoDataCalculator.cs new file mode 100644 index 00000000..6afa7b8c --- /dev/null +++ b/84 Super Star Trek/csharp/Systems/ComputerFunctions/TorpedoDataCalculator.cs @@ -0,0 +1,33 @@ +using SuperStarTrek.Objects; +using SuperStarTrek.Resources; +using SuperStarTrek.Space; + +namespace SuperStarTrek.Systems.ComputerFunctions +{ + internal class TorpedoDataCalculator : NavigationCalculator + { + private readonly Enterprise _enterprise; + + public TorpedoDataCalculator(Enterprise enterprise, Output output) + : base("Photon torpedo data", output) + { + _enterprise = enterprise; + } + + internal override void Execute(Quadrant quadrant) + { + if (!quadrant.HasKlingons) + { + Output.WriteLine(Strings.NoEnemyShips); + return; + } + + Output.WriteLine("From Enterprise to Klingon battle cruiser".Pluralize(quadrant.KlingonCount)); + + foreach (var klingon in quadrant.Klingons) + { + WriteDirectionAndDistance(_enterprise.Sector, klingon.Sector); + } + } + } +} \ No newline at end of file diff --git a/84 Super Star Trek/csharp/Systems/DamageControl.cs b/84 Super Star Trek/csharp/Systems/DamageControl.cs index 25f5ad78..6ce41bbe 100644 --- a/84 Super Star Trek/csharp/Systems/DamageControl.cs +++ b/84 Super Star Trek/csharp/Systems/DamageControl.cs @@ -24,6 +24,7 @@ namespace SuperStarTrek.Systems } else { + _output.NextLine(); WriteDamageReport(); } @@ -41,7 +42,7 @@ namespace SuperStarTrek.Systems public void WriteDamageReport() { - _output.NextLine().NextLine().WriteLine("Device State of Repair"); + _output.NextLine().WriteLine("Device State of Repair"); foreach (var system in _enterprise.Systems) { _output.Write(system.Name.PadRight(25)) diff --git a/84 Super Star Trek/csharp/Systems/LibraryComputer.cs b/84 Super Star Trek/csharp/Systems/LibraryComputer.cs new file mode 100644 index 00000000..b2e47d2a --- /dev/null +++ b/84 Super Star Trek/csharp/Systems/LibraryComputer.cs @@ -0,0 +1,47 @@ +using SuperStarTrek.Commands; +using SuperStarTrek.Space; +using SuperStarTrek.Systems.ComputerFunctions; + +namespace SuperStarTrek.Systems +{ + internal class LibraryComputer : Subsystem + { + private readonly Output _output; + private readonly Input _input; + private readonly ComputerFunction[] _functions; + + public LibraryComputer(Output output, Input input, params ComputerFunction[] functions) + : base("Library-Computer", Command.COM, output) + { + _output = output; + _input = input; + _functions = functions; + } + + protected override bool CanExecuteCommand() => IsOperational("Computer disabled"); + + protected override CommandResult ExecuteCommandCore(Quadrant quadrant) + { + var index = GetFunctionIndex(); + _output.NextLine(); + + _functions[index].Execute(quadrant); + + return CommandResult.Ok; + } + + private int GetFunctionIndex() + { + while (true) + { + var index = (int)_input.GetNumber("Computer active and waiting command"); + if (index >= 0 && index <= 5) { return index; } + + for (int i = 0; i < _functions.Length; i++) + { + _output.WriteLine($" {i} = {_functions[i].Description}"); + } + } + } + } +} diff --git a/84 Super Star Trek/csharp/Utils/DirectionAndDistance.cs b/84 Super Star Trek/csharp/Utils/DirectionAndDistance.cs new file mode 100644 index 00000000..3fa9f4b8 --- /dev/null +++ b/84 Super Star Trek/csharp/Utils/DirectionAndDistance.cs @@ -0,0 +1,65 @@ +using System; +using SuperStarTrek.Space; + +namespace SuperStarTrek.Utils +{ + internal class DirectionAndDistance + { + private readonly float _fromX; + private readonly float _fromY; + + private DirectionAndDistance(float fromX, float fromY) + { + _fromX = fromX; + _fromY = fromY; + } + + public static DirectionAndDistance From(Coordinates coordinates) => From(coordinates.X, coordinates.Y); + + public static DirectionAndDistance From(float x, float y) => new DirectionAndDistance(x, y); + + public (float Direction, float Distance) To(Coordinates coordinates) => To(coordinates.X, coordinates.Y); + + public (float Direction, float Distance) To(float x, float y) + { + var deltaX = x - _fromX; + var deltaY = y - _fromY; + + return (GetDirection(deltaX, deltaY), GetDistance(deltaX, deltaY)); + } + + // The algorithm here is mathematically equivalent to the following code in the original, + // where X is deltaY and A is deltaX + // 8220 X=X-A:A=C1-W1:IFX<0THEN8350 + // 8250 IFA<0THEN8410 + // 8260 IFX>0THEN8280 + // 8270 IFA=0THENC1=5:GOTO8290 + // 8280 C1=1 + // 8290 IFABS(A)<=ABS(X)THEN8330 + // 8310 PRINT"DIRECTION =";C1+(((ABS(A)-ABS(X))+ABS(A))/ABS(A)):GOTO8460 + // 8330 PRINT"DIRECTION =";C1+(ABS(A)/ABS(X)):GOTO8460 + // 8350 IFA>0THENC1=3:GOTO8420 + // 8360 IFX<>0THENC1=5:GOTO8290 + // 8410 C1=7 + // 8420 IFABS(A)>=ABS(X)THEN8450 + // 8430 PRINT"DIRECTION =";C1+(((ABS(X)-ABS(A))+ABS(X))/ABS(X)):GOTO8460 + // 8450 PRINT"DIRECTION =";C1+(ABS(X)/ABS(A)) + // 8460 PRINT"DISTANCE =";SQR(X^2+A^2):IFH8=1THEN1990 + private float GetDirection(float deltaX, float deltaY) + { + var deltaXDominant = Math.Abs(deltaX) > Math.Abs(deltaY); + var fractionalPart = deltaXDominant ? deltaY / deltaX : -deltaX / deltaY; + var nearestCardinal = deltaXDominant switch + { + true => deltaX > 0 ? 7 : 3, + false => deltaY > 0 ? 1 : 5 + }; + + var direction = nearestCardinal + fractionalPart; + return direction < 1 ? direction + 8 : direction; + } + + private float GetDistance(float deltaX, float deltaY) => + (float)Math.Sqrt(Math.Pow(deltaX, 2) + Math.Pow(deltaY, 2)); + } +} \ No newline at end of file From 4b352db8ef72e1c8e76204639c8b43995b9e7ca3 Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Thu, 11 Mar 2021 12:13:02 +1100 Subject: [PATCH 09/15] Add Phaser Control --- 84 Super Star Trek/csharp/Game.cs | 1 + .../csharp/Objects/Enterprise.cs | 1 + 84 Super Star Trek/csharp/Objects/Klingon.cs | 18 +++- 84 Super Star Trek/csharp/Space/Coordinate.cs | 6 ++ 84 Super Star Trek/csharp/Space/Quadrant.cs | 13 ++- .../csharp/Systems/PhaserControl.cs | 95 +++++++++++++++++++ 6 files changed, 125 insertions(+), 9 deletions(-) create mode 100644 84 Super Star Trek/csharp/Systems/PhaserControl.cs diff --git a/84 Super Star Trek/csharp/Game.cs b/84 Super Star Trek/csharp/Game.cs index e32f15c8..de3c2c4c 100644 --- a/84 Super Star Trek/csharp/Game.cs +++ b/84 Super Star Trek/csharp/Game.cs @@ -83,6 +83,7 @@ namespace SuperStarTrek _enterprise .Add(new ShortRangeSensors(_enterprise, _galaxy, this, _output)) .Add(new LongRangeSensors(_galaxy, _output)) + .Add(new PhaserControl(_enterprise, _output, _input, random)) .Add(new PhotonTubes(10, _enterprise, _output, _input)) .Add(new ShieldControl(_enterprise, _output, _input)) .Add(new DamageControl(_enterprise, _output)) diff --git a/84 Super Star Trek/csharp/Objects/Enterprise.cs b/84 Super Star Trek/csharp/Objects/Enterprise.cs index ed11bb1e..d87a3aec 100644 --- a/84 Super Star Trek/csharp/Objects/Enterprise.cs +++ b/84 Super Star Trek/csharp/Objects/Enterprise.cs @@ -32,6 +32,7 @@ namespace SuperStarTrek.Objects public Coordinates Quadrant => _quadrant.Coordinates; public Coordinates Sector { get; } public string Condition => GetCondition(); + public LibraryComputer Computer => (LibraryComputer)_commandExecutors[Command.COM]; public ShieldControl ShieldControl => (ShieldControl)_commandExecutors[Command.SHE]; public float Energy => TotalEnergy - ShieldControl.ShieldEnergy; public float TotalEnergy { get; private set; } diff --git a/84 Super Star Trek/csharp/Objects/Klingon.cs b/84 Super Star Trek/csharp/Objects/Klingon.cs index f722fe06..d16c6792 100644 --- a/84 Super Star Trek/csharp/Objects/Klingon.cs +++ b/84 Super Star Trek/csharp/Objects/Klingon.cs @@ -5,16 +5,16 @@ namespace SuperStarTrek.Objects { internal class Klingon { - private float _energy; private readonly Random _random; public Klingon(Coordinates sector, Random random) { Sector = sector; _random = random; - _energy = _random.GetFloat(100, 300); + Energy = _random.GetFloat(100, 300); } + public float Energy { get; private set; } public Coordinates Sector { get; private set; } public override string ToString() => "+K+"; @@ -22,11 +22,19 @@ namespace SuperStarTrek.Objects public CommandResult FireOn(Enterprise enterprise) { var attackStrength = _random.GetFloat(); - var (_, distanceToEnterprise) = Sector.GetDirectionAndDistanceTo(enterprise.Sector); - var hitStrength = (int)(_energy * (2 + attackStrength) / distanceToEnterprise); - _energy /= 3 + attackStrength; + var distanceToEnterprise = Sector.GetDistanceTo(enterprise.Sector); + var hitStrength = (int)(Energy * (2 + attackStrength) / distanceToEnterprise); + Energy /= 3 + attackStrength; return enterprise.TakeHit(Sector, hitStrength); } + + internal bool TakeHit(int hitStrength) + { + if (hitStrength < 0.15 * Energy) { return false; } + + Energy -= hitStrength; + return true; + } } } diff --git a/84 Super Star Trek/csharp/Space/Coordinate.cs b/84 Super Star Trek/csharp/Space/Coordinate.cs index b8660d52..759ca45e 100644 --- a/84 Super Star Trek/csharp/Space/Coordinate.cs +++ b/84 Super Star Trek/csharp/Space/Coordinate.cs @@ -57,5 +57,11 @@ namespace SuperStarTrek.Space internal (float Direction, float Distance) GetDirectionAndDistanceTo(Coordinates destination) => DirectionAndDistance.From(this).To(destination); + + internal float GetDistanceTo(Coordinates destination) + { + var (_, distance) = GetDirectionAndDistanceTo(destination); + return distance; + } } } diff --git a/84 Super Star Trek/csharp/Space/Quadrant.cs b/84 Super Star Trek/csharp/Space/Quadrant.cs index efcaadb2..8d9d0556 100644 --- a/84 Super Star Trek/csharp/Space/Quadrant.cs +++ b/84 Super Star Trek/csharp/Space/Quadrant.cs @@ -72,10 +72,8 @@ namespace SuperStarTrek.Space switch (_sectors.GetValueOrDefault(coordinates)) { - case Klingon _: - _sectors.Remove(coordinates); - _info.RemoveKlingon(); - message = "*** Klingon destroyed ***"; + case Klingon klingon: + message = Remove(klingon); gameOver = _galaxy.KlingonCount == 0; return true; @@ -96,6 +94,13 @@ namespace SuperStarTrek.Space } } + internal string Remove(Klingon klingon) + { + _sectors.Remove(klingon.Sector); + _info.RemoveKlingon(); + return "*** Klingon destroyed ***"; + } + internal CommandResult KlingonsFireOnEnterprise() { if (EnterpriseIsNextToStarbase && Klingons.Any()) diff --git a/84 Super Star Trek/csharp/Systems/PhaserControl.cs b/84 Super Star Trek/csharp/Systems/PhaserControl.cs new file mode 100644 index 00000000..48da4ace --- /dev/null +++ b/84 Super Star Trek/csharp/Systems/PhaserControl.cs @@ -0,0 +1,95 @@ +using System.Linq; +using SuperStarTrek.Commands; +using SuperStarTrek.Objects; +using SuperStarTrek.Resources; +using SuperStarTrek.Space; + +namespace SuperStarTrek.Systems +{ + internal class PhaserControl : Subsystem + { + private readonly Enterprise _enterprise; + private readonly Output _output; + private readonly Input _input; + private readonly Random _random; + + public PhaserControl(Enterprise enterprise, Output output, Input input, Random random) + : base("Phaser Control", Command.PHA, output) + { + _enterprise = enterprise; + _output = output; + _input = input; + _random = random; + } + + protected override bool CanExecuteCommand() => IsOperational("Phasers inoperative"); + + protected override CommandResult ExecuteCommandCore(Quadrant quadrant) + { + if (!quadrant.HasKlingons) + { + _output.WriteLine(Strings.NoEnemyShips); + return CommandResult.Ok; + } + + if (_enterprise.Computer.IsDamaged) + { + _output.WriteLine("Computer failure hampers accuracy"); + } + + _output.Write($"Phasers locked on target; "); + + var phaserStrength = GetPhaserStrength(); + if (phaserStrength < 0) { return CommandResult.Ok; } + + var perEnemyStrength = GetPerTargetPhaserStrength(phaserStrength, quadrant.KlingonCount); + + foreach (var klingon in quadrant.Klingons.ToList()) + { + ResolveHitOn(klingon, perEnemyStrength, quadrant); + } + + return quadrant.KlingonsFireOnEnterprise(); + } + + private float GetPhaserStrength() + { + while (true) + { + _output.WriteLine($"Energy available = {_enterprise.Energy} units"); + var phaserStrength = _input.GetNumber("Number of units to fire"); + + if (phaserStrength <= _enterprise.Energy) { return phaserStrength; } + } + } + + private float GetPerTargetPhaserStrength(float phaserStrength, int targetCount) + { + if (_enterprise.Computer.IsDamaged) + { + phaserStrength *= _random.GetFloat(); + } + + return phaserStrength / targetCount; + } + + private void ResolveHitOn(Klingon klingon, float perEnemyStrength, Quadrant quadrant) + { + var distance = _enterprise.Sector.GetDistanceTo(klingon.Sector); + var hitStrength = (int)(perEnemyStrength / distance * (2 + _random.GetFloat())); + + if (klingon.TakeHit(hitStrength)) + { + _output.WriteLine($"{hitStrength} unit hit on Klingon at sector {klingon.Sector}"); + _output.WriteLine( + klingon.Energy <= 0 + ? quadrant.Remove(klingon) + : $" (sensors show {klingon.Energy} units remaining)"); + } + else + { + _output.WriteLine($"Sensors show no damage to enemy at {klingon.Sector}"); + } + } + } +} From 835ee3546481a21904fae9ecccbdcc7d448e1ed8 Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Sun, 21 Mar 2021 12:39:19 +1100 Subject: [PATCH 10/15] Add Warp Engines --- 84 Super Star Trek/csharp/Game.cs | 27 ++-- 84 Super Star Trek/csharp/Input.cs | 15 ++- .../csharp/Objects/Enterprise.cs | 120 +++++++++++++++--- 84 Super Star Trek/csharp/Objects/Klingon.cs | 4 +- .../csharp/Resources/NowEntering.txt | 2 + .../csharp/Resources/PermissionDenied.txt | 5 + .../csharp/Resources/Strings.cs | 2 + .../Space/{Coordinate.cs => Coordinates.cs} | 2 +- 84 Super Star Trek/csharp/Space/Course.cs | 36 +++++- 84 Super Star Trek/csharp/Space/Galaxy.cs | 6 +- 84 Super Star Trek/csharp/Space/Quadrant.cs | 52 ++++++-- .../csharp/Space/QuadrantInfo.cs | 6 +- .../DirectionDistanceCalculator.cs | 3 +- .../StarbaseDataCalculator.cs | 2 +- .../TorpedoDataCalculator.cs | 2 +- .../csharp/Systems/PhaserControl.cs | 2 +- .../csharp/Systems/PhotonTubes.cs | 5 +- .../csharp/Systems/ShortRangeSensors.cs | 4 +- .../csharp/Systems/Subsystem.cs | 21 ++- .../csharp/Systems/WarpEngines.cs | 75 +++++++++++ 20 files changed, 330 insertions(+), 61 deletions(-) create mode 100644 84 Super Star Trek/csharp/Resources/NowEntering.txt create mode 100644 84 Super Star Trek/csharp/Resources/PermissionDenied.txt rename 84 Super Star Trek/csharp/Space/{Coordinate.cs => Coordinates.cs} (95%) create mode 100644 84 Super Star Trek/csharp/Systems/WarpEngines.cs diff --git a/84 Super Star Trek/csharp/Game.cs b/84 Super Star Trek/csharp/Game.cs index de3c2c4c..f2e1c819 100644 --- a/84 Super Star Trek/csharp/Game.cs +++ b/84 Super Star Trek/csharp/Game.cs @@ -12,6 +12,7 @@ namespace SuperStarTrek { private readonly Output _output; private readonly Input _input; + private readonly Random _random; private int _initialStardate; private int _finalStarDate; @@ -25,6 +26,7 @@ namespace SuperStarTrek { _output = new Output(); _input = new Input(_output); + _random = new Random(); } public float Stardate => _currentStardate; @@ -46,15 +48,19 @@ namespace SuperStarTrek { Initialise(); var gameOver = false; + var newQuadrantText = Strings.StartText; while (!gameOver) { + _enterprise.Quadrant.Display(Strings.NowEntering); + var command = _input.GetCommand(); var result = _enterprise.Execute(command); gameOver = result.IsGameOver || CheckIfStranded(); _currentStardate += result.TimeElapsed; + gameOver |= _currentStardate > _finalStarDate; } if (_galaxy.KlingonCount > 0) @@ -69,21 +75,20 @@ namespace SuperStarTrek private void Initialise() { - var random = new Random(); + _currentStardate = _initialStardate = _random.GetInt(20, 40) * 100; + _finalStarDate = _initialStardate + _random.GetInt(25, 35); - _currentStardate = _initialStardate = random.GetInt(20, 40) * 100; - _finalStarDate = _initialStardate + random.GetInt(25, 35); + _currentQuadrant = _random.GetCoordinate(); - _currentQuadrant = random.GetCoordinate(); - - _galaxy = new Galaxy(); + _galaxy = new Galaxy(_random); _initialKlingonCount = _galaxy.KlingonCount; - _enterprise = new Enterprise(3000, random.GetCoordinate(), _output, random); + _enterprise = new Enterprise(3000, _random.GetCoordinate(), _output, _random, _input); _enterprise + .Add(new WarpEngines(_enterprise, _output, _input)) .Add(new ShortRangeSensors(_enterprise, _galaxy, this, _output)) .Add(new LongRangeSensors(_galaxy, _output)) - .Add(new PhaserControl(_enterprise, _output, _input, random)) + .Add(new PhaserControl(_enterprise, _output, _input, _random)) .Add(new PhotonTubes(10, _enterprise, _output, _input)) .Add(new ShieldControl(_enterprise, _output, _input)) .Add(new DamageControl(_enterprise, _output)) @@ -109,10 +114,12 @@ namespace SuperStarTrek _input.WaitForAnyKeyButEnter("when ready to accept command"); - var quadrant = _galaxy[_currentQuadrant].BuildQuadrant(_enterprise, random, _galaxy, _input, _output); - _enterprise.Enter(quadrant, Strings.StartText); + _enterprise.StartIn(BuildCurrentQuadrant()); } + private Quadrant BuildCurrentQuadrant() => + new Quadrant(_galaxy[_currentQuadrant], _enterprise, _random, _galaxy, _input, _output); + public bool Replay() => _galaxy.StarbaseCount > 0 && _input.GetString(Strings.ReplayPrompt, "Aye"); private bool CheckIfStranded() diff --git a/84 Super Star Trek/csharp/Input.cs b/84 Super Star Trek/csharp/Input.cs index af17f3c4..3011738b 100644 --- a/84 Super Star Trek/csharp/Input.cs +++ b/84 Super Star Trek/csharp/Input.cs @@ -1,7 +1,7 @@ using System; using System.Linq; using SuperStarTrek.Commands; - +using SuperStarTrek.Space; using static System.StringComparison; namespace SuperStarTrek @@ -82,6 +82,19 @@ namespace SuperStarTrek } } + public bool TryGetCourse(string prompt, string officer, out Course course) + { + if (!TryGetNumber(prompt, 1, 9, out var direction)) + { + _output.WriteLine($"{officer} reports, 'Incorrect course data, sir!'"); + course = default; + return false; + } + + course = new Course(direction); + return true; + } + public bool GetYesNo(string prompt, YesNoMode mode) { _output.Prompt($"{prompt} (Y/N)"); diff --git a/84 Super Star Trek/csharp/Objects/Enterprise.cs b/84 Super Star Trek/csharp/Objects/Enterprise.cs index d87a3aec..004ce893 100644 --- a/84 Super Star Trek/csharp/Objects/Enterprise.cs +++ b/84 Super Star Trek/csharp/Objects/Enterprise.cs @@ -16,21 +16,25 @@ namespace SuperStarTrek.Objects private readonly List _systems; private readonly Dictionary _commandExecutors; private readonly Random _random; + private readonly Input _input; private Quadrant _quadrant; - public Enterprise(int maxEnergy, Coordinates sector, Output output, Random random) + public Enterprise(int maxEnergy, Coordinates sector, Output output, Random random, Input input) { - Sector = sector; + SectorCoordinates = sector; TotalEnergy = _maxEnergy = maxEnergy; _systems = new List(); _commandExecutors = new Dictionary(); _output = output; _random = random; + _input = input; } - public Coordinates Quadrant => _quadrant.Coordinates; - public Coordinates Sector { get; } + public Quadrant Quadrant => _quadrant; + public Coordinates QuadrantCoordinates => _quadrant.Coordinates; + public Coordinates SectorCoordinates { get; private set; } + public string Condition => GetCondition(); public LibraryComputer Computer => (LibraryComputer)_commandExecutors[Command.COM]; public ShieldControl ShieldControl => (ShieldControl)_commandExecutors[Command.SHE]; @@ -50,19 +54,10 @@ namespace SuperStarTrek.Objects return this; } - public void Enter(Quadrant quadrant, string entryTextFormat) + public void StartIn(Quadrant quadrant) { _quadrant = quadrant; - - _output.Write(entryTextFormat, quadrant); - - if (quadrant.HasKlingons) - { - _output.Write(Strings.CombatArea); - if (ShieldControl.ShieldEnergy <= 200) { _output.Write(Strings.LowShields); } - } - - Execute(Command.SRS); + quadrant.Display(Strings.StartText); } private string GetCondition() => @@ -121,7 +116,100 @@ namespace SuperStarTrek.Objects return; } - _systems[_random.Get1To8Inclusive() - 1].TakeDamage(hitShieldRatio + 0.5f * _random.GetFloat()); + var system = _systems[_random.Get1To8Inclusive() - 1]; + system.TakeDamage(hitShieldRatio + 0.5f * _random.GetFloat()); + _output.WriteLine($"Damage Control reports, '{system.Name} damaged by the hit.'"); } + + internal void RepairSystems(float repairWorkDone) + { + var repairedSystems = new List(); + + foreach (var system in _systems.Where(s => s.IsDamaged)) + { + if (system.Repair(repairWorkDone)) + { + repairedSystems.Add(system.Name); + } + } + + if (repairedSystems.Any()) + { + _output.WriteLine("Damage Control report:"); + foreach (var systemName in repairedSystems) + { + _output.WriteLine($" {systemName} repair completed."); + } + } + } + + internal void VaryConditionOfRandomSystem() + { + if (_random.GetFloat() > 0.2f) { return; } + + var system = _systems[_random.Get1To8Inclusive() - 1]; + _output.Write($"Damage Control report: {system.Name} "); + if (_random.GetFloat() >= 0.6) + { + system.Repair(_random.GetFloat() * 3 + 1); + _output.WriteLine("state of repair improved"); + } + else + { + system.TakeDamage(_random.GetFloat() * 5 + 1); + _output.WriteLine("damaged"); + } + } + + internal float Move(Course course, float warpFactor, int distance) + { + var (quadrant, sector) = MoveWithinQuadrant(course, distance) ?? MoveBeyondQuadrant(course, distance); + + if (quadrant != _quadrant.Coordinates) + { + _quadrant = new Quadrant(_quadrant.Galaxy[quadrant], this, _random, _quadrant.Galaxy, _input, _output); + } + SectorCoordinates = sector; + + return GetTimeElapsed(quadrant, warpFactor); + } + + private (Coordinates, Coordinates)? MoveWithinQuadrant(Course course, int distance) + { + var currentSector = SectorCoordinates; + foreach (var (sector, index) in course.GetSectorsFrom(SectorCoordinates).Select((s, i) => (s, i))) + { + if (distance == 0) { break; } + + if (_quadrant.HasObjectAt(sector)) + { + _output.WriteLine($"Warp engines shut down at sector {currentSector} dues to bad navigation"); + distance = 0; + break; + } + + currentSector = sector; + distance -= 1; + } + + return distance == 0 ? (_quadrant.Coordinates, currentSector) : null; + } + + private (Coordinates, Coordinates) MoveBeyondQuadrant(Course course, int distance) + { + var (complete, quadrant, sector) = course.GetDestination(QuadrantCoordinates, SectorCoordinates, distance); + + if (!complete) + { + _output.Write(Strings.PermissionDenied, sector, quadrant); + } + + return (quadrant, sector); + } + + private float GetTimeElapsed(Coordinates finalQuadrant, float warpFactor) => + finalQuadrant == _quadrant.Coordinates + ? Math.Min(1, (float)Math.Round(warpFactor, 1, MidpointRounding.ToZero)) + : 1; } } diff --git a/84 Super Star Trek/csharp/Objects/Klingon.cs b/84 Super Star Trek/csharp/Objects/Klingon.cs index d16c6792..4e277b07 100644 --- a/84 Super Star Trek/csharp/Objects/Klingon.cs +++ b/84 Super Star Trek/csharp/Objects/Klingon.cs @@ -22,7 +22,7 @@ namespace SuperStarTrek.Objects public CommandResult FireOn(Enterprise enterprise) { var attackStrength = _random.GetFloat(); - var distanceToEnterprise = Sector.GetDistanceTo(enterprise.Sector); + var distanceToEnterprise = Sector.GetDistanceTo(enterprise.SectorCoordinates); var hitStrength = (int)(Energy * (2 + attackStrength) / distanceToEnterprise); Energy /= 3 + attackStrength; @@ -36,5 +36,7 @@ namespace SuperStarTrek.Objects Energy -= hitStrength; return true; } + + internal void MoveTo(Coordinates newSector) => Sector = newSector; } } diff --git a/84 Super Star Trek/csharp/Resources/NowEntering.txt b/84 Super Star Trek/csharp/Resources/NowEntering.txt new file mode 100644 index 00000000..915b526f --- /dev/null +++ b/84 Super Star Trek/csharp/Resources/NowEntering.txt @@ -0,0 +1,2 @@ +Now entering {0} quadrant . . . + diff --git a/84 Super Star Trek/csharp/Resources/PermissionDenied.txt b/84 Super Star Trek/csharp/Resources/PermissionDenied.txt new file mode 100644 index 00000000..c24d9da7 --- /dev/null +++ b/84 Super Star Trek/csharp/Resources/PermissionDenied.txt @@ -0,0 +1,5 @@ +Lt. Uhura report message from Starfleet Command: + 'Permission to attempt crossing of galactic perimeter + is hereby *Denied*. Shut down your engines.' +Chief Engineer Scott reports, 'Warp engines shut down + at sector {0} of quadrant {1}.' diff --git a/84 Super Star Trek/csharp/Resources/Strings.cs b/84 Super Star Trek/csharp/Resources/Strings.cs index 7b315545..ddb768ca 100644 --- a/84 Super Star Trek/csharp/Resources/Strings.cs +++ b/84 Super Star Trek/csharp/Resources/Strings.cs @@ -17,7 +17,9 @@ namespace SuperStarTrek.Resources public static string LowShields => GetResource(); public static string NoEnemyShips => GetResource(); public static string NoStarbase => GetResource(); + public static string NowEntering => GetResource(); public static string Orders => GetResource(); + public static string PermissionDenied => GetResource(); public static string Protected => GetResource(); public static string RegionNames => GetResource(); public static string RelievedOfCommand => GetResource(); diff --git a/84 Super Star Trek/csharp/Space/Coordinate.cs b/84 Super Star Trek/csharp/Space/Coordinates.cs similarity index 95% rename from 84 Super Star Trek/csharp/Space/Coordinate.cs rename to 84 Super Star Trek/csharp/Space/Coordinates.cs index 759ca45e..1619d387 100644 --- a/84 Super Star Trek/csharp/Space/Coordinate.cs +++ b/84 Super Star Trek/csharp/Space/Coordinates.cs @@ -52,7 +52,7 @@ namespace SuperStarTrek.Space coordinates = default; return false; - int Round(float value) => (int)Math.Round(value, MidpointRounding.AwayFromZero); + static int Round(float value) => (int)Math.Round(value, MidpointRounding.AwayFromZero); } internal (float Direction, float Distance) GetDirectionAndDistanceTo(Coordinates destination) => diff --git a/84 Super Star Trek/csharp/Space/Course.cs b/84 Super Star Trek/csharp/Space/Course.cs index 40bf4bb2..a46385c3 100644 --- a/84 Super Star Trek/csharp/Space/Course.cs +++ b/84 Super Star Trek/csharp/Space/Course.cs @@ -25,7 +25,7 @@ namespace SuperStarTrek.Space (0, 1) }; - public Course(float direction) + internal Course(float direction) { if (direction < 1 || direction > 9) { @@ -45,10 +45,10 @@ namespace SuperStarTrek.Space DeltaY = baseCardinal.DeltaY + (nextCardinal.DeltaY - baseCardinal.DeltaY) * fractionalDirection; } - public float DeltaX { get; } - public float DeltaY { get; } + internal float DeltaX { get; } + internal float DeltaY { get; } - public IEnumerable GetSectorsFrom(Coordinates start) + internal IEnumerable GetSectorsFrom(Coordinates start) { (float x, float y) = start; @@ -65,5 +65,33 @@ namespace SuperStarTrek.Space yield return coordinates; } } + + internal (bool, Coordinates, Coordinates) GetDestination(Coordinates quadrant, Coordinates sector, int distance) + { + var (xComplete, quadrantX, sectorX) = GetNewCoordinate(quadrant.X, sector.X, DeltaX * distance); + var (yComplete, quadrantY, sectorY) = GetNewCoordinate(quadrant.Y, sector.Y, DeltaY * distance); + + return (xComplete && yComplete, new Coordinates(quadrantX, quadrantY), new Coordinates(sectorX, sectorY)); + } + + private (bool, int, int) GetNewCoordinate(int quadrant, int sector, float sectorsTravelled) + { + var galacticCoordinate = quadrant * 8 + sector + sectorsTravelled; + var newQuadrant = (int)(galacticCoordinate / 8); + var newSector = (int)(galacticCoordinate - newQuadrant * 8); + + if (newSector == -1) + { + newQuadrant -= 1; + newSector = 7; + } + + return newQuadrant switch + { + < 0 => (false, 0, 0), + > 7 => (false, 7, 7), + _ => (true, newQuadrant, newSector) + }; + } } } diff --git a/84 Super Star Trek/csharp/Space/Galaxy.cs b/84 Super Star Trek/csharp/Space/Galaxy.cs index 38382754..63838567 100644 --- a/84 Super Star Trek/csharp/Space/Galaxy.cs +++ b/84 Super Star Trek/csharp/Space/Galaxy.cs @@ -1,6 +1,7 @@ using System.Collections; using System.Collections.Generic; using System.Linq; +using SuperStarTrek.Objects; using SuperStarTrek.Resources; using static System.StringSplitOptions; @@ -12,6 +13,7 @@ namespace SuperStarTrek.Space private static readonly string[] _regionNames; private static readonly string[] _subRegionIdentifiers; private readonly QuadrantInfo[][] _quadrants; + private readonly Random _random; static Galaxy() { @@ -19,9 +21,9 @@ namespace SuperStarTrek.Space _subRegionIdentifiers = new[] { "I", "II", "III", "IV" }; } - public Galaxy() + public Galaxy(Random random) { - var random = new Random(); + _random = random; _quadrants = Enumerable .Range(0, 8) diff --git a/84 Super Star Trek/csharp/Space/Quadrant.cs b/84 Super Star Trek/csharp/Space/Quadrant.cs index 8d9d0556..50c577e2 100644 --- a/84 Super Star Trek/csharp/Space/Quadrant.cs +++ b/84 Super Star Trek/csharp/Space/Quadrant.cs @@ -13,7 +13,8 @@ namespace SuperStarTrek.Space private readonly Random _random; private readonly Dictionary _sectors; private readonly Enterprise _enterprise; - private readonly Galaxy _galaxy; + private readonly Output _output; + private bool _displayed = false; public Quadrant( QuadrantInfo info, @@ -25,9 +26,11 @@ namespace SuperStarTrek.Space { _info = info; _random = random; - _galaxy = galaxy; + _output = output; + Galaxy = galaxy; - _sectors = new() { [enterprise.Sector] = _enterprise = enterprise }; + info.MarkAsKnown(); + _sectors = new() { [enterprise.SectorCoordinates] = _enterprise = enterprise }; PositionObject(sector => new Klingon(sector, _random), _info.KlingonCount); if (_info.HasStarbase) { @@ -41,10 +44,11 @@ namespace SuperStarTrek.Space public int KlingonCount => _info.KlingonCount; public bool HasStarbase => _info.HasStarbase; public Starbase Starbase { get; } + internal Galaxy Galaxy { get; } public bool EnterpriseIsNextToStarbase => _info.HasStarbase && - Math.Abs(_enterprise.Sector.X - Starbase.Sector.X) <= 1 && - Math.Abs(_enterprise.Sector.Y - Starbase.Sector.Y) <= 1; + Math.Abs(_enterprise.SectorCoordinates.X - Starbase.Sector.X) <= 1 && + Math.Abs(_enterprise.SectorCoordinates.Y - Starbase.Sector.Y) <= 1; internal IEnumerable Klingons => _sectors.Values.OfType(); @@ -65,6 +69,25 @@ namespace SuperStarTrek.Space } } + internal void Display(string textFormat) + { + if (_displayed) { return; } + + _output.Write(textFormat, this); + + if (_info.KlingonCount > 0) + { + _output.Write(Strings.CombatArea); + if (_enterprise.ShieldControl.ShieldEnergy <= 200) { _output.Write(Strings.LowShields); } + } + + _enterprise.Execute(Command.SRS); + + _displayed = true; + } + + internal bool HasObjectAt(Coordinates coordinates) => _sectors.ContainsKey(coordinates); + internal bool TorpedoCollisionAt(Coordinates coordinates, out string message, out bool gameOver) { gameOver = false; @@ -74,7 +97,7 @@ namespace SuperStarTrek.Space { case Klingon klingon: message = Remove(klingon); - gameOver = _galaxy.KlingonCount == 0; + gameOver = Galaxy.KlingonCount == 0; return true; case Star _: @@ -85,8 +108,8 @@ namespace SuperStarTrek.Space _sectors.Remove(coordinates); _info.RemoveStarbase(); message = "*** Starbase destroyed ***" + - (_galaxy.StarbaseCount > 0 ? Strings.CourtMartial : Strings.RelievedOfCommand); - gameOver = _galaxy.StarbaseCount == 0; + (Galaxy.StarbaseCount > 0 ? Strings.CourtMartial : Strings.RelievedOfCommand); + gameOver = Galaxy.StarbaseCount == 0; return true; default: @@ -101,6 +124,19 @@ namespace SuperStarTrek.Space return "*** Klingon destroyed ***"; } + internal CommandResult KlingonsMoveAndFire() + { + foreach (var klingon in Klingons.ToList()) + { + var newSector = GetRandomEmptySector(); + _sectors.Remove(klingon.Sector); + _sectors[newSector] = klingon; + klingon.MoveTo(newSector); + } + + return KlingonsFireOnEnterprise(); + } + internal CommandResult KlingonsFireOnEnterprise() { if (EnterpriseIsNextToStarbase && Klingons.Any()) diff --git a/84 Super Star Trek/csharp/Space/QuadrantInfo.cs b/84 Super Star Trek/csharp/Space/QuadrantInfo.cs index 8b4357db..70447250 100644 --- a/84 Super Star Trek/csharp/Space/QuadrantInfo.cs +++ b/84 Super Star Trek/csharp/Space/QuadrantInfo.cs @@ -41,11 +41,7 @@ namespace SuperStarTrek.Space internal void AddStarbase() => HasStarbase = true; - internal Quadrant BuildQuadrant(Enterprise enterprise, Random random, Galaxy galaxy, Input input, Output output) - { - _isKnown = true; - return new(this, enterprise, random, galaxy, input, output); - } + internal void MarkAsKnown() => _isKnown = true; internal string Scan() { diff --git a/84 Super Star Trek/csharp/Systems/ComputerFunctions/DirectionDistanceCalculator.cs b/84 Super Star Trek/csharp/Systems/ComputerFunctions/DirectionDistanceCalculator.cs index c8b195f4..ff6239ed 100644 --- a/84 Super Star Trek/csharp/Systems/ComputerFunctions/DirectionDistanceCalculator.cs +++ b/84 Super Star Trek/csharp/Systems/ComputerFunctions/DirectionDistanceCalculator.cs @@ -21,7 +21,8 @@ namespace SuperStarTrek.Systems.ComputerFunctions internal override void Execute(Quadrant quadrant) { Output.WriteLine("Direction/distance calculator:") - .WriteLine($"You are at quadrant {_enterprise.Quadrant} sector {_enterprise.Sector}") + .Write($"You are at quadrant {_enterprise.QuadrantCoordinates}") + .WriteLine($" sector {_enterprise.SectorCoordinates}") .WriteLine("Please enter"); WriteDirectionAndDistance( diff --git a/84 Super Star Trek/csharp/Systems/ComputerFunctions/StarbaseDataCalculator.cs b/84 Super Star Trek/csharp/Systems/ComputerFunctions/StarbaseDataCalculator.cs index b81a353d..0d2c5b50 100644 --- a/84 Super Star Trek/csharp/Systems/ComputerFunctions/StarbaseDataCalculator.cs +++ b/84 Super Star Trek/csharp/Systems/ComputerFunctions/StarbaseDataCalculator.cs @@ -24,7 +24,7 @@ namespace SuperStarTrek.Systems.ComputerFunctions Output.WriteLine("From Enterprise to Starbase:"); - WriteDirectionAndDistance(_enterprise.Sector, quadrant.Starbase.Sector); + WriteDirectionAndDistance(_enterprise.SectorCoordinates, quadrant.Starbase.Sector); } } } \ No newline at end of file diff --git a/84 Super Star Trek/csharp/Systems/ComputerFunctions/TorpedoDataCalculator.cs b/84 Super Star Trek/csharp/Systems/ComputerFunctions/TorpedoDataCalculator.cs index 6afa7b8c..09c71859 100644 --- a/84 Super Star Trek/csharp/Systems/ComputerFunctions/TorpedoDataCalculator.cs +++ b/84 Super Star Trek/csharp/Systems/ComputerFunctions/TorpedoDataCalculator.cs @@ -26,7 +26,7 @@ namespace SuperStarTrek.Systems.ComputerFunctions foreach (var klingon in quadrant.Klingons) { - WriteDirectionAndDistance(_enterprise.Sector, klingon.Sector); + WriteDirectionAndDistance(_enterprise.SectorCoordinates, klingon.Sector); } } } diff --git a/84 Super Star Trek/csharp/Systems/PhaserControl.cs b/84 Super Star Trek/csharp/Systems/PhaserControl.cs index 48da4ace..5aa7cf8b 100644 --- a/84 Super Star Trek/csharp/Systems/PhaserControl.cs +++ b/84 Super Star Trek/csharp/Systems/PhaserControl.cs @@ -75,7 +75,7 @@ namespace SuperStarTrek.Systems private void ResolveHitOn(Klingon klingon, float perEnemyStrength, Quadrant quadrant) { - var distance = _enterprise.Sector.GetDistanceTo(klingon.Sector); + var distance = _enterprise.SectorCoordinates.GetDistanceTo(klingon.Sector); var hitStrength = (int)(perEnemyStrength / distance * (2 + _random.GetFloat())); if (klingon.TakeHit(hitStrength)) diff --git a/84 Super Star Trek/csharp/Systems/PhotonTubes.cs b/84 Super Star Trek/csharp/Systems/PhotonTubes.cs index 034199c9..024cf7ea 100644 --- a/84 Super Star Trek/csharp/Systems/PhotonTubes.cs +++ b/84 Super Star Trek/csharp/Systems/PhotonTubes.cs @@ -34,15 +34,14 @@ namespace SuperStarTrek.Systems protected override CommandResult ExecuteCommandCore(Quadrant quadrant) { - if (!_input.TryGetNumber("Photon torpedo course", 1, 9, out var direction)) + if (!_input.TryGetCourse("Photon torpedo course", "Ensign Chekov", out var course)) { - _output.WriteLine("Ensign Chekov reports, 'Incorrect course data, sir!'"); return CommandResult.Ok; } var isHit = false; _output.WriteLine("Torpedo track:"); - foreach (var sector in new Course(direction).GetSectorsFrom(_enterprise.Sector)) + foreach (var sector in course.GetSectorsFrom(_enterprise.SectorCoordinates)) { _output.WriteLine($" {sector}"); diff --git a/84 Super Star Trek/csharp/Systems/ShortRangeSensors.cs b/84 Super Star Trek/csharp/Systems/ShortRangeSensors.cs index e01c829e..e25cf966 100644 --- a/84 Super Star Trek/csharp/Systems/ShortRangeSensors.cs +++ b/84 Super Star Trek/csharp/Systems/ShortRangeSensors.cs @@ -51,8 +51,8 @@ namespace SuperStarTrek.Systems { yield return $"Stardate {_game.Stardate}"; yield return $"Condition {_enterprise.Condition}"; - yield return $"Quadrant {_enterprise.Quadrant}"; - yield return $"Sector {_enterprise.Sector}"; + yield return $"Quadrant {_enterprise.QuadrantCoordinates}"; + yield return $"Sector {_enterprise.SectorCoordinates}"; yield return $"Photon torpedoes {_enterprise.TorpedoCount}"; yield return $"Total energy {Math.Ceiling(_enterprise.TotalEnergy)}"; yield return $"Shields {(int)_enterprise.ShieldControl.ShieldEnergy}"; diff --git a/84 Super Star Trek/csharp/Systems/Subsystem.cs b/84 Super Star Trek/csharp/Systems/Subsystem.cs index ab7bef4c..9e5f3570 100644 --- a/84 Super Star Trek/csharp/Systems/Subsystem.cs +++ b/84 Super Star Trek/csharp/Systems/Subsystem.cs @@ -41,13 +41,26 @@ namespace SuperStarTrek.Systems public virtual void Repair() { - if (IsDamaged) { Condition = 0; } + if (IsDamaged) + { + Condition = 0; + } } - internal void TakeDamage(float damage) + public virtual bool Repair(float repairWorkDone) { - Condition -= damage; - _output.WriteLine($"Damage Control reports, '{Name} damaged by the hit.'"); + if (IsDamaged) + { + Condition += repairWorkDone; + if (Condition > -0.1f && Condition < 0) + { + Condition = -0.1f; + } + } + + return !IsDamaged; } + + internal void TakeDamage(float damage) => Condition -= damage; } } diff --git a/84 Super Star Trek/csharp/Systems/WarpEngines.cs b/84 Super Star Trek/csharp/Systems/WarpEngines.cs new file mode 100644 index 00000000..8e24b750 --- /dev/null +++ b/84 Super Star Trek/csharp/Systems/WarpEngines.cs @@ -0,0 +1,75 @@ +using System; +using SuperStarTrek.Commands; +using SuperStarTrek.Objects; +using SuperStarTrek.Space; + +namespace SuperStarTrek.Systems +{ + internal class WarpEngines : Subsystem + { + private readonly Enterprise _enterprise; + private readonly Output _output; + private readonly Input _input; + + public WarpEngines(Enterprise enterprise, Output output, Input input) + : base("Warp Engines", Command.NAV, output) + { + _enterprise = enterprise; + _output = output; + _input = input; + } + + protected override CommandResult ExecuteCommandCore(Quadrant quadrant) + { + if (_input.TryGetCourse("Course", " Lt. Sulu", out var course) && + TryGetWarpFactor(out var warpFactor) && + TryGetDistanceToMove(warpFactor, out var distanceToMove)) + { + var result = quadrant.KlingonsMoveAndFire(); + if (result.IsGameOver) { return result; } + + _enterprise.RepairSystems(warpFactor); + _enterprise.VaryConditionOfRandomSystem(); + var timeElapsed = _enterprise.Move(course, warpFactor, distanceToMove); + + return CommandResult.Elapsed(timeElapsed); + } + + return CommandResult.Ok; + } + + private bool TryGetWarpFactor(out float warpFactor) + { + var maximumWarp = IsDamaged ? 0.2f : 8; + if (_input.TryGetNumber("Warp Factor", 0, maximumWarp, out warpFactor)) + { + return warpFactor > 0; + } + + _output.WriteLine( + IsDamaged && warpFactor > maximumWarp + ? "Warp engines are damaged. Maximum speed = warp 0.2" + : $" Chief Engineer Scott reports, 'The engines won't take warp {warpFactor} !'"); + + return false; + } + + private bool TryGetDistanceToMove(float warpFactor, out int distanceToTravel) + { + distanceToTravel = (int)Math.Round(warpFactor * 8, MidpointRounding.AwayFromZero); + if (distanceToTravel <= _enterprise.Energy) { return true; } + + _output.WriteLine("Engineering reports, 'Insufficient energy available") + .WriteLine($" for maneuvering at warp {warpFactor} !'"); + + if (distanceToTravel <= _enterprise.TotalEnergy && !_enterprise.ShieldControl.IsDamaged) + { + _output.Write($"Deflector control room acknowledges {_enterprise.ShieldControl.ShieldEnergy} ") + .WriteLine("units of energy") + .WriteLine(" presently deployed to shields."); + } + + return false; + } + } +} From 3777f835c145c135eba607b665ee6487300880e6 Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Sun, 21 Mar 2021 12:46:32 +1100 Subject: [PATCH 11/15] Fix phaser energy use --- 84 Super Star Trek/csharp/Objects/Enterprise.cs | 5 +++++ 84 Super Star Trek/csharp/Systems/PhaserControl.cs | 2 ++ 2 files changed, 7 insertions(+) diff --git a/84 Super Star Trek/csharp/Objects/Enterprise.cs b/84 Super Star Trek/csharp/Objects/Enterprise.cs index 004ce893..bb177369 100644 --- a/84 Super Star Trek/csharp/Objects/Enterprise.cs +++ b/84 Super Star Trek/csharp/Objects/Enterprise.cs @@ -87,6 +87,11 @@ namespace SuperStarTrek.Objects public override string ToString() => "<*>"; + internal void UseEnergy(float amountUsed) + { + TotalEnergy -= amountUsed; + } + internal CommandResult TakeHit(Coordinates sector, int hitStrength) { _output.WriteLine($"{hitStrength} unit hit on Enterprise from sector {sector}"); diff --git a/84 Super Star Trek/csharp/Systems/PhaserControl.cs b/84 Super Star Trek/csharp/Systems/PhaserControl.cs index 5aa7cf8b..18566294 100644 --- a/84 Super Star Trek/csharp/Systems/PhaserControl.cs +++ b/84 Super Star Trek/csharp/Systems/PhaserControl.cs @@ -42,6 +42,8 @@ namespace SuperStarTrek.Systems var phaserStrength = GetPhaserStrength(); if (phaserStrength < 0) { return CommandResult.Ok; } + _enterprise.UseEnergy(phaserStrength); + var perEnemyStrength = GetPerTargetPhaserStrength(phaserStrength, quadrant.KlingonCount); foreach (var klingon in quadrant.Klingons.ToList()) From 95ec6a2c024200453776594a4d9d68d8d830c0af Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Sun, 21 Mar 2021 12:54:14 +1100 Subject: [PATCH 12/15] Fix movement within quadrant --- 84 Super Star Trek/csharp/Objects/Enterprise.cs | 1 + 84 Super Star Trek/csharp/Space/Quadrant.cs | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/84 Super Star Trek/csharp/Objects/Enterprise.cs b/84 Super Star Trek/csharp/Objects/Enterprise.cs index bb177369..feb51646 100644 --- a/84 Super Star Trek/csharp/Objects/Enterprise.cs +++ b/84 Super Star Trek/csharp/Objects/Enterprise.cs @@ -174,6 +174,7 @@ namespace SuperStarTrek.Objects { _quadrant = new Quadrant(_quadrant.Galaxy[quadrant], this, _random, _quadrant.Galaxy, _input, _output); } + _quadrant.SetEnterpriseSector(sector); SectorCoordinates = sector; return GetTimeElapsed(quadrant, warpFactor); diff --git a/84 Super Star Trek/csharp/Space/Quadrant.cs b/84 Super Star Trek/csharp/Space/Quadrant.cs index 50c577e2..b333cb7e 100644 --- a/84 Super Star Trek/csharp/Space/Quadrant.cs +++ b/84 Super Star Trek/csharp/Space/Quadrant.cs @@ -176,5 +176,11 @@ namespace SuperStarTrek.Space .Select(y => new Coordinates(x, y)) .Select(c => _sectors.GetValueOrDefault(c)) .Select(o => o?.ToString() ?? " ")); + + internal void SetEnterpriseSector(Coordinates sector) + { + _sectors.Remove(_enterprise.SectorCoordinates); + _sectors[sector] = _enterprise; + } } } From 5e6aae3c195b2dade1f59936bc58595eea9e05ab Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Sun, 21 Mar 2021 13:00:54 +1100 Subject: [PATCH 13/15] Fix torpedo count --- 84 Super Star Trek/csharp/Objects/Enterprise.cs | 2 +- 84 Super Star Trek/csharp/Systems/PhotonTubes.cs | 2 ++ 84 Super Star Trek/csharp/Systems/ShortRangeSensors.cs | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/84 Super Star Trek/csharp/Objects/Enterprise.cs b/84 Super Star Trek/csharp/Objects/Enterprise.cs index feb51646..1608b94b 100644 --- a/84 Super Star Trek/csharp/Objects/Enterprise.cs +++ b/84 Super Star Trek/csharp/Objects/Enterprise.cs @@ -42,7 +42,7 @@ namespace SuperStarTrek.Objects public float TotalEnergy { get; private set; } public int DamagedSystemCount => _systems.Count(s => s.IsDamaged); public IEnumerable Systems => _systems; - public int TorpedoCount { get; } + public PhotonTubes PhotonTubes => (PhotonTubes)_commandExecutors[Command.TOR]; public bool IsDocked => _quadrant.EnterpriseIsNextToStarbase; public bool IsStranded => TotalEnergy < 10 || Energy < 10 && ShieldControl.IsDamaged; diff --git a/84 Super Star Trek/csharp/Systems/PhotonTubes.cs b/84 Super Star Trek/csharp/Systems/PhotonTubes.cs index 024cf7ea..656c65be 100644 --- a/84 Super Star Trek/csharp/Systems/PhotonTubes.cs +++ b/84 Super Star Trek/csharp/Systems/PhotonTubes.cs @@ -39,6 +39,8 @@ namespace SuperStarTrek.Systems return CommandResult.Ok; } + TorpedoCount -= 1; + var isHit = false; _output.WriteLine("Torpedo track:"); foreach (var sector in course.GetSectorsFrom(_enterprise.SectorCoordinates)) diff --git a/84 Super Star Trek/csharp/Systems/ShortRangeSensors.cs b/84 Super Star Trek/csharp/Systems/ShortRangeSensors.cs index e25cf966..ad3929d1 100644 --- a/84 Super Star Trek/csharp/Systems/ShortRangeSensors.cs +++ b/84 Super Star Trek/csharp/Systems/ShortRangeSensors.cs @@ -53,7 +53,7 @@ namespace SuperStarTrek.Systems yield return $"Condition {_enterprise.Condition}"; yield return $"Quadrant {_enterprise.QuadrantCoordinates}"; yield return $"Sector {_enterprise.SectorCoordinates}"; - yield return $"Photon torpedoes {_enterprise.TorpedoCount}"; + yield return $"Photon torpedoes {_enterprise.PhotonTubes.TorpedoCount}"; yield return $"Total energy {Math.Ceiling(_enterprise.TotalEnergy)}"; yield return $"Shields {(int)_enterprise.ShieldControl.ShieldEnergy}"; yield return $"Klingons remaining {_galaxy.KlingonCount}"; From e3f53762481ce3720ceb92d75c35ac73ef8c8b4c Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Sun, 21 Mar 2021 13:12:44 +1100 Subject: [PATCH 14/15] Refuel Enterprise at starbase --- 84 Super Star Trek/csharp/Objects/Enterprise.cs | 2 ++ 84 Super Star Trek/csharp/Systems/PhotonTubes.cs | 2 ++ 84 Super Star Trek/csharp/Systems/ShieldControl.cs | 2 ++ 84 Super Star Trek/csharp/Systems/WarpEngines.cs | 7 +++++++ 4 files changed, 13 insertions(+) diff --git a/84 Super Star Trek/csharp/Objects/Enterprise.cs b/84 Super Star Trek/csharp/Objects/Enterprise.cs index 1608b94b..e48c5f76 100644 --- a/84 Super Star Trek/csharp/Objects/Enterprise.cs +++ b/84 Super Star Trek/csharp/Objects/Enterprise.cs @@ -75,6 +75,8 @@ namespace SuperStarTrek.Objects return _commandExecutors[command].ExecuteCommand(_quadrant); } + public void Refuel() => TotalEnergy = _maxEnergy; + internal bool Recognises(string command) { throw new NotImplementedException(); diff --git a/84 Super Star Trek/csharp/Systems/PhotonTubes.cs b/84 Super Star Trek/csharp/Systems/PhotonTubes.cs index 656c65be..a807d16c 100644 --- a/84 Super Star Trek/csharp/Systems/PhotonTubes.cs +++ b/84 Super Star Trek/csharp/Systems/PhotonTubes.cs @@ -60,5 +60,7 @@ namespace SuperStarTrek.Systems return quadrant.KlingonsFireOnEnterprise(); } + + internal void ReplenishTorpedoes() => TorpedoCount = _tubeCount; } } diff --git a/84 Super Star Trek/csharp/Systems/ShieldControl.cs b/84 Super Star Trek/csharp/Systems/ShieldControl.cs index 6ceefcf4..5af343f1 100644 --- a/84 Super Star Trek/csharp/Systems/ShieldControl.cs +++ b/84 Super Star Trek/csharp/Systems/ShieldControl.cs @@ -51,5 +51,7 @@ namespace SuperStarTrek.Systems } internal void AbsorbHit(int hitStrength) => ShieldEnergy -= hitStrength; + + internal void DropShields() => ShieldEnergy = 0; } } diff --git a/84 Super Star Trek/csharp/Systems/WarpEngines.cs b/84 Super Star Trek/csharp/Systems/WarpEngines.cs index 8e24b750..0dcf396c 100644 --- a/84 Super Star Trek/csharp/Systems/WarpEngines.cs +++ b/84 Super Star Trek/csharp/Systems/WarpEngines.cs @@ -32,6 +32,13 @@ namespace SuperStarTrek.Systems _enterprise.VaryConditionOfRandomSystem(); var timeElapsed = _enterprise.Move(course, warpFactor, distanceToMove); + if (_enterprise.IsDocked) + { + _enterprise.ShieldControl.DropShields(); + _enterprise.Refuel(); + _enterprise.PhotonTubes.ReplenishTorpedoes(); + } + return CommandResult.Elapsed(timeElapsed); } From 5418068462e91092ac60a0a58c0bdf522da001be Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Sun, 21 Mar 2021 13:55:55 +1100 Subject: [PATCH 15/15] Fix energy usage by warp engines. --- 84 Super Star Trek/csharp/Objects/Enterprise.cs | 7 +++++++ 84 Super Star Trek/csharp/Systems/ShieldControl.cs | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/84 Super Star Trek/csharp/Objects/Enterprise.cs b/84 Super Star Trek/csharp/Objects/Enterprise.cs index e48c5f76..4adf81df 100644 --- a/84 Super Star Trek/csharp/Objects/Enterprise.cs +++ b/84 Super Star Trek/csharp/Objects/Enterprise.cs @@ -179,6 +179,13 @@ namespace SuperStarTrek.Objects _quadrant.SetEnterpriseSector(sector); SectorCoordinates = sector; + TotalEnergy -= distance + 10; + if (Energy < 0) + { + _output.WriteLine("Shield Control supplies energy to complete the maneuver."); + ShieldControl.ShieldEnergy = Math.Max(0, TotalEnergy); + } + return GetTimeElapsed(quadrant, warpFactor); } diff --git a/84 Super Star Trek/csharp/Systems/ShieldControl.cs b/84 Super Star Trek/csharp/Systems/ShieldControl.cs index 5af343f1..a7518359 100644 --- a/84 Super Star Trek/csharp/Systems/ShieldControl.cs +++ b/84 Super Star Trek/csharp/Systems/ShieldControl.cs @@ -18,7 +18,7 @@ namespace SuperStarTrek.Systems _input = input; } - public float ShieldEnergy { get; private set; } + public float ShieldEnergy { get; set; } protected override bool CanExecuteCommand() => IsOperational("{name} inoperable");